Skip to content

Commit

Permalink
feat: rework right-click
Browse files Browse the repository at this point in the history
  • Loading branch information
TwIStOy committed Nov 22, 2023
1 parent 3e21f4b commit 6c43bfb
Show file tree
Hide file tree
Showing 8 changed files with 230 additions and 288 deletions.
104 changes: 0 additions & 104 deletions src/conf/base/right-click.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { AvailableActions } from "@conf/plugins";

export const RightClickIndexes = {
textobjects: 1,
Expand All @@ -17,106 +16,3 @@ export type RightClickGroups = {
default: 1000;
};

interface RightClickMenuItemBase {
title: string;
keys?: string | string[];
}

interface RightClickMenuActionItem extends RightClickMenuItemBase {
actionId: AvailableActions;
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",
},
],
},
],
};

const RustToolkitGroup: RightClickMenuGroup = {
items: [
{
title: "Open cargo.toml",
actionId: "rust-tools.open-cargo-toml",
},
{
title: "Open parent module",
actionId: "rust-tools.open-parent-module",
},
],
};

const FormatFileItem: RightClickMenuActionItem = {
title: "Format file",
actionId: "conform.format",
keys: "c",
};

const CopilotGroup: RightClickMenuGroup = {
items: [
{
title: "Copilot",
children: [
{
title: "Copilot status",
actionId: "copilot.status",
keys: "s",
},
{
title: "Copilot auth",
actionId: "copilot.auth",
keys: "a",
},
{
title: "Copilot panel",
actionId: "copilot.show-panel",
keys: "p",
},
],
},
],
};

export const RightClickMenu: RightClickMenuItem[] = [
FormatFileItem,
CppToolkitGroup,
RustToolkitGroup,
CopilotGroup,
];
38 changes: 37 additions & 1 deletion src/conf/plugins/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { plugins as uiPlugins } from "./ui";
import { plugins as otherPlugins } from "./other";
import { plugins as codingPlugins } from "./coding";
import { plugins as treesitterPlugins } from "./treesitter";
import { Plugin, PluginActionIds } from "@core/model";
import { Action, Plugin, PluginActionIds } from "@core/model";
import { TupleToUnion } from "@core/type_traits";

export const AllPlugins = [
Expand All @@ -25,6 +25,42 @@ export const LazySpecs = [...AllPlugins, ...AllLspServers]
.flat()
.map((p) => p.asLazySpec());

export class ActionRegistry {
private static instance?: ActionRegistry;

private _actions: Map<string, Action<any>> = new Map();

private constructor() {
AllPlugins.flat().forEach((plug) => {
plug.actions.forEach((action) => {
this.add(action);
});
});
}

static getInstance() {
if (!ActionRegistry.instance) {
ActionRegistry.instance = new ActionRegistry();
}
return ActionRegistry.instance;
}

private add(action: Action<any>) {
if (this._actions.has(action.id)) {
throw new Error(`Action ${action.id} already exists`);
}
this._actions.set(action.id, action);
}

public get(id: string) {
return this._actions.get(id);
}

public get actions() {
return this._actions.values();
}
}

type RemoveReadonlyFromTuple<T extends readonly any[]> = T extends readonly [
infer A,
...infer Rest,
Expand Down
173 changes: 173 additions & 0 deletions src/conf/ui/right-click.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
import { ActionRegistry, AvailableActions } from "@conf/plugins";
import { ContextMenu } from "@core/components/context-menu";
import { MenuItem } from "@core/components/menu-item";
import { MenuText } from "@core/components/menu-text";
import { Cache } from "@core/model";
import { VimBuffer, isNil } from "@core/vim";

interface RightClickMenuItemBase {
title: string;
keys?: string | string[];
}

interface RightClickMenuActionItem extends RightClickMenuItemBase {
actionId: AvailableActions;
alwaysInMenu?: boolean;
}

interface RightClickMenuSubMenuItem extends RightClickMenuItemBase {
children: RightClickMenuItem[];
}

interface RightClickMenuGroup {
items: RightClickMenuItem[];
}

type RightClickMenuItem =
| RightClickMenuActionItem
| RightClickMenuSubMenuItem
| RightClickMenuGroup;

function normalizeKeys(keys?: string | string[]): string[] {
if (isNil(keys)) {
return [];
}
if (typeof keys === "string") {
return [keys];
} else {
return keys;
}
}

function intoMenuItem(buffer: VimBuffer, item: RightClickMenuItem): MenuItem[] {
if ("actionId" in item) {
return [
new MenuItem(
item.title,
() => {
let action = ActionRegistry.getInstance().get(item.actionId);
if (action === undefined) {
throw new Error(`Action ${item.actionId} not found`);
}
action.execute();
},
{
keys: normalizeKeys(item.keys),
alwaysInMenu: item.alwaysInMenu,
enabled: () => {
let action = ActionRegistry.getInstance().get(item.actionId);
if (action === undefined) {
throw new Error(`Action ${item.actionId} not found`);
}
return action.enabled(buffer);
},
}
),
];
} else if ("children" in item) {
return [
new MenuItem(item.title, () => {}, {
children: item.children.map((v) => intoMenuItem(buffer, v)).flat(),
keys: normalizeKeys(item.keys),
}),
];
} else {
return [
new MenuItem("---", () => {}),
...item.items.map((v) => intoMenuItem(buffer, v)).flat(),
];
}
}

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",
},
],
},
],
};

const RustToolkitGroup: RightClickMenuGroup = {
items: [
{
title: "Open cargo.toml",
actionId: "rust-tools.open-cargo-toml",
},
{
title: "Open parent module",
actionId: "rust-tools.open-parent-module",
},
],
};

const FormatFileItem: RightClickMenuActionItem = {
title: "Format file",
actionId: "conform.format",
keys: "c",
};

const CopilotGroup: RightClickMenuGroup = {
items: [
{
title: "Copilot",
children: [
{
title: "Copilot status",
actionId: "copilot.status",
keys: "s",
},
{
title: "Copilot auth",
actionId: "copilot.auth",
keys: "a",
},
{
title: "Copilot panel",
actionId: "copilot.show-panel",
keys: "p",
},
],
},
],
};

export const rightClickMenu: RightClickMenuItem[] = [
FormatFileItem,
CppToolkitGroup,
RustToolkitGroup,
CopilotGroup,
];

const _rightClickMenuCache = new Cache();

export function mountRightClickMenu(buffer: VimBuffer, opt?: any): void {
let items = _rightClickMenuCache.ensure(buffer.asCacheKey(), () => {
return rightClickMenu.map((v) => intoMenuItem(buffer, v)).flat();
});
let menu = new ContextMenu(items);
vim.schedule(() => {
menu.asNuiMenu(opt ?? {}).mount();
});
}
Loading

0 comments on commit 6c43bfb

Please sign in to comment.