Skip to content

Commit

Permalink
Moves context into system
Browse files Browse the repository at this point in the history
Adds better command typings
  • Loading branch information
eamodio committed Apr 10, 2023
1 parent 23134ad commit 50d0d94
Show file tree
Hide file tree
Showing 9 changed files with 76 additions and 48 deletions.
5 changes: 3 additions & 2 deletions src/commands.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { TextDocument, TextDocumentShowOptions, TextEditor, Uri } from 'vscode';
import { Disposable, ViewColumn, window, workspace } from 'vscode';
import type { PaletteCommands } from './constants';
import type { Container } from './container';
import { showRelatedPicker } from './quickPicks/relatedPicker';
import { showRelatedPicker } from './pickers/relatedPicker';
import type { IRule } from './rule';
import { registerCommand } from './system/command';
import { configuration } from './system/configuration';
Expand All @@ -10,7 +11,7 @@ import { createCommandDecorator } from './system/decorators/command';
import { Logger } from './system/logger';
import { basename, dirname, normalizePath } from './system/path';

const registrableCommands: Command[] = [];
const registrableCommands: Command<keyof PaletteCommands>[] = [];
const command = createCommandDecorator(registrableCommands);

export class CommandProvider implements Disposable {
Expand Down
13 changes: 8 additions & 5 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
export const extensionPrefix = 'findrelated';
type StripPrefix<T extends string, S extends '.' | ':'> = T extends `${typeof extensionPrefix}${S}${infer U}`
? U
: never;
type StripPrefix<Key extends string, Prefix extends string> = Key extends `${Prefix}${infer Rest}` ? Rest : never;

export const enum CharCode {
/**
Expand All @@ -14,8 +12,13 @@ export const enum CharCode {
Backslash = 92,
}

export type Commands = `${typeof extensionPrefix}.key.${Keys}` | `${typeof extensionPrefix}.show`;
export type CommandsUnqualified = StripPrefix<Commands, '.'>;
export type PaletteCommands = {
'findrelated.show': [];
};

export type Commands = PaletteCommands & { [Key in `${typeof extensionPrefix}.key.${Keys}`]: [] };

export type UnqualifiedPaletteCommands = StripPrefix<keyof PaletteCommands, 'findrelated.'>;

export type ContextKeys = `${typeof extensionPrefix}:key:${Keys}`;

Expand Down
21 changes: 16 additions & 5 deletions src/container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,19 @@ export class Container {
private constructor(context: ExtensionContext) {
this._context = context;

context.subscriptions.unshift((this._rulesProvider = new RulesProvider(this)));
context.subscriptions.unshift((this._keyboard = new Keyboard()));
context.subscriptions.unshift((this._api = new FindRelatedApi(this)));
const disposables = [
(this._rulesProvider = new RulesProvider(this)),
(this._keyboard = new Keyboard()),
(this._api = new FindRelatedApi(this)),
new CommandProvider(this),
configuration.onDidChangeAny(this.onAnyConfigurationChanged, this),
];

context.subscriptions.unshift(new CommandProvider(this));
context.subscriptions.unshift(configuration.onDidChangeAny(this.onAnyConfigurationChanged, this));
context.subscriptions.push({
dispose: function () {
disposables.reverse().forEach(d => void d.dispose());
},
});
}

private _api: FindRelatedApi;
Expand Down Expand Up @@ -71,3 +78,7 @@ export class Container {
}
}
}

export function isContainer(container: any): container is Container {
return container instanceof Container;
}
38 changes: 23 additions & 15 deletions src/quickPicks/common.ts → src/pickers/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,26 @@ declare module 'vscode' {
}
}

export class CommandQuickPickItem<Arguments extends any[] = any[]> implements QuickPickItem {
static fromCommand<T>(label: string, command: Commands, args?: T): CommandQuickPickItem;
static fromCommand<T>(item: QuickPickItem, command: Commands, args?: T): CommandQuickPickItem;
static fromCommand<T>(labelOrItem: string | QuickPickItem, command: Commands, args?: T): CommandQuickPickItem {
export class CommandQuickPickItem<T extends keyof Commands = keyof Commands> implements QuickPickItem {
static fromCommand<T extends keyof Commands>(label: string, command: T, args: Commands[T]): CommandQuickPickItem<T>;
static fromCommand<T extends keyof Commands>(
item: QuickPickItem,
command: T,
args: Commands[T],
): CommandQuickPickItem<T>;
static fromCommand<T extends keyof Commands>(
labelOrItem: string | QuickPickItem,
command: T,
args: Commands[T],
): CommandQuickPickItem<T> {
return new CommandQuickPickItem(
typeof labelOrItem === 'string' ? { label: labelOrItem } : labelOrItem,
command,
args == null ? [] : [args],
args,
);
}

static is(item: QuickPickItem): item is CommandQuickPickItem {
static is<T extends keyof Commands>(item: QuickPickItem): item is CommandQuickPickItem<T> {
return item instanceof CommandQuickPickItem;
}

Expand All @@ -30,35 +38,35 @@ export class CommandQuickPickItem<Arguments extends any[] = any[]> implements Qu

constructor(
label: string,
command?: Commands,
args?: Arguments,
command?: T,
args?: Commands[T],
options?: {
onDidPressKey?: (key: Keys, result: Thenable<unknown>) => void;
suppressKeyPress?: boolean;
},
);
constructor(
item: QuickPickItem,
command?: Commands,
args?: Arguments,
command?: T,
args?: Commands[T],
options?: {
onDidPressKey?: (key: Keys, result: Thenable<unknown>) => void;
suppressKeyPress?: boolean;
},
);
constructor(
labelOrItem: string | QuickPickItem,
command?: Commands,
args?: Arguments,
command?: T,
args?: Commands[T],
options?: {
onDidPressKey?: (key: Keys, result: Thenable<unknown>) => void;
suppressKeyPress?: boolean;
},
);
constructor(
labelOrItem: string | QuickPickItem,
protected readonly command?: Commands,
protected readonly args?: Arguments,
protected readonly command: T,
protected readonly args: Commands[T],
protected readonly options?: {
// onDidExecute?: (
// options: { preserveFocus?: boolean; preview?: boolean } | undefined,
Expand All @@ -81,7 +89,7 @@ export class CommandQuickPickItem<Arguments extends any[] = any[]> implements Qu
execute(_options?: { preserveFocus?: boolean; preview?: boolean }): Promise<unknown | undefined> {
if (this.command === undefined) return Promise.resolve(undefined);

const result = executeCommand(this.command, ...(this.args ?? [])) as Promise<unknown | undefined>;
const result = executeCommand(this.command, ...this.args) as Promise<unknown | undefined>;
// this.options?.onDidExecute?.(options, result);
return result;
}
Expand Down
File renamed without changes.
13 changes: 7 additions & 6 deletions src/system/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,23 @@ import type { Command, Disposable } from 'vscode';
import { commands } from 'vscode';
import type { Commands, CoreCommands } from '../constants';

export function registerCommand(command: Commands, callback: (...args: any[]) => any, thisArg?: any): Disposable {
export function registerCommand<T extends keyof Commands>(
command: T,
callback: (...args: Commands[T]) => unknown,
thisArg?: any,
): Disposable {
return commands.registerCommand(command, callback, thisArg);
}

export function createCommand<T extends unknown[]>(command: Commands, title: string, ...args: T): Command {
export function createCommand<T extends keyof Commands>(command: T, title: string, ...args: Commands[T]): Command {
return {
command: command,
title: title,
arguments: args,
};
}

export function executeCommand<U = any>(command: Commands): Thenable<U>;
export function executeCommand<T = unknown, U = any>(command: Commands, arg: T): Thenable<U>;
export function executeCommand<T extends [...unknown[]] = [], U = any>(command: Commands, ...args: T): Thenable<U>;
export function executeCommand<T extends [...unknown[]] = [], U = any>(command: Commands, ...args: T): Thenable<U> {
export function executeCommand<T extends keyof Commands, U = any>(command: T, ...args: Commands[T]): Thenable<U> {
return commands.executeCommand<U>(command, ...args);
}

Expand Down
4 changes: 2 additions & 2 deletions src/context.ts → src/system/context.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { EventEmitter } from 'vscode';
import type { ContextKeys } from './constants';
import { executeCoreCommand } from './system/command';
import type { ContextKeys } from '../constants';
import { executeCoreCommand } from './command';

const contextStorage = new Map<string, unknown>();

Expand Down
28 changes: 16 additions & 12 deletions src/system/decorators/command.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import type { MessageItem } from 'vscode';
import { window } from 'vscode';
import type { Commands, CommandsUnqualified } from '../../constants';
import type { Commands, UnqualifiedPaletteCommands } from '../../constants';
import { extensionPrefix } from '../../constants';
import { Logger } from '../logger';
import { LogLevel } from '../logger.constants';

type CommandCallback = (this: any, ...args: any[]) => any;
type CommandCallback<T extends keyof Commands> = (this: any, ...args: Commands[T]) => any;

export function createCommandDecorator(
registry: Command[],
): (command: CommandsUnqualified, options?: CommandOptions) => CommandCallback {
return (command: CommandsUnqualified, options?: CommandOptions) => _command(registry, command, options);
export function createCommandDecorator<T extends UnqualifiedPaletteCommands>(
registry: Command<`${typeof extensionPrefix}.${T}`>[],
): (command: T, options?: CommandOptions) => (target: any, key: string, descriptor: PropertyDescriptor) => void {
return (command: T, options?: CommandOptions) => _command<T>(registry, command, options);
}

export interface CommandOptions {
Expand All @@ -19,16 +19,20 @@ export interface CommandOptions {
showErrorMessage?: string;
}

export interface Command {
name: Commands;
export interface Command<T extends keyof Commands> {
name: T;
key: string;
method: CommandCallback;
method: CommandCallback<T>;
options?: CommandOptions;
}

function _command(registry: Command[], command: CommandsUnqualified, options?: CommandOptions): CommandCallback {
return (_target: any, key: string, descriptor: any) => {
if (!(typeof descriptor.value === 'function')) throw new Error('not supported');
function _command<T extends UnqualifiedPaletteCommands>(
registry: Command<`${typeof extensionPrefix}.${T}`>[],
command: T,
options?: CommandOptions,
) {
return (_target: any, key: string, descriptor: PropertyDescriptor) => {
if (typeof descriptor.value !== 'function') throw new Error('not supported');

let method;
if (!options?.customErrorHandling) {
Expand Down
2 changes: 1 addition & 1 deletion src/system/keyboard.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Disposable } from 'vscode';
import type { Keys } from '../constants';
import { extensionPrefix, keys } from '../constants';
import { setContext } from '../context';
import { registerCommand } from './command';
import { setContext } from './context';
import { log } from './decorators/log';
import { Logger } from './logger';
import { getLogScope } from './logger.scope';
Expand Down

0 comments on commit 50d0d94

Please sign in to comment.