diff --git a/src/conf/base/right-click.ts b/src/conf/base/right-click.ts index 56b9edd6..ffd40175 100644 --- a/src/conf/base/right-click.ts +++ b/src/conf/base/right-click.ts @@ -14,3 +14,58 @@ export type RightClickGroups = { treesitter: 1; default: 1000; }; + +interface RightClickMenuItemBase { + title: string; + keys?: string | string[]; +} + +interface RightClickMenuActionItem extends RightClickMenuItemBase { + actionId: string; + alwaysInMenu?: boolean; +} + +interface RightClickMenuSubMenuItem extends RightClickMenuItemBase { + children: RightClickMenuItem[]; +} + +interface RightClickMenuGroup { + items: RightClickMenuItem[]; +} + +type RightClickMenuItem = + | RightClickMenuActionItem + | RightClickMenuSubMenuItem + | RightClickMenuGroup; + +const CppToolkitGroup: RightClickMenuGroup = { + items: [ + { + title: "CppToolkit", + children: [ + { + title: "Insert header", + actionId: "cpptoolkit.insert-header", + keys: "i", + }, + { + title: "Generate function implementation", + actionId: "cpptoolkit.gen-def", + keys: "d", + }, + { + title: "Move value", + actionId: "cpptoolkit.move-value", + keys: "m", + }, + { + title: "Forward value", + actionId: "cpptoolkit.forward-value", + keys: "f", + }, + ], + }, + ], +}; + +export const RightClickMenu: RightClickMenuItem[] = [CppToolkitGroup]; diff --git a/src/core/model/action.ts b/src/core/model/action.ts index 49697965..4913dd26 100644 --- a/src/core/model/action.ts +++ b/src/core/model/action.ts @@ -4,8 +4,8 @@ import { LazyKeySpec } from "types/plugin/lazy"; export type ActionCondition = (buf: VimBuffer) => boolean; -interface ActionOptions { - id: string; +interface ActionOptions { + id: Id; title: string; callback: string | ((this: void) => void); description?: string; @@ -27,27 +27,30 @@ type RestKeys = Exclude< TupleToUnion >; -export class ActionBuilder { - private _opts: ActionOptions; +export class ActionBuilder< + Used extends (keyof ActionBuilder)[] = [], + Id extends string = "", +> { + private _opts: ActionOptions; constructor() { this._opts = { - id: "", + id: "" as any, title: "", callback: () => {}, }; } static start() { - return new ActionBuilder<[]>(); + return new ActionBuilder(); } - id( + id( this: "id" extends RestKeys ? ActionBuilder : never, - id: string + id: R ) { - this._opts.id = id; - return this as unknown as ActionBuilder>; + this._opts.id = id as any; + return this as unknown as ActionBuilder, R>; } title( @@ -55,7 +58,7 @@ export class ActionBuilder { title: string ) { this._opts.title = title; - return this as unknown as ActionBuilder>; + return this as unknown as ActionBuilder, Id>; } callback( @@ -63,7 +66,7 @@ export class ActionBuilder { callback: string | ((this: void) => void) ) { this._opts.callback = callback; - return this as unknown as ActionBuilder>; + return this as unknown as ActionBuilder, Id>; } description( @@ -71,7 +74,7 @@ export class ActionBuilder { description: string ) { this._opts.description = description; - return this as unknown as ActionBuilder>; + return this as unknown as ActionBuilder, Id>; } icon( @@ -79,7 +82,7 @@ export class ActionBuilder { icon: string ) { this._opts.icon = icon; - return this as unknown as ActionBuilder>; + return this as unknown as ActionBuilder, Id>; } condition( @@ -87,7 +90,7 @@ export class ActionBuilder { condition: ActionCondition ) { this._opts.condition = condition; - return this as unknown as ActionBuilder>; + return this as unknown as ActionBuilder, Id>; } category( @@ -95,7 +98,7 @@ export class ActionBuilder { category: string ) { this._opts.category = category; - return this as unknown as ActionBuilder>; + return this as unknown as ActionBuilder, Id>; } keys( @@ -103,7 +106,7 @@ export class ActionBuilder { keys: string | string[] ) { this._opts.keys = keys; - return this as unknown as ActionBuilder>; + return this as unknown as ActionBuilder, Id>; } from( @@ -111,25 +114,33 @@ export class ActionBuilder { from: string ) { this._opts.from = from; - return this as unknown as ActionBuilder>; + return this as unknown as ActionBuilder, Id>; } build( - this: keyof GetRequired extends TupleToUnion - ? ActionBuilder + this: keyof GetRequired> extends TupleToUnion + ? ActionBuilder : never - ): Action { + ): Action { return new Action(this._opts); } } -export class ActionGroupBuilder { +type ActionList = Ids extends [infer F, ...infer R] + ? F extends string + ? R extends string[] + ? [Action, ...ActionList] + : never + : never + : []; + +export class ActionGroupBuilder { private _sharedOptions: Pick< - ActionOptions, + ActionOptions, "category" | "from" | "condition" >; - private _actions: Action[] = []; + private _actions: Action[] = []; constructor() { this._sharedOptions = {}; @@ -150,7 +161,7 @@ export class ActionGroupBuilder { return this; } - private _update(action: Action) { + private _update(action: Action) { if (this._sharedOptions.category && !action.opts.category) { action.opts.category = this._sharedOptions.category; } @@ -162,26 +173,26 @@ export class ActionGroupBuilder { } } - public add(action: Action) { + public add(action: Action) { this._actions.push(action); - return this; + return this as unknown as ActionGroupBuilder>; } - public addOpts(opts: ActionOptions) { + public addOpts(opts: ActionOptions) { this._actions.push(new Action(opts)); - return this; + return this as unknown as ActionGroupBuilder>; } - public build(): Action[] { + public build() { return this._actions.map((action) => { this._update(action); return action; - }); + }) as ActionList; } } -export class Action { - constructor(public opts: ActionOptions) {} +export class Action { + constructor(public opts: ActionOptions) {} public get id() { return this.opts.id; @@ -238,11 +249,11 @@ export class Action { } export class ActionRegistry { - private _actions: Map = new Map(); + private _actions: Map> = new Map(); constructor() {} - public add(action: Action) { + public add(action: Action) { if (this._actions.has(action.id)) { throw new Error(`Action ${action.id} already exists`); } diff --git a/src/core/model/plugin.ts b/src/core/model/plugin.ts index 5db19aa7..70a56aaf 100644 --- a/src/core/model/plugin.ts +++ b/src/core/model/plugin.ts @@ -25,7 +25,7 @@ export type PluginOpts = { /** * All actions registered by this plugin. */ - providedActions?: Action[] | (() => Action[]); + providedActions?: Action[] | (() => Action[]); /** * Options for extending the plugin @@ -117,7 +117,7 @@ export class Plugin { }); } - get actions(): Action[] { + get actions(): Action[] { return this._cache.ensure("actions", () => { if (!this._opts.providedActions) { return [];