119 lines
3.1 KiB
TypeScript
119 lines
3.1 KiB
TypeScript
import { resolveTaskLocations } from "@/commands/resolveTaskLocations";
|
|
import {
|
|
findFieldRange,
|
|
replaceFrontmatterField,
|
|
} from "@/frontmatter/frontmatterFields";
|
|
import {
|
|
isTaskFileName,
|
|
TASK_LANGUAGE_ID,
|
|
} from "@/model/taskFile";
|
|
import { IConfigProvider, IFileSystem } from "@/ports";
|
|
import * as vscode from "vscode";
|
|
import { resolveTaskFolderForPath } from "./resolveTaskFolder";
|
|
|
|
export type FrontmatterEditDeps = {
|
|
fs: IFileSystem;
|
|
config: IConfigProvider;
|
|
};
|
|
|
|
export const EditableField = {
|
|
STATUS: "status",
|
|
PRIORITY: "priority",
|
|
ASSIGNEE: "assignee",
|
|
TAGS: "tags",
|
|
} as const;
|
|
|
|
export type EditableField = (typeof EditableField)[keyof typeof EditableField];
|
|
|
|
function isTaskDocument(document: vscode.TextDocument): boolean {
|
|
if (document.languageId === TASK_LANGUAGE_ID) return true;
|
|
return isTaskFileName(document.fileName);
|
|
}
|
|
|
|
export async function resolveDocument(
|
|
uriArg?: string,
|
|
): Promise<vscode.TextDocument | undefined> {
|
|
if (typeof uriArg === "string" && uriArg.length > 0) {
|
|
const uri = vscode.Uri.parse(uriArg);
|
|
return vscode.workspace.openTextDocument(uri);
|
|
}
|
|
const active = vscode.window.activeTextEditor?.document;
|
|
if (active && isTaskDocument(active)) {
|
|
return active;
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
export function workspaceCwdFor(
|
|
document: vscode.TextDocument,
|
|
): string | undefined {
|
|
const folder = vscode.workspace.getWorkspaceFolder(document.uri);
|
|
return folder?.uri.fsPath;
|
|
}
|
|
|
|
export async function applyFieldValue(
|
|
document: vscode.TextDocument,
|
|
key: EditableField,
|
|
value: string,
|
|
): Promise<boolean> {
|
|
const text = document.getText();
|
|
const result = replaceFrontmatterField(text, key, value);
|
|
if (!result.ok) {
|
|
void vscode.window.showErrorMessage(
|
|
result.reason === "no-field"
|
|
? `Field "${key}" not found in frontmatter`
|
|
: "No YAML frontmatter in this file",
|
|
);
|
|
return false;
|
|
}
|
|
|
|
const valueRange = findFieldRange(text, key);
|
|
if (!valueRange) {
|
|
const full = new vscode.Range(
|
|
document.positionAt(0),
|
|
document.positionAt(text.length),
|
|
);
|
|
const edit = new vscode.WorkspaceEdit();
|
|
edit.replace(document.uri, full, result.content);
|
|
return vscode.workspace.applyEdit(edit);
|
|
}
|
|
|
|
const range = new vscode.Range(
|
|
valueRange.startLine,
|
|
valueRange.startCol,
|
|
valueRange.endLine,
|
|
valueRange.endCol,
|
|
);
|
|
const edit = new vscode.WorkspaceEdit();
|
|
edit.replace(document.uri, range, value);
|
|
return vscode.workspace.applyEdit(edit);
|
|
}
|
|
|
|
export function getCurrentFieldValue(
|
|
text: string,
|
|
field: string,
|
|
): string | undefined {
|
|
const range = findFieldRange(text, field);
|
|
if (!range) return undefined;
|
|
const lines = text.split(/\r?\n/);
|
|
const raw = lines[range.startLine]!.slice(
|
|
range.startCol,
|
|
range.endCol,
|
|
).trim();
|
|
if (
|
|
(raw.startsWith('"') && raw.endsWith('"')) ||
|
|
(raw.startsWith("'") && raw.endsWith("'"))
|
|
) {
|
|
return raw.slice(1, raw.length - 1);
|
|
}
|
|
return raw;
|
|
}
|
|
|
|
export async function resolveTaskFolder(
|
|
document: vscode.TextDocument,
|
|
config: IConfigProvider,
|
|
): Promise<string | undefined> {
|
|
const locations = resolveTaskLocations(config);
|
|
return resolveTaskFolderForPath(document.fileName, locations);
|
|
}
|