feat: change ui from decorations to codelens
This commit is contained in:
+5
-5
@@ -1,18 +1,18 @@
|
||||
import * as path from "path";
|
||||
import * as vscode from "vscode";
|
||||
import { resolveTaskLocations } from "@/commands/resolveTaskLocations";
|
||||
import { TASK_FILE_EXTENSION } from "@/model/taskFile";
|
||||
import { IConfigProvider } from "@/ports";
|
||||
import { FsTaskRepository } from "@/storage/FsTaskRepository";
|
||||
import { NodeFileSystem } from "@/storage/NodeFileSystem";
|
||||
import { VscodeConfigProvider } from "@/storage/VscodeConfigProvider";
|
||||
import { IConfigProvider } from "@/ports";
|
||||
import { registerTaskCodeActions } from "@/ui/taskCodeActions";
|
||||
import { registerTaskCodeLenses } from "@/ui/taskCodeLenses";
|
||||
import { registerTaskCommands } from "@/ui/taskCommands";
|
||||
import { registerTaskDecorations } from "@/ui/taskDecorations";
|
||||
import { registerTaskDiagnostics } from "@/ui/taskDiagnostics";
|
||||
import { TaskDashboardPanel } from "@/views/taskDashboardPanel";
|
||||
import { TaskKanbanPanel } from "@/views/taskKanbanPanel";
|
||||
import { TaskTreeProvider } from "@/views/taskTreeProvider";
|
||||
import * as path from "path";
|
||||
import * as vscode from "vscode";
|
||||
|
||||
function createTaskWatchers(
|
||||
config: IConfigProvider,
|
||||
@@ -74,7 +74,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
context.subscriptions.push(statusBarItem);
|
||||
|
||||
registerTaskDiagnostics(context, { fs: fileSystem, config });
|
||||
registerTaskDecorations(context);
|
||||
registerTaskCodeLenses(context);
|
||||
registerTaskCodeActions(context);
|
||||
|
||||
registerTaskCommands(context, {
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
import { findFieldRange } from "@/frontmatter/frontmatterFields";
|
||||
import {
|
||||
isTaskFileName,
|
||||
TASK_FILE_EXTENSION,
|
||||
TASK_LANGUAGE_ID,
|
||||
} from "@/model/taskFile";
|
||||
import * as vscode from "vscode";
|
||||
import { EditableField } from "./editFrontmatterField";
|
||||
|
||||
const NBSP = "\u00A0";
|
||||
|
||||
type FieldLensDef = {
|
||||
field: EditableField;
|
||||
icon: string;
|
||||
label: string;
|
||||
command: string;
|
||||
};
|
||||
|
||||
const FIELDS: FieldLensDef[] = [
|
||||
{
|
||||
field: EditableField.STATUS,
|
||||
icon: "$(symbol-misc)",
|
||||
label: "Change status",
|
||||
command: "xboctukFlow.editTaskStatus",
|
||||
},
|
||||
{
|
||||
field: EditableField.PRIORITY,
|
||||
icon: "$(arrow-up)",
|
||||
label: "Change priority",
|
||||
command: "xboctukFlow.editTaskPriority",
|
||||
},
|
||||
{
|
||||
field: EditableField.TAGS,
|
||||
icon: "$(tag)",
|
||||
label: "Edit tags",
|
||||
command: "xboctukFlow.editTaskTags",
|
||||
},
|
||||
{
|
||||
field: EditableField.ASSIGNEE,
|
||||
icon: "$(account)",
|
||||
label: "Assign me",
|
||||
command: "xboctukFlow.setAssigneeMe",
|
||||
},
|
||||
];
|
||||
|
||||
function isTaskDocument(document: vscode.TextDocument): boolean {
|
||||
if (document.languageId === TASK_LANGUAGE_ID) return true;
|
||||
return isTaskFileName(document.fileName);
|
||||
}
|
||||
|
||||
class TaskFieldCodeLensProvider implements vscode.CodeLensProvider {
|
||||
provideCodeLenses(document: vscode.TextDocument): vscode.CodeLens[] {
|
||||
if (!isTaskDocument(document)) return [];
|
||||
|
||||
const lenses: vscode.CodeLens[] = [];
|
||||
const text = document.getText();
|
||||
const uri = document.uri.toString();
|
||||
|
||||
for (const { field, icon, label, command } of FIELDS) {
|
||||
const range = findFieldRange(text, field);
|
||||
if (!range) continue;
|
||||
|
||||
lenses.push(
|
||||
new vscode.CodeLens(
|
||||
new vscode.Range(range.startLine, 0, range.startLine, 0),
|
||||
{
|
||||
title: `${icon}${NBSP}${label}`,
|
||||
command,
|
||||
arguments: [uri],
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return lenses;
|
||||
}
|
||||
}
|
||||
|
||||
export function registerTaskCodeLenses(context: vscode.ExtensionContext): void {
|
||||
const provider = new TaskFieldCodeLensProvider();
|
||||
context.subscriptions.push(
|
||||
vscode.languages.registerCodeLensProvider(
|
||||
[
|
||||
{ language: TASK_LANGUAGE_ID },
|
||||
{ pattern: `**/*${TASK_FILE_EXTENSION}` },
|
||||
],
|
||||
provider,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -1,162 +0,0 @@
|
||||
import * as vscode from "vscode";
|
||||
import { findFieldRange } from "@/frontmatter/frontmatterFields";
|
||||
import { isTaskFileName, TASK_LANGUAGE_ID } from "@/model/taskFile";
|
||||
import { EditableField } from "./editFrontmatterField";
|
||||
|
||||
function isTaskEditor(editor: vscode.TextEditor): boolean {
|
||||
const { document } = editor;
|
||||
if (document.languageId === TASK_LANGUAGE_ID) {
|
||||
return true;
|
||||
}
|
||||
return isTaskFileName(document.fileName);
|
||||
}
|
||||
|
||||
function commandUri(command: string, args: unknown[]): string {
|
||||
return `command:${command}?${encodeURIComponent(JSON.stringify(args))}`;
|
||||
}
|
||||
|
||||
function hoverEditField(
|
||||
document: vscode.TextDocument,
|
||||
field: typeof EditableField.STATUS | typeof EditableField.PRIORITY,
|
||||
): vscode.MarkdownString {
|
||||
const command =
|
||||
field === EditableField.STATUS
|
||||
? "xboctukFlow.editTaskStatus"
|
||||
: "xboctukFlow.editTaskPriority";
|
||||
const label =
|
||||
field === EditableField.STATUS ? "Change status…" : "Change priority…";
|
||||
const md = new vscode.MarkdownString(
|
||||
`[$(edit) ${label}](${commandUri(command, [document.uri.toString()])})`,
|
||||
);
|
||||
md.isTrusted = true;
|
||||
md.supportThemeIcons = true;
|
||||
return md;
|
||||
}
|
||||
|
||||
function hoverAssigneeMe(document: vscode.TextDocument): vscode.MarkdownString {
|
||||
const md = new vscode.MarkdownString(
|
||||
`[$(account) me](${commandUri("xboctukFlow.setAssigneeMe", [document.uri.toString()])}) — set assignee from \`git config user.name\``,
|
||||
);
|
||||
md.isTrusted = true;
|
||||
md.supportThemeIcons = true;
|
||||
return md;
|
||||
}
|
||||
|
||||
function hoverTags(document: vscode.TextDocument): vscode.MarkdownString {
|
||||
const uri = document.uri.toString();
|
||||
const md = new vscode.MarkdownString(
|
||||
`[$(edit) Edit tags…](${commandUri("xboctukFlow.editTaskTags", [uri])})`,
|
||||
);
|
||||
md.isTrusted = true;
|
||||
md.supportThemeIcons = true;
|
||||
return md;
|
||||
}
|
||||
|
||||
export function registerTaskDecorations(
|
||||
context: vscode.ExtensionContext,
|
||||
): void {
|
||||
const decorationType = vscode.window.createTextEditorDecorationType({
|
||||
after: {
|
||||
margin: "0 0 0 1.5em",
|
||||
color: new vscode.ThemeColor("editorCodeLens.foreground"),
|
||||
},
|
||||
});
|
||||
context.subscriptions.push(decorationType);
|
||||
|
||||
const refresh = (editor: vscode.TextEditor | undefined): void => {
|
||||
if (!editor || !isTaskEditor(editor)) {
|
||||
if (editor) {
|
||||
editor.setDecorations(decorationType, []);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const text = editor.document.getText();
|
||||
const options: vscode.DecorationOptions[] = [];
|
||||
|
||||
for (const field of [
|
||||
EditableField.STATUS,
|
||||
EditableField.PRIORITY,
|
||||
] as const) {
|
||||
const range = findFieldRange(text, field);
|
||||
if (!range) continue;
|
||||
|
||||
options.push({
|
||||
range: new vscode.Range(
|
||||
range.startLine,
|
||||
range.startCol,
|
||||
range.endLine,
|
||||
range.endCol,
|
||||
),
|
||||
hoverMessage: hoverEditField(editor.document, field),
|
||||
renderOptions: {
|
||||
after: {
|
||||
contentText: " ✎",
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const assigneeRange = findFieldRange(text, EditableField.ASSIGNEE);
|
||||
if (assigneeRange) {
|
||||
options.push({
|
||||
range: new vscode.Range(
|
||||
assigneeRange.startLine,
|
||||
assigneeRange.startCol,
|
||||
assigneeRange.endLine,
|
||||
assigneeRange.endCol,
|
||||
),
|
||||
hoverMessage: hoverAssigneeMe(editor.document),
|
||||
renderOptions: {
|
||||
after: {
|
||||
contentText: " me",
|
||||
color: new vscode.ThemeColor("textLink.foreground"),
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const tagsRange = findFieldRange(text, EditableField.TAGS);
|
||||
if (tagsRange) {
|
||||
const lines = text.split(/\r?\n/);
|
||||
const lineEnd = lines[tagsRange.startLine]?.length ?? 0;
|
||||
options.push({
|
||||
range: new vscode.Range(
|
||||
tagsRange.startLine,
|
||||
lineEnd,
|
||||
tagsRange.startLine,
|
||||
lineEnd,
|
||||
),
|
||||
hoverMessage: hoverTags(editor.document),
|
||||
renderOptions: {
|
||||
after: {
|
||||
contentText: " ✎ tags",
|
||||
color: new vscode.ThemeColor("textLink.foreground"),
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
editor.setDecorations(decorationType, options);
|
||||
};
|
||||
|
||||
const refreshVisible = (): void => {
|
||||
for (const editor of vscode.window.visibleTextEditors) {
|
||||
refresh(editor);
|
||||
}
|
||||
};
|
||||
|
||||
refreshVisible();
|
||||
|
||||
context.subscriptions.push(
|
||||
vscode.window.onDidChangeActiveTextEditor(refresh),
|
||||
vscode.window.onDidChangeVisibleTextEditors(() => refreshVisible()),
|
||||
vscode.workspace.onDidChangeTextDocument((event) => {
|
||||
for (const editor of vscode.window.visibleTextEditors) {
|
||||
if (editor.document === event.document) {
|
||||
refresh(editor);
|
||||
}
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user