@fresh-editor/fresh-editor 0.1.75 → 0.1.76
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 +26 -0
- package/README.md +6 -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 +44 -2
- 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_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 +93 -17
- package/plugins/lib/index.ts +14 -0
- 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/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/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
|
// =============================================================================
|
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"));
|
package/plugins/git_grep.ts
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
|
-
/// <reference path="
|
|
2
|
-
const editor = getEditor();
|
|
3
|
-
|
|
1
|
+
/// <reference path="./lib/fresh.d.ts" />
|
|
4
2
|
|
|
5
3
|
/**
|
|
6
4
|
* Git Grep Plugin
|
|
7
5
|
*
|
|
8
|
-
* Provides interactive git grep functionality with live search results
|
|
6
|
+
* Provides interactive git grep functionality with live search results
|
|
7
|
+
* and preview panel. Uses the Finder abstraction for unified search UX.
|
|
9
8
|
*/
|
|
10
9
|
|
|
10
|
+
import { Finder, parseGrepOutput } from "./lib/finder.ts";
|
|
11
|
+
|
|
12
|
+
const editor = getEditor();
|
|
13
|
+
|
|
14
|
+
// Result type from git grep
|
|
11
15
|
interface GrepMatch {
|
|
12
16
|
file: string;
|
|
13
17
|
line: number;
|
|
@@ -15,177 +19,56 @@ interface GrepMatch {
|
|
|
15
19
|
content: string;
|
|
16
20
|
}
|
|
17
21
|
|
|
18
|
-
//
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
function
|
|
38
|
-
|
|
39
|
-
suggestions: PromptSuggestion[];
|
|
40
|
-
} {
|
|
41
|
-
const results: GrepMatch[] = [];
|
|
42
|
-
const suggestions: PromptSuggestion[] = [];
|
|
43
|
-
|
|
44
|
-
for (const line of stdout.split("\n")) {
|
|
45
|
-
if (!line.trim()) continue;
|
|
46
|
-
const match = parseGitGrepLine(line);
|
|
47
|
-
if (match) {
|
|
48
|
-
results.push(match);
|
|
49
|
-
suggestions.push({
|
|
50
|
-
text: `${match.file}:${match.line}:${match.column}`,
|
|
51
|
-
description: match.content,
|
|
52
|
-
value: `${match.file}:${match.line}:${match.column}`,
|
|
53
|
-
disabled: false,
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
// Limit to 100 results for performance
|
|
57
|
-
if (results.length >= 100) {
|
|
58
|
-
break;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return { results, suggestions };
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Global function to start git grep
|
|
67
|
-
globalThis.start_git_grep = function(): void {
|
|
68
|
-
// Clear previous results
|
|
69
|
-
gitGrepResults = [];
|
|
70
|
-
|
|
71
|
-
// Start the prompt
|
|
72
|
-
editor.startPrompt(editor.t("prompt.grep"), "git-grep");
|
|
73
|
-
editor.setStatus(editor.t("status.type_to_search"));
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
// React to prompt input changes
|
|
77
|
-
globalThis.onGitGrepPromptChanged = function(args: {
|
|
78
|
-
prompt_type: string;
|
|
79
|
-
input: string;
|
|
80
|
-
}): boolean {
|
|
81
|
-
if (args.prompt_type !== "git-grep") {
|
|
82
|
-
return true; // Not our prompt
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const query = args.input;
|
|
86
|
-
|
|
87
|
-
// Don't search for empty queries
|
|
88
|
-
if (!query || query.trim() === "") {
|
|
89
|
-
editor.setPromptSuggestions([]);
|
|
90
|
-
return true;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// Spawn git grep asynchronously
|
|
22
|
+
// Create the finder instance
|
|
23
|
+
const finder = new Finder<GrepMatch>(editor, {
|
|
24
|
+
id: "git-grep",
|
|
25
|
+
format: (match) => ({
|
|
26
|
+
label: `${match.file}:${match.line}`,
|
|
27
|
+
description:
|
|
28
|
+
match.content.length > 60
|
|
29
|
+
? match.content.substring(0, 57).trim() + "..."
|
|
30
|
+
: match.content.trim(),
|
|
31
|
+
location: {
|
|
32
|
+
file: match.file,
|
|
33
|
+
line: match.line,
|
|
34
|
+
column: match.column,
|
|
35
|
+
},
|
|
36
|
+
}),
|
|
37
|
+
preview: true,
|
|
38
|
+
maxResults: 100,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// Search function using git grep
|
|
42
|
+
async function searchWithGitGrep(query: string): Promise<GrepMatch[]> {
|
|
94
43
|
const cwd = editor.getCwd();
|
|
95
|
-
editor.spawnProcess(
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
const { results, suggestions } = parseGitGrepOutput(result.stdout);
|
|
100
|
-
gitGrepResults = results;
|
|
101
|
-
|
|
102
|
-
// Update prompt with suggestions
|
|
103
|
-
editor.setPromptSuggestions(suggestions);
|
|
104
|
-
|
|
105
|
-
// Update status
|
|
106
|
-
if (results.length > 0) {
|
|
107
|
-
editor.setStatus(editor.t("status.found", { count: String(results.length) }));
|
|
108
|
-
} else {
|
|
109
|
-
editor.setStatus(editor.t("status.no_matches"));
|
|
110
|
-
}
|
|
111
|
-
} else if (result.exit_code === 1) {
|
|
112
|
-
// No matches found (git grep returns 1)
|
|
113
|
-
gitGrepResults = [];
|
|
114
|
-
editor.setPromptSuggestions([]);
|
|
115
|
-
editor.setStatus(editor.t("status.no_matches"));
|
|
116
|
-
} else {
|
|
117
|
-
// Error occurred
|
|
118
|
-
editor.setStatus(editor.t("status.error", { error: result.stderr }));
|
|
119
|
-
}
|
|
120
|
-
})
|
|
121
|
-
.catch((e) => {
|
|
122
|
-
editor.setStatus(editor.t("status.error", { error: String(e) }));
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
return true;
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
// Handle prompt confirmation (user pressed Enter)
|
|
129
|
-
globalThis.onGitGrepPromptConfirmed = function(args: {
|
|
130
|
-
prompt_type: string;
|
|
131
|
-
selected_index: number | null;
|
|
132
|
-
input: string;
|
|
133
|
-
}): boolean {
|
|
134
|
-
if (args.prompt_type !== "git-grep") {
|
|
135
|
-
return true; // Not our prompt
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
editor.debug(
|
|
139
|
-
`prompt-confirmed: selected_index=${args.selected_index}, num_results=${gitGrepResults.length}`
|
|
44
|
+
const result = await editor.spawnProcess(
|
|
45
|
+
"git",
|
|
46
|
+
["grep", "-n", "--column", "-I", "--", query],
|
|
47
|
+
cwd
|
|
140
48
|
);
|
|
141
49
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
const selected = gitGrepResults[args.selected_index];
|
|
145
|
-
|
|
146
|
-
editor.debug(`Opening file: ${selected.file}:${selected.line}:${selected.column}`);
|
|
147
|
-
|
|
148
|
-
// Open the file at the specific location
|
|
149
|
-
editor.openFile(selected.file, selected.line, selected.column);
|
|
150
|
-
editor.setStatus(editor.t("status.opened", { location: `${selected.file}:${selected.line}:${selected.column}` }));
|
|
151
|
-
} else {
|
|
152
|
-
// No selection
|
|
153
|
-
editor.debug("No file selected - selected_index is null or out of bounds");
|
|
154
|
-
editor.setStatus(editor.t("status.no_selection"));
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
return true;
|
|
158
|
-
};
|
|
159
|
-
|
|
160
|
-
// Handle prompt cancellation (user pressed Escape)
|
|
161
|
-
globalThis.onGitGrepPromptCancelled = function(args: {
|
|
162
|
-
prompt_type: string;
|
|
163
|
-
}): boolean {
|
|
164
|
-
if (args.prompt_type !== "git-grep") {
|
|
165
|
-
return true; // Not our prompt
|
|
50
|
+
if (result.exit_code === 0) {
|
|
51
|
+
return parseGrepOutput(result.stdout, 100) as GrepMatch[];
|
|
166
52
|
}
|
|
53
|
+
return [];
|
|
54
|
+
}
|
|
167
55
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
56
|
+
// Global function to start git grep
|
|
57
|
+
globalThis.start_git_grep = function (): void {
|
|
58
|
+
finder.prompt({
|
|
59
|
+
title: editor.t("prompt.grep"),
|
|
60
|
+
source: {
|
|
61
|
+
mode: "search",
|
|
62
|
+
search: searchWithGitGrep,
|
|
63
|
+
debounceMs: 150,
|
|
64
|
+
minQueryLength: 1,
|
|
65
|
+
},
|
|
66
|
+
});
|
|
173
67
|
};
|
|
174
68
|
|
|
175
|
-
// Register event handlers
|
|
176
|
-
editor.on("prompt_changed", "onGitGrepPromptChanged");
|
|
177
|
-
editor.on("prompt_confirmed", "onGitGrepPromptConfirmed");
|
|
178
|
-
editor.on("prompt_cancelled", "onGitGrepPromptCancelled");
|
|
179
|
-
|
|
180
69
|
// Register command
|
|
181
|
-
editor.registerCommand(
|
|
182
|
-
"%cmd.grep",
|
|
183
|
-
"%cmd.grep_desc",
|
|
184
|
-
"start_git_grep",
|
|
185
|
-
"normal"
|
|
186
|
-
);
|
|
70
|
+
editor.registerCommand("%cmd.grep", "%cmd.grep_desc", "start_git_grep", "normal");
|
|
187
71
|
|
|
188
72
|
// Log that plugin loaded successfully
|
|
189
|
-
editor.debug("Git Grep plugin loaded
|
|
190
|
-
editor.debug("Usage: Call start_git_grep() or use command palette 'Git Grep'");
|
|
73
|
+
editor.debug("Git Grep plugin loaded (using Finder abstraction)");
|
|
191
74
|
editor.setStatus(editor.t("status.ready"));
|
package/plugins/git_gutter.ts
CHANGED
package/plugins/git_log.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
|
|
|
@@ -932,16 +932,9 @@ globalThis.git_log_copy_hash = function(): void {
|
|
|
932
932
|
return;
|
|
933
933
|
}
|
|
934
934
|
|
|
935
|
-
//
|
|
936
|
-
|
|
937
|
-
editor.
|
|
938
|
-
.then(() => {
|
|
939
|
-
editor.setStatus(editor.t("status.hash_copied", { short: commit.shortHash, full: commit.hash }));
|
|
940
|
-
})
|
|
941
|
-
.catch(() => {
|
|
942
|
-
// If all clipboard commands fail, just show the hash
|
|
943
|
-
editor.setStatus(editor.t("status.hash_display", { hash: commit.hash }));
|
|
944
|
-
});
|
|
935
|
+
// Copy hash to clipboard
|
|
936
|
+
editor.copyToClipboard(commit.hash);
|
|
937
|
+
editor.setStatus(editor.t("status.hash_copied", { short: commit.shortHash, full: commit.hash }));
|
|
945
938
|
};
|
|
946
939
|
|
|
947
940
|
// =============================================================================
|