Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate to only custom formats #89

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .vscodeignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
**/*.zip
node_modules/**
out/**
out/test/**
package-lock.json
res/*.svg
src/**
Expand Down
21 changes: 11 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,20 +51,21 @@ You can set different configuration options to control the format of GUIDs that
* insertGuid.showUppercase: Show uppercase GUIDs (with and without braces) when presenting possible GUID formats to insert. The default is `false`.
* insertGuid.showCodeSnippets: Show code snippets for C++ when presenting possible GUID formats to insert. The default is `true`.
* insertGuid.pasteAutomatically: When not empty, paste the GUID in a specified format without showing selection menu. The default is "". The formatting options are:
* `{b}|{B}` inserts a braced string in lowercase `{b}` or uppercase `{B}` e.g., `{880c86bc-384c-4cce-9e9a-4f760ca755c4}`
* `{d}|{D}` inserts a hyphenated string in lowercase `{d}` or uppercase `{D}` e.g., `880c86bc-384c-4cce-9e9a-4f760ca755c4`
* `{n}|{N}` inserts an unformatted string in lowercase `{n}` or uppercase `{N}` e.g., `880c86bc384c4cce9e9a4f760ca755c4`
* `{x}|{X}` inserts a struct-formatted string in lowercase `{x}` or uppercase `{X}` e.g., `{0x880c86bc,0x384c,0x4cce,{0x9e,0x9a,0x4f,0x76,0x0c,0xa7,0x55,0xc4}}`
* `{x0}|{X0}` inserts the first four bytes as a hexadecimal string in lowercase `{x0}` or uppercase `{X0}` e.g., `0x880c86bc`
* `{x1}|{X1}` and `{x2}|{X2}` insert the second and third two bytes as a hexadecimal string in lowercase `{x1}` and `{x2}`, or uppercase `{X1}` and `{X2}` e.g., `0x384c` and `0x4cce`
* `{x3}|{X3}` through `{x10}|{X10}` insert the subsequent bytes individually as a hexadecimal string in lowercase `{x3}` or uppercase `{X3}` e.g., `0x9e` through `0xc4`.
* `{nl}` inserts a new line
* All other characters will be interpreted literally e.g., `new GUID("{D}")` inserts `new GUID("880C86BC-384C-4CCE-9E9A-4F760CA755C4")`
* `{b}` or `{B}` inserts a braced string in lowercase `{b}` or uppercase `{B}` e.g., `{880c86bc-384c-4cce-9e9a-4f760ca755c4}`
* `{d}` or `{D}` inserts a hyphenated string in lowercase `{d}` or uppercase `{D}` e.g., `880c86bc-384c-4cce-9e9a-4f760ca755c4`
* `{n}` or `{N}` inserts an unformatted string in lowercase `{n}` or uppercase `{N}` e.g., `880c86bc384c4cce9e9a4f760ca755c4`
* `{x}` or `{X}` inserts a struct-formatted string in lowercase `{x}` or uppercase `{X}` e.g., `{0x880c86bc,0x384c,0x4cce,{0x9e,0x9a,0x4f,0x76,0x0c,0xa7,0x55,0xc4}}`
* `{x0}` or `{X0}` inserts the first four bytes as a hexadecimal string in lowercase `{x0}` or uppercase `{X0}` e.g., `0x880c86bc`
* `{x1}` or `{X1}`, and `{x2}` or `{X2}` insert the second and third two bytes as a hexadecimal string in lowercase `{x1}` and `{x2}`, or uppercase `{X1}` and `{X2}` e.g., `0x384c` and `0x4cce`
* `{x3}` or `{X3}` through `{x10}` or `{X10}` insert the subsequent bytes individually as a hexadecimal string in lowercase `{x3}` or uppercase `{X3}` e.g., `0x9e` through `0xc4`.
* `\n` or `{nl}` inserts a new line

All other characters will be interpreted literally e.g., `new GUID("{D}")` inserts `new GUID("880C86BC-384C-4CCE-9E9A-4F760CA755C4")`

For example, to generate a `GUID` for the [windows](https://crates.io/crates/windows) crate, you could define:

```json
"const G: ::windows::core::GUID = ::windows::core::GUID {{nl} data1: 0x{x0},{nl} data2: 0x{x1},{nl} data3: 0x{x2},{nl} data4: [0x{x3}, 0x{x4}, 0x{x5}, 0x{x6}, 0x{x7}, 0x{x8}, 0x{x9}, 0x{x10}],{nl}};"
"const G: ::windows::core::GUID = ::windows::core::GUID {\n data1: 0x{x0},\n data2: 0x{x1},\n data3: 0x{x2},\n data4: [0x{x3}, 0x{x4}, 0x{x5}, 0x{x6}, 0x{x7}, 0x{x8}, 0x{x9}, 0x{x10}],\n};"
```

Which would insert a `GUID` like:
Expand Down
35 changes: 24 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,25 +29,43 @@
"configuration": {
"title": "Insert GUID",
"properties": {
"insertGuid.formats": {
"type": "array",
"items": {
"type": "string"
},
"minItems": 1,
"uniqueItems": true,
"default": null,
"order": 0,
"markdownDescription": "An array of string formats to display in a quick pick menu. Each line contains format specifiers from the list below:\n* `{b}` or `{B}` inserts a braced string in lowercase `{b}` or uppercase `{B}` e.g., `{880c86bc-384c-4cce-9e9a-4f760ca755c4}`\n* `{d}` or `{D}` inserts a hyphenated string in lowercase `{d}` or uppercase `{D}` e.g., `880c86bc-384c-4cce-9e9a-4f760ca755c4`\n* `{n}` or `{N}` inserts an unformatted string in lowercase `{n}` or uppercase `{N}` e.g., `880c86bc384c4cce9e9a4f760ca755c4`\n* `{x}` or `{X}` inserts a struct-formatted string in lowercase `{x}` or uppercase `{X}` e.g., `{0x880c86bc,0x384c,0x4cce,{0x9e,0x9a,0x4f,0x76,0x0c,0xa7,0x55\nxc4}}`\n* `{x0}` or `{X0}` inserts the first four bytes as a hexadecimal string in lowercase `{x0}` or uppercase `{X0}` e.g., `0x880c86bc`\n* `{x1}` or `{X1}`, and `{x2}` or `{X2}` insert the second and third two bytes as a hexadecimal string in lowercase `{x1}` and `{x2}`, or uppercase `{X1}` nd \n{X2}` e.g., `0x384c` and `0x4cce`\n* `{x3}` or `{X3}` through `{x10}` or `{X10}` insert the subsequent bytes individually as a hexadecimal string in lowercase `{x3}` or uppercase `{X3}` e.g.,\n0x9e` through `0xc4`.\n* `\\n` or `{nl}` inserts a new line\n\nAll other characters will be interpreted literally e.g., `new GUID(\"{D}\")` inserts `new GUID(\"880C86BC-384C-4CCE-9E9A-4F760CA755C4\")`"
},
"insertGuid.showLowercase": {
"type": "boolean",
"default": true,
"description": "Show lowercase GUIDs (with and without braces) when presenting possible GUID formats to insert."
"order": 1,
"description": "Show lowercase GUIDs (with and without braces) when presenting possible GUID formats to insert.",
"deprecationMessage": "Add desired lowercase formats to `#insertGuid.formats#`. This setting will be removed in a future version."
},
"insertGuid.showUppercase": {
"type": "boolean",
"default": false,
"description": "Show uppercase GUIDs (with and without braces) when presenting possible GUID formats to insert."
"order": 2,
"description": "Show uppercase GUIDs (with and without braces) when presenting possible GUID formats to insert.",
"deprecationMessage": "Add desired uppercase formats to `#insertGuid.formats#`. This setting will be removed in a future version."
},
"insertGuid.showCodeSnippets": {
"type": "boolean",
"default": true,
"description": "Show code snippets for C++ when presenting possible GUID formats to insert."
"order": 3,
"description": "Show code snippets for C++ when presenting possible GUID formats to insert.",
"deprecationMessage": "Add desired snippet formats to `#insertGuid.formats#`. This setting will be removed in a future version."
},
"insertGuid.pasteAutomatically": {
"type": "string",
"default": "",
"markdownDescription": "Paste GUID without prompting using the specified format:\n* `{b}|{B}` inserts a braced string in lowercase `{b}` or uppercase `{B}` e.g., `{880c86bc-384c-4cce-9e9a-4f760ca755c4}`\n* `{d}|{D}` inserts a hyphenated string in lowercase `{d}` or uppercase `{D}` e.g., `880c86bc-384c-4cce-9e9a-4f760ca755c4`\n* `{n}|{N}` inserts an unformatted string in lowercase `{n}` or uppercase `{N}` e.g., `880c86bc384c4cce9e9a4f760ca755c4`\n* `{x}|{X}` inserts a struct-formatted string in lowercase `{x}` or uppercase `{X}` e.g., `{0x880c86bc,0x384c,0x4cce,{0x9e,0x9a,0x4f,0x76,0x0c,0xa7,0x55,0xc4}}`\n* `{x0}|{X0}` inserts the first four bytes as a hexadecimal string in lowercase `{x0}` or uppercase `{X0}` e.g., `0x880c86bc`\n* `{x1}|{X1}` and `{x2}|{X2}` insert the second and third two bytes as a hexadecimal string in lowercase `{x1}` and `{x2}`, or uppercase `{X1}` and `{X2}` e.g., `0x384c` and `0x4cce`\n* `{x3}|{X3}` through `{x10}|{X10}` insert the subsequent bytes individually as a hexadecimal string in lowercase `{x3}` or uppercase `{X3}` e.g., `0x9e` through `0xc4`.\n* `{nl}` inserts a new line\n* All other characters will be interpreted literally e.g., `new GUID(\"{D}\")` inserts `new GUID(\"880C86BC-384C-4CCE-9E9A-4F760CA755C4\")`"
"order": 4,
"markdownDescription": "Paste GUID without prompting using format specifiers described on `#insertGuid.formats#`."
}
}
},
Expand All @@ -66,11 +84,6 @@
}
]
},
"activationEvents": [
"onCommand:guid.insert",
"onCommand:guid.insertMany",
"onCommand:guid.insertEmpty"
],
"icon": "res/logo.png",
"galleryBanner": {
"color": "#252526",
Expand All @@ -93,13 +106,13 @@
"watch": "webpack --watch",
"watch-test": "tsc -p . -w",
"pretest": "npm run compile-test",
"test": "node ./out/test/runTest.js",
"test": "node ./out/src/test/runTest.js",
"package": "webpack --mode production --devtool hidden-source-map",
"preversion": "npm test",
"vscode:prepublish": "npm run package"
},
"engines": {
"vscode": "^1.30.0"
"vscode": "^1.75.0"
},
"dependencies": {
"buffer": "^6.0.3",
Expand Down
50 changes: 36 additions & 14 deletions src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import * as vscode from 'vscode';
import * as util from 'util';
import { Guid } from './guid';
import getSettings, { Settings } from './settings';

enum FormatType {
LOWERCASE,
Expand Down Expand Up @@ -50,10 +51,17 @@ class GuidPickItem implements vscode.QuickPickItem {
private _guid: Guid;
private readonly _format: GuidPickFormat;

constructor(index: number, guid: Guid, format: GuidPickFormat) {
constructor(index: number, guid: Guid, format: GuidPickFormat | string) {
this._index = index;
this._guid = guid;
this._format = format;
if (typeof format === 'string') {
this._format = {
format: (g) => g.format(format),
type: FormatType.CUSTOM,
};
} else {
this._format = format;
}
}

get label(): string {
Expand Down Expand Up @@ -192,16 +200,27 @@ export function insertEmptyCommand(textEditor: vscode.TextEditor, edit: vscode.T

async function insertCommandImpl(textEditor: vscode.TextEditor, edit: vscode.TextEditorEdit, type: GuidGenerateType): Promise<void> {
const g = type === GuidGenerateType.EMPTY ? Guid.EMPTY : new Guid();
const settings = vscode.workspace.getConfiguration('insertGuid');
const showLowercase = settings.get<boolean>('showLowercase', true);
const showUppercase = settings.get<boolean>('showUppercase', false);
const showCodeSnippets = settings.get<boolean>('showCodeSnippets', true);
const pasteAutomatically = settings.get<string>('pasteAutomatically', '');
const settings = getSettings();
const formats = settings.formats;
const pasteAutomatically = settings.pasteAutomatically;

let item: GuidPickItem;
if (formats !== null) {
const items: GuidPickItem[] = [];
let nextIndex = 0;

const items = getQuickPickItems(g, showLowercase, showUppercase, showCodeSnippets);
let item = items[0];
for (const format of formats) {
items.push(new GuidPickItem(++nextIndex, g, format));
}

if (pasteAutomatically !== '') {
const selection = await vscode.window.showQuickPick<GuidPickItem>(items)
if (selection == null) {
// Selection canceled.
return
}

item = selection
} else if (pasteAutomatically !== null) {
// Format with the specified string and insert without user selection
const customFormatter = {
format: (g: Guid) => g.format(pasteAutomatically),
Expand All @@ -210,6 +229,7 @@ async function insertCommandImpl(textEditor: vscode.TextEditor, edit: vscode.Tex
item = new GuidPickItem(-1, g, customFormatter)
} else {
// Let user select format
const items = getQuickPickItems(g, settings);
const selection = await vscode.window.showQuickPick<GuidPickItem>(items)
if (selection == null) {
// Selection canceled.
Expand Down Expand Up @@ -239,6 +259,8 @@ async function insertCommandImpl(textEditor: vscode.TextEditor, edit: vscode.Tex
});
}

export type QuickPickSettings = Pick<Settings, 'showLowercase' | 'showUppercase' | 'showCodeSnippets'>;

/**
* Gets an array of items to display in the Quick Pick window.
* @param guid The GUID to render in each Quick Pick item.
Expand All @@ -247,14 +269,14 @@ async function insertCommandImpl(textEditor: vscode.TextEditor, edit: vscode.Tex
* @param showCodeSnippets Indicates whether code snippet options should be included in the array.
* @returns An array of items to display in the Quick Pick window.
*/
export function getQuickPickItems(guid: Guid, showLowercase: boolean, showUppercase: boolean, showCodeSnippets: boolean): GuidPickItem[] {
export function getQuickPickItems(guid: Guid, settings: QuickPickSettings): GuidPickItem[] {
const items: GuidPickItem[] = [];
let nextIndex = 0;

for (const format of FORMATS) {
if (((showLowercase || (!showUppercase && !showCodeSnippets)) && format.type === FormatType.LOWERCASE) ||
(showUppercase && format.type === FormatType.UPPERCASE) ||
(showCodeSnippets && format.type === FormatType.SNIPPET)) {
if (((settings.showLowercase || (!settings.showUppercase && !settings.showCodeSnippets)) && format.type === FormatType.LOWERCASE) ||
(settings.showUppercase && format.type === FormatType.UPPERCASE) ||
(settings.showCodeSnippets && format.type === FormatType.SNIPPET)) {
const item = new GuidPickItem(++nextIndex, guid, format);
items.push(item);
}
Expand Down
2 changes: 1 addition & 1 deletion src/guid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ export class Guid {
const fn = replacements[replacement]
ret = ret.replace(replacement, fn(this));
}
return ret.replace(/\{nl\}/g, '\n');
return ret.replace(/\{nl\}|\\n/g, '\n');
}

/**
Expand Down
104 changes: 104 additions & 0 deletions src/settings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// The MIT License (MIT)
//
// Copyright (c) Heath Stewart
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import { WorkspaceConfiguration, workspace } from 'vscode';

export interface Settings {
showLowercase: boolean
showUppercase: boolean
showCodeSnippets: boolean
pasteAutomatically: string
formats: string[] | null
};

export const DEFAULTS: Settings = {
showLowercase: true,
showUppercase: false,
showCodeSnippets: true,
pasteAutomatically: '',
formats: null,
};

// Use placeholder token that completely selects with double click.
const NAME_PLACEHOLDER: string = '__NAME__';
const FORMATS: Array<{ format: string, type: 'LOWERCASE' | 'UPPERCASE' | 'SNIPPET' }> = [
{
format: '{d}',
type: 'LOWERCASE',
},
{
format: '{b}',
type: 'LOWERCASE',
},
{
format: `// {b}\nstatic const struct GUID ${NAME_PLACEHOLDER} = {x}\n`,
type: 'SNIPPET',
},
// TODO
];

class SettingsImpl implements Settings {
private readonly _settings: WorkspaceConfiguration;
constructor() {
this._settings = workspace.getConfiguration('insertGuid');
}

get showLowercase(): boolean {
return this._settings.get('showLowercase', DEFAULTS.showLowercase);
}

get showUppercase(): boolean {
return this._settings.get('showUppercase', DEFAULTS.showUppercase);
}

get showCodeSnippets(): boolean {
return this._settings.get('showCodeSnippets', DEFAULTS.showCodeSnippets);
}

get pasteAutomatically(): string {
return this._settings.get('pasteAutomatically', DEFAULTS.pasteAutomatically);
}

get formats(): string[] | null {
let formats = this._settings.get<string[]>('formats');
if (formats !== undefined && formats.length > 0) {
return formats;
}

formats = new Array<string>();
for (const format of FORMATS) {
if (format.type === 'LOWERCASE' && this.showLowercase) {
formats.push(format.format);
} else if (format.type === 'UPPERCASE' && this.showUppercase) {
formats.push(format.format);
} else if (format.type === 'SNIPPET' && this.showCodeSnippets) {
formats.push(format.format);
}
}

return formats;
}

// TODO: Write migration route during start up to populate `formats` using `WorkspaceConfiguration.update`.
};

export default (): Settings => new SettingsImpl();
Loading