mirror of
https://github.com/murashit/codex-panel.git
synced 2026-07-22 06:57:10 +00:00
Clarify composer context reference suggestions
This commit is contained in:
parent
0c587f72cd
commit
e1e3786531
6 changed files with 49 additions and 13 deletions
|
|
@ -1,6 +1,7 @@
|
|||
export interface DailyNoteReferenceCandidate {
|
||||
keyword: "today" | "tomorrow" | "yesterday";
|
||||
display: string;
|
||||
name: string;
|
||||
path: string;
|
||||
linktext: string;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@ const THREAD_COMMAND_SUGGESTION_POLICIES: Record<ThreadSuggestionCommand, Thread
|
|||
};
|
||||
|
||||
const THREAD_SUGGESTION_COMMAND_PATTERN = new RegExp(`^/(${THREAD_SUGGESTION_COMMANDS.join("|")})\\s+([^\\s\\n]{0,120})$`);
|
||||
const SELECTION_SUGGESTION_PREVIEW_LIMIT = 500;
|
||||
|
||||
export function parseSlashCommand(text: string): { command: SlashCommandName; args: string } | null {
|
||||
const match = /^\/([A-Za-z-]+)(?:\s+([\s\S]*))?$/.exec(text);
|
||||
|
|
@ -142,7 +143,7 @@ function activeContextReferenceSuggestions(
|
|||
const suggestions: ComposerSuggestion[] = [];
|
||||
if (references?.activeNote && "active".startsWith(query)) {
|
||||
suggestions.push({
|
||||
display: "Active file",
|
||||
display: `Active · ${references.activeNote.name}`,
|
||||
detail: references.activeNote.path,
|
||||
replacement: activeNoteContextReferenceMarker(references.activeNote),
|
||||
start,
|
||||
|
|
@ -151,8 +152,8 @@ function activeContextReferenceSuggestions(
|
|||
}
|
||||
if (references?.selection && "selection".startsWith(query) && query !== "selection") {
|
||||
suggestions.push({
|
||||
display: "Selection",
|
||||
detail: `${references.selection.path} ${formatComposerContextRange(references.selection.range)}`,
|
||||
display: `Selection · ${references.selection.name} · ${formatComposerContextRange(references.selection.range)}`,
|
||||
detail: selectionSuggestionPreview(references.selection),
|
||||
replacement: selectionContextReferenceMarker(references.selection),
|
||||
start,
|
||||
selectionContext: references.selection,
|
||||
|
|
@ -161,7 +162,7 @@ function activeContextReferenceSuggestions(
|
|||
const matchingDailyNotes = dailyNoteReferenceList(dailyNoteReferences).filter((candidate) => candidate.keyword.startsWith(query));
|
||||
suggestions.push(
|
||||
...matchingDailyNotes.map((candidate) => ({
|
||||
display: candidate.display,
|
||||
display: `${candidate.display} · ${candidate.name}`,
|
||||
detail: candidate.path,
|
||||
replacement: `[[${candidate.linktext}]]`,
|
||||
start,
|
||||
|
|
@ -170,6 +171,11 @@ function activeContextReferenceSuggestions(
|
|||
return suggestions.slice(0, 8);
|
||||
}
|
||||
|
||||
function selectionSuggestionPreview(selection: SelectionContextReference): string {
|
||||
const preview = selection.text.replace(/\s+/g, " ").trim();
|
||||
return preview.length > SELECTION_SUGGESTION_PREVIEW_LIMIT ? `${preview.slice(0, SELECTION_SUGGESTION_PREVIEW_LIMIT - 1)}…` : preview;
|
||||
}
|
||||
|
||||
function dailyNoteReferenceList(
|
||||
references: readonly DailyNoteReferenceCandidate[] | (() => readonly DailyNoteReferenceCandidate[]) | undefined,
|
||||
): readonly DailyNoteReferenceCandidate[] {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { type App, moment, normalizePath, TFile } from "obsidian";
|
|||
import { appHasDailyNotesPluginLoaded, getDailyNoteSettings, type IPeriodicNoteSettings } from "obsidian-daily-notes-interface";
|
||||
|
||||
import type { DailyNoteReferenceCandidate } from "../../application/composer/daily-note-references";
|
||||
import { linktextForFile } from "./vault-note-links.obsidian";
|
||||
import { displayNameForFile, linktextForFile } from "./vault-note-links.obsidian";
|
||||
|
||||
const RELATIVE_DAILY_NOTES = [
|
||||
{ keyword: "today", display: "Today", dayOffset: 0 },
|
||||
|
|
@ -38,12 +38,17 @@ export function dailyNoteReferencesFromSettings(
|
|||
return {
|
||||
keyword,
|
||||
display,
|
||||
name: existingFile instanceof TFile ? displayNameForFile(existingFile) : dailyNoteName(filename),
|
||||
path,
|
||||
linktext: existingFile instanceof TFile ? linktextForFile(app, existingFile, sourcePath) : path.replace(/\.md$/i, ""),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function dailyNoteName(filename: string): string {
|
||||
return (filename.split("/").at(-1) ?? filename).replace(/\.md$/i, "");
|
||||
}
|
||||
|
||||
function dailyNotePath(folder: string, filename: string): string {
|
||||
const markdownFilename = filename.toLowerCase().endsWith(".md") ? filename : `${filename}.md`;
|
||||
return normalizePath(folder ? `${folder}/${markdownFilename}` : markdownFilename);
|
||||
|
|
|
|||
|
|
@ -236,7 +236,7 @@ describe("composer suggestions", () => {
|
|||
},
|
||||
})[0],
|
||||
).toMatchObject({
|
||||
display: "Active file",
|
||||
display: "Active · Beta Note",
|
||||
detail: "topics/Beta Note.md",
|
||||
replacement: "[[Beta Note]]",
|
||||
});
|
||||
|
|
@ -257,20 +257,20 @@ describe("composer suggestions", () => {
|
|||
path: "topics/Beta Note.md",
|
||||
linktext: "Beta Note",
|
||||
range: { from: { line: 41, ch: 4 }, to: { line: 46, ch: 0 } },
|
||||
text: "selected",
|
||||
text: " selected\n\ttext ",
|
||||
},
|
||||
},
|
||||
})[0],
|
||||
).toMatchObject({
|
||||
display: "Selection",
|
||||
detail: "topics/Beta Note.md L42:C5-L47:C1",
|
||||
display: "Selection · Beta Note · L42:C5-L47:C1",
|
||||
detail: "selected text",
|
||||
replacement: "[[Beta Note]] (L42:C5-L47:C1)",
|
||||
selectionContext: {
|
||||
name: "Beta Note",
|
||||
path: "topics/Beta Note.md",
|
||||
linktext: "Beta Note",
|
||||
range: { from: { line: 41, ch: 4 }, to: { line: 46, ch: 0 } },
|
||||
text: "selected",
|
||||
text: " selected\n\ttext ",
|
||||
},
|
||||
});
|
||||
expect(activeComposerSuggestions("/pla", notes, [])[0]?.replacement).toBe("/plan");
|
||||
|
|
@ -281,23 +281,43 @@ describe("composer suggestions", () => {
|
|||
expect(activeComposerSuggestions("/help", notes, [])).toEqual([]);
|
||||
});
|
||||
|
||||
it("bounds selection preview text before rendering it in the suggestion list", () => {
|
||||
const suggestion = activeComposerSuggestions("@sel", notes, [], [], [], null, {
|
||||
contextReferences: {
|
||||
activeNote: null,
|
||||
selection: {
|
||||
name: "Beta Note",
|
||||
path: "topics/Beta Note.md",
|
||||
linktext: "Beta Note",
|
||||
range: { from: { line: 0, ch: 0 }, to: { line: 0, ch: 600 } },
|
||||
text: "x".repeat(600),
|
||||
},
|
||||
},
|
||||
})[0];
|
||||
|
||||
expect(suggestion?.detail).toBe(`${"x".repeat(499)}…`);
|
||||
});
|
||||
|
||||
it("resolves relative daily-note references to configured wikilinks", () => {
|
||||
const dailyNoteReferences = [
|
||||
{
|
||||
keyword: "today",
|
||||
display: "Today",
|
||||
name: "2026-07-10",
|
||||
path: "Journal/2026/07/2026-07-10.md",
|
||||
linktext: "Journal/2026/07/2026-07-10",
|
||||
},
|
||||
{
|
||||
keyword: "tomorrow",
|
||||
display: "Tomorrow",
|
||||
name: "2026-07-11",
|
||||
path: "Journal/2026/07/2026-07-11.md",
|
||||
linktext: "Journal/2026/07/2026-07-11",
|
||||
},
|
||||
{
|
||||
keyword: "yesterday",
|
||||
display: "Yesterday",
|
||||
name: "2026-07-09",
|
||||
path: "Journal/2026/07/2026-07-09.md",
|
||||
linktext: "Journal/2026/07/2026-07-09",
|
||||
},
|
||||
|
|
@ -309,12 +329,12 @@ describe("composer suggestions", () => {
|
|||
}),
|
||||
).toMatchObject([
|
||||
{
|
||||
display: "Today",
|
||||
display: "Today · 2026-07-10",
|
||||
detail: "Journal/2026/07/2026-07-10.md",
|
||||
replacement: "[[Journal/2026/07/2026-07-10]]",
|
||||
},
|
||||
{
|
||||
display: "Tomorrow",
|
||||
display: "Tomorrow · 2026-07-11",
|
||||
detail: "Journal/2026/07/2026-07-11.md",
|
||||
replacement: "[[Journal/2026/07/2026-07-11]]",
|
||||
},
|
||||
|
|
@ -324,7 +344,7 @@ describe("composer suggestions", () => {
|
|||
dailyNoteReferences,
|
||||
})[0],
|
||||
).toMatchObject({
|
||||
display: "Yesterday",
|
||||
display: "Yesterday · 2026-07-09",
|
||||
detail: "Journal/2026/07/2026-07-09.md",
|
||||
replacement: "[[Journal/2026/07/2026-07-09]]",
|
||||
});
|
||||
|
|
|
|||
|
|
@ -48,18 +48,21 @@ describe("VaultNoteCandidateProvider", () => {
|
|||
{
|
||||
keyword: "today",
|
||||
display: "Today",
|
||||
name: "2026-07-10",
|
||||
path: "Journal/2026/07/2026-07-10.md",
|
||||
linktext: "2026-07-10",
|
||||
},
|
||||
{
|
||||
keyword: "tomorrow",
|
||||
display: "Tomorrow",
|
||||
name: "2026-07-11",
|
||||
path: "Journal/2026/07/2026-07-11.md",
|
||||
linktext: "Journal/2026/07/2026-07-11",
|
||||
},
|
||||
{
|
||||
keyword: "yesterday",
|
||||
display: "Yesterday",
|
||||
name: "2026-07-09",
|
||||
path: "Journal/2026/07/2026-07-09.md",
|
||||
linktext: "Journal/2026/07/2026-07-09",
|
||||
},
|
||||
|
|
|
|||
|
|
@ -178,6 +178,7 @@ describe("ChatComposerController", () => {
|
|||
{
|
||||
keyword: "today" as const,
|
||||
display: "Today",
|
||||
name: "2026-07-10",
|
||||
path: "Journal/2026-07-10.md",
|
||||
linktext: "Journal/2026-07-10",
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in a new issue