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

QuickInput : Add an example of prompt with history #89

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
3 changes: 3 additions & 0 deletions quickinput-sample/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,17 @@ import { window, commands, ExtensionContext } from 'vscode';
import { showQuickPick, showInputBox } from './basicInput';
import { multiStepInput } from './multiStepInput';
import { quickOpen } from './quickOpen';
import { getPromptCommand } from './promptCommandWithHistory';

export function activate(context: ExtensionContext) {
context.subscriptions.push(commands.registerCommand('samples.quickInput', async () => {
const promptCommand = getPromptCommand(context.globalState);
const options: { [key: string]: (context: ExtensionContext) => Promise<void> } = {
showQuickPick,
showInputBox,
multiStepInput,
quickOpen,
promptCommand
};
const quickPick = window.createQuickPick();
quickPick.items = Object.keys(options).map(label => ({ label }));
Expand Down
104 changes: 104 additions & 0 deletions quickinput-sample/src/promptCommandWithHistory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { window, Disposable, Memento } from 'vscode';
import { QuickPickItem } from 'vscode';

export const historyPath = `${process.env.HOME}/.vscode-cmd-history`;
AdrieanKhisbe marked this conversation as resolved.
Show resolved Hide resolved

const HISTORY_KEY = 'HISTORY_KEY';

/**
* A command prompt with history
*
*/
export const getPromptCommand = (memo: Memento) => {
const pickCommand = getPickCommand(memo);
// §TODO: cache promptCommand!
return async function promptCommand() {
const command = await pickCommand();
if (command) {
window.showInformationMessage(`You picked the following command: '${command}'`)
AdrieanKhisbe marked this conversation as resolved.
Show resolved Hide resolved
}
}
}

abstract class CommandItem implements QuickPickItem {
public label: string;
public description?: string;
public abstract type: string;
AdrieanKhisbe marked this conversation as resolved.
Show resolved Hide resolved
constructor(label: string, description?: string) {
this.label = label;
this.description = description;
}
}
class HistoryItem extends CommandItem {
public type: string;
constructor(label: string, description?: string) {
super(label, description);
this.type = 'history'
}
}
class InputItem extends CommandItem {
public type: string;
constructor(public label: string) {
super(label, '(current input)');
this.type = 'input';
};
}

const getPickCommand = (memo: Memento) => async function pickCommand() {
const disposables: Disposable[] = [];
try {
return await new Promise<string | undefined>((resolve, reject) => {
const input = window.createQuickPick<CommandItem>();
input.placeholder = 'Type a command';
input.items = [];

const updateQuickPick = (value?: string): void => {
if (value === input.value) return;
if (!value) {
AdrieanKhisbe marked this conversation as resolved.
Show resolved Hide resolved
if (input.items[0] && input.items[0].type === 'input')
input.items = input.items.slice(1);
return;
}
if (input.items[0] && input.items[0].type === 'input') {
AdrieanKhisbe marked this conversation as resolved.
Show resolved Hide resolved
input.items = [new InputItem(value)].concat(input.items.slice(1));
} else {
input.items = [new InputItem(value)].concat(input.items);
}
// §todo: add autocomplete suggestions
}

disposables.push(
input.onDidChangeValue(updateQuickPick),
input.onDidChangeSelection((items: CommandItem[]) => {
const item = items[0];
if (item instanceof HistoryItem) {
resolve(item.label);
input.hide();
// do not record new input in history
// §todo : maybe reorder
} else if (item instanceof InputItem) {
resolve(item.label);
input.hide();
// record new input in history
if (!item.label.startsWith(' ')) {
chrmarti marked this conversation as resolved.
Show resolved Hide resolved
const currentHistory: string[] = memo.get(HISTORY_KEY, []);
currentHistory.unshift(item.label);
memo.update(HISTORY_KEY, currentHistory);
}
}
}),
input.onDidHide(() => {
resolve(undefined);
input.dispose();
})
);
input.show();
const historyItems: HistoryItem[] = memo.get(HISTORY_KEY, []).map(
(cmd: string, index: number) => new HistoryItem(cmd, `(history item ${index})`)
);
input.items = input.items.concat(historyItems)
});
} finally {
disposables.forEach(d => d.dispose());
}
}