@fresh-editor/fresh-editor 0.1.75 → 0.1.77
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +55 -0
- package/README.md +8 -0
- package/package.json +1 -1
- package/plugins/audit_mode.ts +9 -4
- package/plugins/buffer_modified.ts +1 -1
- package/plugins/calculator.ts +1 -1
- package/plugins/check-types.sh +41 -0
- package/plugins/clangd_support.ts +1 -1
- package/plugins/color_highlighter.ts +4 -1
- package/plugins/config-schema.json +75 -3
- package/plugins/diagnostics_panel.i18n.json +52 -52
- package/plugins/diagnostics_panel.ts +168 -540
- package/plugins/find_references.ts +82 -324
- package/plugins/git_blame.i18n.json +260 -247
- package/plugins/git_blame.ts +4 -9
- package/plugins/git_explorer.ts +159 -0
- package/plugins/git_find_file.ts +42 -270
- package/plugins/git_grep.ts +50 -167
- package/plugins/git_gutter.ts +1 -1
- package/plugins/git_log.ts +4 -11
- package/plugins/lib/finder.ts +1499 -0
- package/plugins/lib/fresh.d.ts +118 -17
- package/plugins/lib/index.ts +23 -1
- package/plugins/lib/navigation-controller.ts +1 -1
- package/plugins/lib/panel-manager.ts +7 -13
- package/plugins/lib/results-panel.ts +914 -0
- package/plugins/lib/search-utils.ts +343 -0
- package/plugins/lib/types.ts +14 -0
- package/plugins/lib/virtual-buffer-factory.ts +3 -2
- package/plugins/live_grep.ts +56 -379
- package/plugins/markdown_compose.ts +1 -17
- package/plugins/merge_conflict.ts +16 -14
- package/plugins/odin-lsp.ts +135 -0
- package/plugins/path_complete.ts +1 -1
- package/plugins/search_replace.i18n.json +13 -13
- package/plugins/search_replace.ts +11 -9
- package/plugins/theme_editor.ts +15 -9
- package/plugins/todo_highlighter.ts +1 -0
- package/plugins/vi_mode.ts +9 -5
- package/plugins/welcome.ts +1 -1
package/plugins/git_blame.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/// <reference path="
|
|
1
|
+
/// <reference path="./lib/fresh.d.ts" />
|
|
2
2
|
const editor = getEditor();
|
|
3
3
|
|
|
4
4
|
|
|
@@ -664,14 +664,9 @@ globalThis.git_blame_copy_hash = function(): void {
|
|
|
664
664
|
return;
|
|
665
665
|
}
|
|
666
666
|
|
|
667
|
-
//
|
|
668
|
-
editor.
|
|
669
|
-
|
|
670
|
-
editor.setStatus(editor.t("status.hash_copied", { short: hash.slice(0, 7), full: hash }));
|
|
671
|
-
})
|
|
672
|
-
.catch(() => {
|
|
673
|
-
editor.setStatus(editor.t("status.hash_display", { hash }));
|
|
674
|
-
});
|
|
667
|
+
// Copy hash to clipboard
|
|
668
|
+
editor.copyToClipboard(hash);
|
|
669
|
+
editor.setStatus(editor.t("status.hash_copied", { short: hash.slice(0, 7), full: hash }));
|
|
675
670
|
};
|
|
676
671
|
|
|
677
672
|
// =============================================================================
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/// <reference path="../types/fresh.d.ts" />
|
|
2
|
+
const editor = getEditor();
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Git Explorer Decorations
|
|
6
|
+
*
|
|
7
|
+
* Adds VS Code-style status badges (M/A/U/D/...) to the file explorer.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const NAMESPACE = "git-explorer";
|
|
11
|
+
|
|
12
|
+
const COLORS = {
|
|
13
|
+
added: [80, 250, 123] as [number, number, number],
|
|
14
|
+
modified: [255, 184, 108] as [number, number, number],
|
|
15
|
+
deleted: [255, 85, 85] as [number, number, number],
|
|
16
|
+
renamed: [139, 233, 253] as [number, number, number],
|
|
17
|
+
untracked: [241, 250, 140] as [number, number, number],
|
|
18
|
+
conflicted: [255, 121, 198] as [number, number, number],
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const PRIORITY = {
|
|
22
|
+
conflicted: 90,
|
|
23
|
+
deleted: 80,
|
|
24
|
+
added: 60,
|
|
25
|
+
modified: 50,
|
|
26
|
+
renamed: 40,
|
|
27
|
+
untracked: 30,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
let refreshInFlight = false;
|
|
31
|
+
|
|
32
|
+
function statusToDecoration(status: string, staged: boolean) {
|
|
33
|
+
switch (status) {
|
|
34
|
+
case "A":
|
|
35
|
+
return { symbol: "A", color: COLORS.added, priority: PRIORITY.added };
|
|
36
|
+
case "M":
|
|
37
|
+
return {
|
|
38
|
+
symbol: "M",
|
|
39
|
+
color: staged ? COLORS.added : COLORS.modified,
|
|
40
|
+
priority: PRIORITY.modified + (staged ? 2 : 0),
|
|
41
|
+
};
|
|
42
|
+
case "D":
|
|
43
|
+
return { symbol: "D", color: COLORS.deleted, priority: PRIORITY.deleted };
|
|
44
|
+
case "R":
|
|
45
|
+
return { symbol: "R", color: COLORS.renamed, priority: PRIORITY.renamed };
|
|
46
|
+
case "C":
|
|
47
|
+
return { symbol: "C", color: COLORS.renamed, priority: PRIORITY.renamed };
|
|
48
|
+
case "U":
|
|
49
|
+
return { symbol: "!", color: COLORS.conflicted, priority: PRIORITY.conflicted };
|
|
50
|
+
default:
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function parseStatusOutput(output: string, repoRoot: string) {
|
|
56
|
+
const separator = output.includes("\0") ? "\0" : "\n";
|
|
57
|
+
const entries = output
|
|
58
|
+
.split(separator)
|
|
59
|
+
.map((entry) => entry.replace(/\r$/, ""))
|
|
60
|
+
.filter((entry) => entry.length > 0);
|
|
61
|
+
const byPath = new Map<string, { path: string; symbol: string; color: [number, number, number]; priority: number }>();
|
|
62
|
+
|
|
63
|
+
for (let i = 0; i < entries.length; i++) {
|
|
64
|
+
const entry = entries[i];
|
|
65
|
+
if (entry.length < 3) {
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
const x = entry[0];
|
|
69
|
+
const y = entry[1];
|
|
70
|
+
let path = entry.slice(3);
|
|
71
|
+
|
|
72
|
+
if ((x === "R" || x === "C") && separator === "\0" && i + 1 < entries.length) {
|
|
73
|
+
i += 1;
|
|
74
|
+
path = entries[i];
|
|
75
|
+
} else if (entry.includes(" -> ") && (x === "R" || x === "C" || y === "R" || y === "C")) {
|
|
76
|
+
path = entry.split(" -> ").pop() ?? path;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
let decoration = null;
|
|
80
|
+
if (x === "?" && y === "?") {
|
|
81
|
+
decoration = { symbol: "U", color: COLORS.untracked, priority: PRIORITY.untracked };
|
|
82
|
+
} else if (x !== " " && x !== "?") {
|
|
83
|
+
decoration = statusToDecoration(x, true);
|
|
84
|
+
} else if (y !== " ") {
|
|
85
|
+
decoration = statusToDecoration(y, false);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (!decoration) {
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const absolutePath = editor.pathJoin(repoRoot, path);
|
|
93
|
+
const existing = byPath.get(absolutePath);
|
|
94
|
+
if (!existing || decoration.priority >= existing.priority) {
|
|
95
|
+
byPath.set(absolutePath, { path: absolutePath, ...decoration });
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return Array.from(byPath.values());
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async function refreshGitExplorerDecorations() {
|
|
103
|
+
if (refreshInFlight) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
refreshInFlight = true;
|
|
107
|
+
try {
|
|
108
|
+
const cwd = editor.getCwd();
|
|
109
|
+
const rootResult = await editor.spawnProcess("git", ["rev-parse", "--show-toplevel"], cwd);
|
|
110
|
+
if (rootResult.exit_code !== 0) {
|
|
111
|
+
editor.clearFileExplorerDecorations(NAMESPACE);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const repoRoot = rootResult.stdout.trim();
|
|
115
|
+
if (!repoRoot) {
|
|
116
|
+
editor.clearFileExplorerDecorations(NAMESPACE);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const statusResult = await editor.spawnProcess(
|
|
121
|
+
"git",
|
|
122
|
+
["status", "--porcelain"],
|
|
123
|
+
repoRoot
|
|
124
|
+
);
|
|
125
|
+
if (statusResult.exit_code !== 0) {
|
|
126
|
+
editor.clearFileExplorerDecorations(NAMESPACE);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const decorations = parseStatusOutput(statusResult.stdout, repoRoot);
|
|
131
|
+
if (decorations.length === 0) {
|
|
132
|
+
editor.clearFileExplorerDecorations(NAMESPACE);
|
|
133
|
+
} else {
|
|
134
|
+
editor.setFileExplorerDecorations(NAMESPACE, decorations);
|
|
135
|
+
}
|
|
136
|
+
} catch (_err) {
|
|
137
|
+
editor.clearFileExplorerDecorations(NAMESPACE);
|
|
138
|
+
} finally {
|
|
139
|
+
refreshInFlight = false;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
globalThis.onGitExplorerAfterFileOpen = () => {
|
|
144
|
+
refreshGitExplorerDecorations();
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
globalThis.onGitExplorerAfterFileSave = () => {
|
|
148
|
+
refreshGitExplorerDecorations();
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
globalThis.onGitExplorerEditorInitialized = () => {
|
|
152
|
+
refreshGitExplorerDecorations();
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
editor.on("after_file_open", "onGitExplorerAfterFileOpen");
|
|
156
|
+
editor.on("after_file_save", "onGitExplorerAfterFileSave");
|
|
157
|
+
editor.on("editor_initialized", "onGitExplorerEditorInitialized");
|
|
158
|
+
|
|
159
|
+
refreshGitExplorerDecorations();
|
package/plugins/git_find_file.ts
CHANGED
|
@@ -1,287 +1,65 @@
|
|
|
1
|
-
/// <reference path="
|
|
2
|
-
const editor = getEditor();
|
|
3
|
-
|
|
1
|
+
/// <reference path="./lib/fresh.d.ts" />
|
|
4
2
|
|
|
5
3
|
/**
|
|
6
4
|
* Git Find File Plugin
|
|
7
5
|
*
|
|
8
6
|
* Provides interactive file finding functionality with fuzzy search
|
|
9
|
-
* for git-tracked files. Uses the
|
|
7
|
+
* for git-tracked files. Uses the Finder abstraction with filter mode.
|
|
10
8
|
*/
|
|
11
9
|
|
|
12
|
-
|
|
13
|
-
let allFiles: string[] = [];
|
|
14
|
-
let filteredFiles: string[] = [];
|
|
15
|
-
let isLoading = false;
|
|
16
|
-
|
|
17
|
-
// Simple fuzzy filter function
|
|
18
|
-
function fuzzyMatch(str: string, pattern: string): boolean {
|
|
19
|
-
if (pattern === "") {
|
|
20
|
-
return true;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
str = str.toLowerCase();
|
|
24
|
-
pattern = pattern.toLowerCase();
|
|
25
|
-
|
|
26
|
-
let strIdx = 0;
|
|
27
|
-
let patIdx = 0;
|
|
28
|
-
|
|
29
|
-
while (strIdx < str.length && patIdx < pattern.length) {
|
|
30
|
-
if (str[strIdx] === pattern[patIdx]) {
|
|
31
|
-
patIdx++;
|
|
32
|
-
}
|
|
33
|
-
strIdx++;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
return patIdx >= pattern.length;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Score a fuzzy match (higher is better)
|
|
40
|
-
function fuzzyScore(str: string, pattern: string): number {
|
|
41
|
-
if (pattern === "") return 0;
|
|
42
|
-
|
|
43
|
-
str = str.toLowerCase();
|
|
44
|
-
pattern = pattern.toLowerCase();
|
|
45
|
-
|
|
46
|
-
let score = 0;
|
|
47
|
-
let strIdx = 0;
|
|
48
|
-
let patIdx = 0;
|
|
49
|
-
let consecutiveMatches = 0;
|
|
50
|
-
let lastMatchIdx = -1;
|
|
51
|
-
|
|
52
|
-
while (strIdx < str.length && patIdx < pattern.length) {
|
|
53
|
-
if (str[strIdx] === pattern[patIdx]) {
|
|
54
|
-
// Bonus for consecutive matches
|
|
55
|
-
if (lastMatchIdx === strIdx - 1) {
|
|
56
|
-
consecutiveMatches++;
|
|
57
|
-
score += consecutiveMatches * 10;
|
|
58
|
-
} else {
|
|
59
|
-
consecutiveMatches = 1;
|
|
60
|
-
score += 1;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Bonus for matching at start of path segments
|
|
64
|
-
if (strIdx === 0 || str[strIdx - 1] === "/" || str[strIdx - 1] === "_" || str[strIdx - 1] === "-") {
|
|
65
|
-
score += 15;
|
|
66
|
-
}
|
|
10
|
+
import { Finder } from "./lib/finder.ts";
|
|
67
11
|
|
|
68
|
-
|
|
69
|
-
const lastSlash = str.lastIndexOf("/");
|
|
70
|
-
if (strIdx > lastSlash) {
|
|
71
|
-
score += 5;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
lastMatchIdx = strIdx;
|
|
75
|
-
patIdx++;
|
|
76
|
-
}
|
|
77
|
-
strIdx++;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Penalty for longer paths
|
|
81
|
-
score -= str.length * 0.1;
|
|
82
|
-
|
|
83
|
-
return patIdx >= pattern.length ? score : -1;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Filter and sort files by query using fuzzy matching
|
|
87
|
-
function filterFiles(files: string[], query: string): string[] {
|
|
88
|
-
if (query === "" || query.trim() === "") {
|
|
89
|
-
// Return first 100 files for empty query
|
|
90
|
-
return files.slice(0, 100);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const scored: Array<{ file: string; score: number }> = [];
|
|
94
|
-
|
|
95
|
-
for (const file of files) {
|
|
96
|
-
const score = fuzzyScore(file, query);
|
|
97
|
-
if (score > 0) {
|
|
98
|
-
scored.push({ file, score });
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Stop early if we have enough high-quality matches
|
|
102
|
-
if (scored.length >= 500) {
|
|
103
|
-
break;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// Sort by score descending
|
|
108
|
-
scored.sort((a, b) => b.score - a.score);
|
|
109
|
-
|
|
110
|
-
// Return top 100 results
|
|
111
|
-
return scored.slice(0, 100).map((s) => s.file);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// Load git-tracked files asynchronously
|
|
115
|
-
async function loadGitFiles(): Promise<void> {
|
|
116
|
-
if (isLoading) {
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
isLoading = true;
|
|
121
|
-
editor.setStatus(editor.t("status.loading"));
|
|
122
|
-
|
|
123
|
-
try {
|
|
124
|
-
const result = await editor.spawnProcess("git", ["ls-files"]);
|
|
125
|
-
|
|
126
|
-
if (result.exit_code === 0) {
|
|
127
|
-
allFiles = result.stdout.split("\n").filter((line) => line.trim() !== "");
|
|
12
|
+
const editor = getEditor();
|
|
128
13
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
14
|
+
// Create the finder instance with filter mode
|
|
15
|
+
const finder = new Finder<string>(editor, {
|
|
16
|
+
id: "git-find-file",
|
|
17
|
+
format: (file) => ({
|
|
18
|
+
label: file,
|
|
19
|
+
location: { file, line: 1, column: 1 },
|
|
20
|
+
}),
|
|
21
|
+
preview: false, // No preview for file finder
|
|
22
|
+
maxResults: 100,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// Load git-tracked files
|
|
26
|
+
async function loadGitFiles(): Promise<string[]> {
|
|
27
|
+
const result = await editor.spawnProcess("git", ["ls-files"]);
|
|
28
|
+
|
|
29
|
+
if (result.exit_code === 0) {
|
|
30
|
+
return result.stdout.split("\n").filter((line) => line.trim() !== "");
|
|
142
31
|
}
|
|
143
|
-
}
|
|
144
32
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
return files.map((file) => {
|
|
148
|
-
return {
|
|
149
|
-
text: file,
|
|
150
|
-
description: undefined,
|
|
151
|
-
value: file,
|
|
152
|
-
disabled: false,
|
|
153
|
-
};
|
|
154
|
-
});
|
|
33
|
+
editor.debug(`Failed to load git files: ${result.stderr}`);
|
|
34
|
+
return [];
|
|
155
35
|
}
|
|
156
36
|
|
|
157
37
|
// Global function to start file finder
|
|
158
|
-
globalThis.start_git_find_file =
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// Clear previous results
|
|
170
|
-
filteredFiles = [];
|
|
171
|
-
|
|
172
|
-
// Start the prompt
|
|
173
|
-
editor.startPrompt(editor.t("prompt.find_file"), "git-find-file");
|
|
174
|
-
|
|
175
|
-
// Show initial suggestions (first 100 files)
|
|
176
|
-
const initial = filterFiles(allFiles, "");
|
|
177
|
-
filteredFiles = initial;
|
|
178
|
-
editor.setPromptSuggestions(filesToSuggestions(initial));
|
|
179
|
-
editor.setStatus(editor.t("status.files_available", { count: String(allFiles.length) }));
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
// React to prompt input changes
|
|
183
|
-
globalThis.onGitFindFilePromptChanged = function (args: { prompt_type: string; input: string }): boolean {
|
|
184
|
-
if (args.prompt_type !== "git-find-file") {
|
|
185
|
-
return true; // Not our prompt
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
const query = args.input;
|
|
189
|
-
|
|
190
|
-
// Filter files based on query
|
|
191
|
-
const matches = filterFiles(allFiles, query);
|
|
192
|
-
filteredFiles = matches;
|
|
193
|
-
|
|
194
|
-
// Update suggestions
|
|
195
|
-
editor.setPromptSuggestions(filesToSuggestions(matches));
|
|
196
|
-
|
|
197
|
-
// Update status
|
|
198
|
-
if (matches.length > 0) {
|
|
199
|
-
if (query.trim() === "") {
|
|
200
|
-
editor.setStatus(editor.t("status.showing_first", { shown: String(matches.length), total: String(allFiles.length) }));
|
|
201
|
-
} else {
|
|
202
|
-
editor.setStatus(editor.t("status.found_matching", { count: String(matches.length), query }));
|
|
203
|
-
}
|
|
204
|
-
} else {
|
|
205
|
-
editor.setStatus(editor.t("status.no_matching", { query }));
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
return true;
|
|
209
|
-
};
|
|
210
|
-
|
|
211
|
-
// Handle prompt confirmation (user pressed Enter)
|
|
212
|
-
globalThis.onGitFindFilePromptConfirmed = function (args: {
|
|
213
|
-
prompt_type: string;
|
|
214
|
-
selected_index: number | null;
|
|
215
|
-
input: string;
|
|
216
|
-
}): boolean {
|
|
217
|
-
if (args.prompt_type !== "git-find-file") {
|
|
218
|
-
return true; // Not our prompt
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
editor.debug(`git-find-file confirmed: selected_index=${args.selected_index}, input=${args.input}`);
|
|
222
|
-
|
|
223
|
-
// Check if user selected a suggestion
|
|
224
|
-
if (args.selected_index !== null && filteredFiles[args.selected_index]) {
|
|
225
|
-
const selectedFile = filteredFiles[args.selected_index];
|
|
226
|
-
|
|
227
|
-
editor.debug(`Opening file: ${selectedFile}`);
|
|
228
|
-
|
|
229
|
-
// Open the file at line 1
|
|
230
|
-
editor.openFile(selectedFile, 1, 1);
|
|
231
|
-
editor.setStatus(editor.t("status.opened", { file: selectedFile }));
|
|
232
|
-
} else if (args.input.trim() !== "") {
|
|
233
|
-
// Try to open input directly if it's a valid file path
|
|
234
|
-
const inputFile = args.input.trim();
|
|
235
|
-
|
|
236
|
-
// Check if the exact input matches any file
|
|
237
|
-
if (allFiles.includes(inputFile)) {
|
|
238
|
-
editor.openFile(inputFile, 1, 1);
|
|
239
|
-
editor.setStatus(editor.t("status.opened", { file: inputFile }));
|
|
240
|
-
} else {
|
|
241
|
-
editor.setStatus(editor.t("status.file_not_found", { file: inputFile }));
|
|
242
|
-
}
|
|
243
|
-
} else {
|
|
244
|
-
editor.setStatus(editor.t("status.no_selection"));
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
return true;
|
|
248
|
-
};
|
|
249
|
-
|
|
250
|
-
// Handle prompt cancellation (user pressed Escape)
|
|
251
|
-
globalThis.onGitFindFilePromptCancelled = function (args: { prompt_type: string }): boolean {
|
|
252
|
-
if (args.prompt_type !== "git-find-file") {
|
|
253
|
-
return true; // Not our prompt
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// Clear results
|
|
257
|
-
filteredFiles = [];
|
|
258
|
-
editor.setStatus(editor.t("status.cancelled"));
|
|
259
|
-
|
|
260
|
-
return true;
|
|
38
|
+
globalThis.start_git_find_file = function (): void {
|
|
39
|
+
finder.prompt({
|
|
40
|
+
title: editor.t("prompt.find_file"),
|
|
41
|
+
source: {
|
|
42
|
+
mode: "filter",
|
|
43
|
+
load: loadGitFiles,
|
|
44
|
+
// Uses built-in fuzzy filter by default
|
|
45
|
+
},
|
|
46
|
+
});
|
|
261
47
|
};
|
|
262
48
|
|
|
263
|
-
// Register event handlers
|
|
264
|
-
editor.on("prompt_changed", "onGitFindFilePromptChanged");
|
|
265
|
-
editor.on("prompt_confirmed", "onGitFindFilePromptConfirmed");
|
|
266
|
-
editor.on("prompt_cancelled", "onGitFindFilePromptCancelled");
|
|
267
|
-
|
|
268
49
|
// Reload git files command
|
|
269
50
|
globalThis.git_reload_files = async function (): Promise<void> {
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
// Show file count command
|
|
275
|
-
globalThis.git_file_count = function (): void {
|
|
276
|
-
if (allFiles.length === 0) {
|
|
277
|
-
editor.setStatus(editor.t("status.no_files_loaded"));
|
|
278
|
-
} else {
|
|
279
|
-
editor.setStatus(editor.t("status.indexed", { count: String(allFiles.length) }));
|
|
280
|
-
}
|
|
51
|
+
// Just re-trigger the prompt which will reload
|
|
52
|
+
globalThis.start_git_find_file();
|
|
53
|
+
editor.setStatus(editor.t("status.reloading"));
|
|
281
54
|
};
|
|
282
55
|
|
|
283
56
|
// Register commands
|
|
284
|
-
editor.registerCommand(
|
|
57
|
+
editor.registerCommand(
|
|
58
|
+
"%cmd.find",
|
|
59
|
+
"%cmd.find_desc",
|
|
60
|
+
"start_git_find_file",
|
|
61
|
+
"normal"
|
|
62
|
+
);
|
|
285
63
|
|
|
286
64
|
editor.registerCommand(
|
|
287
65
|
"%cmd.reload",
|
|
@@ -290,11 +68,5 @@ editor.registerCommand(
|
|
|
290
68
|
"normal"
|
|
291
69
|
);
|
|
292
70
|
|
|
293
|
-
editor.
|
|
294
|
-
|
|
295
|
-
// Note: We don't load git files on plugin init because spawning processes requires async context
|
|
296
|
-
// Files will be loaded lazily on first use
|
|
297
|
-
|
|
298
|
-
editor.debug("Git Find File plugin loaded successfully (TypeScript)");
|
|
299
|
-
editor.debug("Usage: Call start_git_find_file() or use command palette 'Git Find File'");
|
|
71
|
+
editor.debug("Git Find File plugin loaded (using Finder abstraction)");
|
|
300
72
|
editor.setStatus(editor.t("status.ready"));
|