Skip to content

Commit

Permalink
...
Browse files Browse the repository at this point in the history
  • Loading branch information
TwIStOy committed Nov 21, 2023
1 parent 88ea0ae commit 080ab7b
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 37 deletions.
55 changes: 55 additions & 0 deletions src/conf/base/right-click.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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];
81 changes: 46 additions & 35 deletions src/core/model/action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { LazyKeySpec } from "types/plugin/lazy";

export type ActionCondition = (buf: VimBuffer) => boolean;

interface ActionOptions {
id: string;
interface ActionOptions<Id extends string> {
id: Id;
title: string;
callback: string | ((this: void) => void);
description?: string;
Expand All @@ -27,109 +27,120 @@ type RestKeys<Used extends (keyof ActionBuilder)[]> = Exclude<
TupleToUnion<Used>
>;

export class ActionBuilder<Used extends (keyof ActionBuilder)[] = []> {
private _opts: ActionOptions;
export class ActionBuilder<
Used extends (keyof ActionBuilder)[] = [],
Id extends string = "",
> {
private _opts: ActionOptions<Id>;

constructor() {
this._opts = {
id: "",
id: "" as any,
title: "",
callback: () => {},
};
}

static start() {
return new ActionBuilder<[]>();
return new ActionBuilder();
}

id(
id<R extends string>(
this: "id" extends RestKeys<Used> ? ActionBuilder<Used> : never,
id: string
id: R
) {
this._opts.id = id;
return this as unknown as ActionBuilder<Push<Used, "id">>;
this._opts.id = id as any;
return this as unknown as ActionBuilder<Push<Used, "id">, R>;
}

title(
this: "title" extends RestKeys<Used> ? ActionBuilder<Used> : never,
title: string
) {
this._opts.title = title;
return this as unknown as ActionBuilder<Push<Used, "title">>;
return this as unknown as ActionBuilder<Push<Used, "title">, Id>;
}

callback(
this: "callback" extends RestKeys<Used> ? ActionBuilder<Used> : never,
callback: string | ((this: void) => void)
) {
this._opts.callback = callback;
return this as unknown as ActionBuilder<Push<Used, "callback">>;
return this as unknown as ActionBuilder<Push<Used, "callback">, Id>;
}

description(
this: "description" extends RestKeys<Used> ? ActionBuilder<Used> : never,
description: string
) {
this._opts.description = description;
return this as unknown as ActionBuilder<Push<Used, "description">>;
return this as unknown as ActionBuilder<Push<Used, "description">, Id>;
}

icon(
this: "icon" extends RestKeys<Used> ? ActionBuilder<Used> : never,
icon: string
) {
this._opts.icon = icon;
return this as unknown as ActionBuilder<Push<Used, "icon">>;
return this as unknown as ActionBuilder<Push<Used, "icon">, Id>;
}

condition(
this: "condition" extends RestKeys<Used> ? ActionBuilder<Used> : never,
condition: ActionCondition
) {
this._opts.condition = condition;
return this as unknown as ActionBuilder<Push<Used, "condition">>;
return this as unknown as ActionBuilder<Push<Used, "condition">, Id>;
}

category(
this: "category" extends RestKeys<Used> ? ActionBuilder<Used> : never,
category: string
) {
this._opts.category = category;
return this as unknown as ActionBuilder<Push<Used, "category">>;
return this as unknown as ActionBuilder<Push<Used, "category">, Id>;
}

keys(
this: "keys" extends RestKeys<Used> ? ActionBuilder<Used> : never,
keys: string | string[]
) {
this._opts.keys = keys;
return this as unknown as ActionBuilder<Push<Used, "keys">>;
return this as unknown as ActionBuilder<Push<Used, "keys">, Id>;
}

from(
this: "from" extends RestKeys<Used> ? ActionBuilder<Used> : never,
from: string
) {
this._opts.from = from;
return this as unknown as ActionBuilder<Push<Used, "from">>;
return this as unknown as ActionBuilder<Push<Used, "from">, Id>;
}

build(
this: keyof GetRequired<ActionOptions> extends TupleToUnion<Used>
? ActionBuilder<Used>
this: keyof GetRequired<ActionOptions<Id>> extends TupleToUnion<Used>
? ActionBuilder<Used, Id>
: never
): Action {
): Action<Id> {
return new Action(this._opts);
}
}

export class ActionGroupBuilder {
type ActionList<Ids extends string[]> = Ids extends [infer F, ...infer R]
? F extends string
? R extends string[]
? [Action<F>, ...ActionList<R>]
: never
: never
: [];

export class ActionGroupBuilder<Ids extends string[] = []> {
private _sharedOptions: Pick<
ActionOptions,
ActionOptions<any>,
"category" | "from" | "condition"
>;

private _actions: Action[] = [];
private _actions: Action<any>[] = [];

constructor() {
this._sharedOptions = {};
Expand All @@ -150,7 +161,7 @@ export class ActionGroupBuilder {
return this;
}

private _update(action: Action) {
private _update<R extends string>(action: Action<R>) {
if (this._sharedOptions.category && !action.opts.category) {
action.opts.category = this._sharedOptions.category;
}
Expand All @@ -162,26 +173,26 @@ export class ActionGroupBuilder {
}
}

public add(action: Action) {
public add<Id extends string>(action: Action<Id>) {
this._actions.push(action);
return this;
return this as unknown as ActionGroupBuilder<Push<Ids, Id>>;
}

public addOpts(opts: ActionOptions) {
public addOpts<Id extends string>(opts: ActionOptions<Id>) {
this._actions.push(new Action(opts));
return this;
return this as unknown as ActionGroupBuilder<Push<Ids, Id>>;
}

public build(): Action[] {
public build() {
return this._actions.map((action) => {
this._update(action);
return action;
});
}) as ActionList<Ids>;
}
}

export class Action {
constructor(public opts: ActionOptions) {}
export class Action<Id extends string> {
constructor(public opts: ActionOptions<Id>) {}

public get id() {
return this.opts.id;
Expand Down Expand Up @@ -238,11 +249,11 @@ export class Action {
}

export class ActionRegistry {
private _actions: Map<string, Action> = new Map();
private _actions: Map<string, Action<any>> = new Map();

constructor() {}

public add(action: Action) {
public add(action: Action<any>) {
if (this._actions.has(action.id)) {
throw new Error(`Action ${action.id} already exists`);
}
Expand Down
4 changes: 2 additions & 2 deletions src/core/model/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export type PluginOpts = {
/**
* All actions registered by this plugin.
*/
providedActions?: Action[] | (() => Action[]);
providedActions?: Action<any>[] | (() => Action<any>[]);

/**
* Options for extending the plugin
Expand Down Expand Up @@ -117,7 +117,7 @@ export class Plugin {
});
}

get actions(): Action[] {
get actions(): Action<any>[] {
return this._cache.ensure("actions", () => {
if (!this._opts.providedActions) {
return [];
Expand Down

0 comments on commit 080ab7b

Please sign in to comment.