@fresh-editor/fresh-editor 0.1.4

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.
Files changed (38) hide show
  1. package/.gitignore +2 -0
  2. package/LICENSE +117 -0
  3. package/README.md +54 -0
  4. package/binary-install.js +212 -0
  5. package/binary.js +126 -0
  6. package/install.js +4 -0
  7. package/npm-shrinkwrap.json +900 -0
  8. package/package.json +100 -0
  9. package/plugins/README.md +121 -0
  10. package/plugins/clangd_support.md +20 -0
  11. package/plugins/clangd_support.ts +323 -0
  12. package/plugins/color_highlighter.ts +302 -0
  13. package/plugins/diagnostics_panel.ts +308 -0
  14. package/plugins/examples/README.md +245 -0
  15. package/plugins/examples/async_demo.ts +165 -0
  16. package/plugins/examples/bookmarks.ts +329 -0
  17. package/plugins/examples/buffer_query_demo.ts +110 -0
  18. package/plugins/examples/git_grep.ts +262 -0
  19. package/plugins/examples/hello_world.ts +93 -0
  20. package/plugins/examples/virtual_buffer_demo.ts +116 -0
  21. package/plugins/find_references.ts +357 -0
  22. package/plugins/git_find_file.ts +298 -0
  23. package/plugins/git_grep.ts +188 -0
  24. package/plugins/git_log.ts +1283 -0
  25. package/plugins/lib/fresh.d.ts +849 -0
  26. package/plugins/lib/index.ts +24 -0
  27. package/plugins/lib/navigation-controller.ts +214 -0
  28. package/plugins/lib/panel-manager.ts +218 -0
  29. package/plugins/lib/types.ts +72 -0
  30. package/plugins/lib/virtual-buffer-factory.ts +158 -0
  31. package/plugins/manual_help.ts +243 -0
  32. package/plugins/markdown_compose.ts +1207 -0
  33. package/plugins/merge_conflict.ts +1811 -0
  34. package/plugins/path_complete.ts +163 -0
  35. package/plugins/search_replace.ts +481 -0
  36. package/plugins/todo_highlighter.ts +204 -0
  37. package/plugins/welcome.ts +74 -0
  38. package/run-fresh.js +4 -0
@@ -0,0 +1,329 @@
1
+ /// <reference path="../../types/fresh.d.ts" />
2
+
3
+ /**
4
+ * Bookmarks Plugin for Fresh Editor (TypeScript)
5
+ *
6
+ * Demonstrates the new TypeScript plugin ops:
7
+ * - editor.registerCommand() - Register plugin commands
8
+ * - editor.openFile() - Open file at specific location
9
+ * - editor.getActiveSplitId() - Get current split ID
10
+ * - editor.openFileInSplit() - Open file in specific split
11
+ *
12
+ * Features:
13
+ * - Add bookmarks at current cursor position
14
+ * - List all bookmarks
15
+ * - Jump to bookmarks
16
+ * - Remove bookmarks
17
+ * - Split-aware navigation
18
+ */
19
+
20
+ // Bookmark storage
21
+ interface Bookmark {
22
+ id: number;
23
+ name: string;
24
+ path: string;
25
+ line: number;
26
+ column: number;
27
+ splitId: number;
28
+ }
29
+
30
+ const bookmarks: Map<number, Bookmark> = new Map();
31
+ let nextBookmarkId = 1;
32
+
33
+ // Helper: Get current location info
34
+ function getCurrentLocation(): {
35
+ path: string;
36
+ position: number;
37
+ splitId: number;
38
+ } {
39
+ const bufferId = editor.getActiveBufferId();
40
+ const path = editor.getBufferPath(bufferId);
41
+ const position = editor.getCursorPosition();
42
+ const splitId = editor.getActiveSplitId();
43
+
44
+ return { path, position, splitId };
45
+ }
46
+
47
+ // Helper: Get actual line number using the API
48
+ function getCurrentLineCol(): { line: number; column: number } {
49
+ // Use the actual getCursorLine API for accurate line number
50
+ const lineNumber = editor.getCursorLine();
51
+
52
+ // Get cursor position within the line by reading buffer content
53
+ const bufferId = editor.getActiveBufferId();
54
+ const cursorPos = editor.getCursorPosition();
55
+ const bufferInfo = editor.getBufferInfo(bufferId);
56
+
57
+ // Calculate column by finding start of current line
58
+ let column = 1;
59
+ if (bufferInfo && cursorPos > 0) {
60
+ // Read a small chunk before cursor to find line start
61
+ const readStart = Math.max(0, cursorPos - 1000);
62
+ const textBefore = editor.getBufferText(bufferId, readStart, cursorPos);
63
+ const lastNewline = textBefore.lastIndexOf("\n");
64
+ if (lastNewline !== -1) {
65
+ column = cursorPos - (readStart + lastNewline);
66
+ } else {
67
+ // No newline found, column is position from readStart
68
+ column = cursorPos - readStart + 1;
69
+ }
70
+ }
71
+
72
+ return { line: lineNumber, column };
73
+ }
74
+
75
+ // Action: Add bookmark at current position
76
+ globalThis.bookmark_add = function (): void {
77
+ const { path, position, splitId } = getCurrentLocation();
78
+ const { line, column } = getCurrentLineCol();
79
+
80
+ if (!path) {
81
+ editor.setStatus("Cannot bookmark: buffer has no file path");
82
+ return;
83
+ }
84
+
85
+ const id = nextBookmarkId++;
86
+ const name = `Bookmark ${id}`;
87
+
88
+ const bookmark: Bookmark = {
89
+ id,
90
+ name,
91
+ path,
92
+ line,
93
+ column,
94
+ splitId,
95
+ };
96
+
97
+ bookmarks.set(id, bookmark);
98
+
99
+ // Add visual indicator with bookmark namespace
100
+ const bufferId = editor.getActiveBufferId();
101
+ editor.addOverlay(
102
+ bufferId,
103
+ "bookmark", // namespace for all bookmarks
104
+ position,
105
+ position + 1,
106
+ 0, // Red
107
+ 128, // Green (teal color)
108
+ 255, // Blue
109
+ true // Underline
110
+ );
111
+
112
+ editor.setStatus(`Added ${name} at ${path}:${line}:${column}`);
113
+ editor.debug(`Bookmark ${id} created: ${JSON.stringify(bookmark)}`);
114
+ };
115
+
116
+ // Action: List all bookmarks
117
+ globalThis.bookmark_list = function (): void {
118
+ if (bookmarks.size === 0) {
119
+ editor.setStatus("No bookmarks");
120
+ return;
121
+ }
122
+
123
+ const list: string[] = [];
124
+ bookmarks.forEach((bm, id) => {
125
+ list.push(`[${id}] ${bm.path}:${bm.line}:${bm.column}`);
126
+ });
127
+
128
+ editor.setStatus(`Bookmarks: ${list.join(" | ")}`);
129
+ editor.debug(`All bookmarks: ${JSON.stringify([...bookmarks.values()])}`);
130
+ };
131
+
132
+ // Action: Jump to bookmark by ID
133
+ globalThis.bookmark_goto = function (): void {
134
+ if (bookmarks.size === 0) {
135
+ editor.setStatus("No bookmarks to jump to");
136
+ return;
137
+ }
138
+
139
+ // Jump to the first bookmark (simplified)
140
+ const firstBookmark = bookmarks.values().next().value;
141
+ if (firstBookmark) {
142
+ const success = editor.openFile(
143
+ firstBookmark.path,
144
+ firstBookmark.line,
145
+ firstBookmark.column
146
+ );
147
+
148
+ if (success) {
149
+ editor.setStatus(
150
+ `Jumped to ${firstBookmark.name}: ${firstBookmark.path}:${firstBookmark.line}`
151
+ );
152
+ } else {
153
+ editor.setStatus(`Failed to open ${firstBookmark.path}`);
154
+ }
155
+ }
156
+ };
157
+
158
+ // Action: Jump to bookmark in same split (split-aware)
159
+ globalThis.bookmark_goto_split = function (): void {
160
+ if (bookmarks.size === 0) {
161
+ editor.setStatus("No bookmarks");
162
+ return;
163
+ }
164
+
165
+ const currentSplit = editor.getActiveSplitId();
166
+ const firstBookmark = bookmarks.values().next().value;
167
+
168
+ if (firstBookmark) {
169
+ // Open in the current split, not the bookmark's original split
170
+ const success = editor.openFileInSplit(
171
+ currentSplit,
172
+ firstBookmark.path,
173
+ firstBookmark.line,
174
+ firstBookmark.column
175
+ );
176
+
177
+ if (success) {
178
+ editor.setStatus(
179
+ `Opened ${firstBookmark.name} in split ${currentSplit}`
180
+ );
181
+ } else {
182
+ editor.setStatus(`Failed to open in split ${currentSplit}`);
183
+ }
184
+ }
185
+ };
186
+
187
+ // Action: Remove all bookmarks
188
+ globalThis.bookmark_clear = function (): void {
189
+ const bufferId = editor.getActiveBufferId();
190
+
191
+ // Remove all bookmark overlays using namespace
192
+ editor.clearNamespace(bufferId, "bookmark");
193
+
194
+ const count = bookmarks.size;
195
+ bookmarks.clear();
196
+
197
+ editor.setStatus(`Cleared ${count} bookmark(s)`);
198
+ };
199
+
200
+ // Action: Show current split info
201
+ globalThis.show_split_info = function (): void {
202
+ const splitId = editor.getActiveSplitId();
203
+ const bufferId = editor.getActiveBufferId();
204
+ const path = editor.getBufferPath(bufferId);
205
+
206
+ editor.setStatus(`Split ${splitId} | Buffer ${bufferId} | ${path || "[untitled]"}`);
207
+ };
208
+
209
+ // Interactive bookmark selection using prompt API
210
+ let bookmarkSuggestionIds: number[] = [];
211
+
212
+ globalThis.bookmark_select = function (): void {
213
+ if (bookmarks.size === 0) {
214
+ editor.setStatus("No bookmarks to select");
215
+ return;
216
+ }
217
+
218
+ // Create suggestions from bookmarks
219
+ const suggestions: PromptSuggestion[] = [];
220
+ bookmarkSuggestionIds = [];
221
+
222
+ bookmarks.forEach((bm) => {
223
+ const filename = bm.path.split("/").pop() || bm.path;
224
+ suggestions.push({
225
+ text: `${bm.name}: ${bm.path}:${bm.line}:${bm.column}`,
226
+ description: `${filename} at line ${bm.line}`,
227
+ value: String(bm.id),
228
+ disabled: false,
229
+ });
230
+ bookmarkSuggestionIds.push(bm.id);
231
+ });
232
+
233
+ editor.startPrompt("Select bookmark: ", "bookmark-select");
234
+ editor.setPromptSuggestions(suggestions);
235
+ editor.setStatus(`${bookmarks.size} bookmark(s) available`);
236
+ };
237
+
238
+ // Handle bookmark selection confirmation
239
+ globalThis.onBookmarkSelectConfirmed = function (args: {
240
+ prompt_type: string;
241
+ selected_index: number | null;
242
+ input: string;
243
+ }): boolean {
244
+ if (args.prompt_type !== "bookmark-select") {
245
+ return true;
246
+ }
247
+
248
+ if (args.selected_index !== null && bookmarkSuggestionIds[args.selected_index] !== undefined) {
249
+ const bookmarkId = bookmarkSuggestionIds[args.selected_index];
250
+ const bookmark = bookmarks.get(bookmarkId);
251
+
252
+ if (bookmark) {
253
+ editor.openFile(bookmark.path, bookmark.line, bookmark.column);
254
+ editor.setStatus(`Jumped to ${bookmark.name}: ${bookmark.path}:${bookmark.line}`);
255
+ }
256
+ } else {
257
+ editor.setStatus("No bookmark selected");
258
+ }
259
+
260
+ return true;
261
+ };
262
+
263
+ // Handle bookmark selection cancellation
264
+ globalThis.onBookmarkSelectCancelled = function (args: { prompt_type: string }): boolean {
265
+ if (args.prompt_type !== "bookmark-select") {
266
+ return true;
267
+ }
268
+
269
+ editor.setStatus("Bookmark selection cancelled");
270
+ return true;
271
+ };
272
+
273
+ // Register bookmark event handlers
274
+ editor.on("prompt_confirmed", "onBookmarkSelectConfirmed");
275
+ editor.on("prompt_cancelled", "onBookmarkSelectCancelled");
276
+
277
+ // Register commands on plugin load
278
+ editor.registerCommand(
279
+ "Add Bookmark",
280
+ "Add a bookmark at the current cursor position",
281
+ "bookmark_add",
282
+ "normal"
283
+ );
284
+
285
+ editor.registerCommand(
286
+ "List Bookmarks",
287
+ "Show all bookmarks",
288
+ "bookmark_list",
289
+ "normal"
290
+ );
291
+
292
+ editor.registerCommand(
293
+ "Go to Bookmark",
294
+ "Jump to the first bookmark",
295
+ "bookmark_goto",
296
+ "normal"
297
+ );
298
+
299
+ editor.registerCommand(
300
+ "Go to Bookmark (Current Split)",
301
+ "Jump to bookmark in current split",
302
+ "bookmark_goto_split",
303
+ "normal"
304
+ );
305
+
306
+ editor.registerCommand(
307
+ "Clear Bookmarks",
308
+ "Remove all bookmarks",
309
+ "bookmark_clear",
310
+ "normal"
311
+ );
312
+
313
+ editor.registerCommand(
314
+ "Show Split Info",
315
+ "Display current split and buffer information",
316
+ "show_split_info",
317
+ "" // Available in all contexts
318
+ );
319
+
320
+ editor.registerCommand(
321
+ "Select Bookmark",
322
+ "Interactively select and jump to a bookmark",
323
+ "bookmark_select",
324
+ "normal"
325
+ );
326
+
327
+ // Plugin initialized
328
+ editor.setStatus("Bookmarks plugin loaded - 7 commands registered");
329
+ editor.debug("Bookmarks plugin initialized with command registration and prompt API support");
@@ -0,0 +1,110 @@
1
+ /// <reference path="../../types/fresh.d.ts" />
2
+
3
+ /**
4
+ * Buffer Query Demo Plugin
5
+ * Demonstrates the buffer query APIs in Phase 2
6
+ */
7
+
8
+ // Show buffer info
9
+ globalThis.show_buffer_info_demo = function(): void {
10
+ const bufferId = editor.getActiveBufferId();
11
+ const info = editor.getBufferInfo(bufferId);
12
+
13
+ if (info) {
14
+ const msg = `Buffer ${info.id}: ${info.path || "[No Name]"} (${
15
+ info.modified ? "modified" : "saved"
16
+ }, ${info.length} bytes)`;
17
+ editor.setStatus(msg);
18
+ } else {
19
+ editor.setStatus("No buffer info available");
20
+ }
21
+ };
22
+
23
+ editor.registerCommand(
24
+ "Query Demo: Show Buffer Info",
25
+ "Display information about the current buffer",
26
+ "show_buffer_info_demo",
27
+ "normal"
28
+ );
29
+
30
+ // Show cursor position with selection info
31
+ globalThis.show_cursor_info_demo = function(): void {
32
+ const cursor = editor.getPrimaryCursor();
33
+
34
+ if (cursor) {
35
+ let msg: string;
36
+ if (cursor.selection) {
37
+ msg = `Cursor at ${cursor.position}, selection: ${cursor.selection.start}-${cursor.selection.end} (${
38
+ cursor.selection.end - cursor.selection.start
39
+ } chars)`;
40
+ } else {
41
+ msg = `Cursor at byte position ${cursor.position} (no selection)`;
42
+ }
43
+ editor.setStatus(msg);
44
+ } else {
45
+ editor.setStatus("No cursor info available");
46
+ }
47
+ };
48
+
49
+ editor.registerCommand(
50
+ "Query Demo: Show Cursor Position",
51
+ "Display cursor position and selection info",
52
+ "show_cursor_info_demo",
53
+ "normal"
54
+ );
55
+
56
+ // Count all cursors (multi-cursor support)
57
+ globalThis.count_cursors_demo = function(): void {
58
+ const cursors = editor.getAllCursors();
59
+ editor.setStatus(`Active cursors: ${cursors.length}`);
60
+ };
61
+
62
+ editor.registerCommand(
63
+ "Query Demo: Count All Cursors",
64
+ "Display the number of active cursors",
65
+ "count_cursors_demo",
66
+ "normal"
67
+ );
68
+
69
+ // List all buffers
70
+ globalThis.list_all_buffers_demo = function(): void {
71
+ const buffers = editor.listBuffers();
72
+ let modifiedCount = 0;
73
+
74
+ for (const buf of buffers) {
75
+ if (buf.modified) {
76
+ modifiedCount++;
77
+ }
78
+ }
79
+
80
+ editor.setStatus(`Open buffers: ${buffers.length} (${modifiedCount} modified)`);
81
+ };
82
+
83
+ editor.registerCommand(
84
+ "Query Demo: List All Buffers",
85
+ "Show count of open buffers",
86
+ "list_all_buffers_demo",
87
+ "normal"
88
+ );
89
+
90
+ // Show viewport info
91
+ globalThis.show_viewport_demo = function(): void {
92
+ const vp = editor.getViewport();
93
+
94
+ if (vp) {
95
+ const msg = `Viewport: ${vp.width}x${vp.height}, top_byte=${vp.top_byte}, left_col=${vp.left_column}`;
96
+ editor.setStatus(msg);
97
+ } else {
98
+ editor.setStatus("No viewport info available");
99
+ }
100
+ };
101
+
102
+ editor.registerCommand(
103
+ "Query Demo: Show Viewport Info",
104
+ "Display viewport dimensions and scroll position",
105
+ "show_viewport_demo",
106
+ "normal"
107
+ );
108
+
109
+ editor.setStatus("Buffer Query Demo plugin loaded! Try the 'Query Demo' commands.");
110
+ editor.debug("Buffer Query Demo plugin initialized (TypeScript version)");
@@ -0,0 +1,262 @@
1
+ /// <reference path="../../types/fresh.d.ts" />
2
+
3
+ /**
4
+ * Git Grep TypeScript Plugin for Fresh Editor
5
+ *
6
+ * Demonstrates async process spawning with native Promises:
7
+ * - Uses editor.spawnProcess() for async git operations
8
+ * - Parses git grep output and displays results
9
+ * - Shows file opening with line/column positioning
10
+ * - Registers multiple commands on plugin load
11
+ *
12
+ * This is a significant improvement over the Lua version because:
13
+ * - Native async/await instead of callback-based pattern
14
+ * - Cleaner error handling with try/catch
15
+ * - Type safety from TypeScript
16
+ * - Better state management with closures
17
+ */
18
+
19
+ // Store search results for navigation
20
+ interface GrepMatch {
21
+ file: string;
22
+ line: number;
23
+ text: string;
24
+ }
25
+
26
+ let searchResults: GrepMatch[] = [];
27
+ let currentResultIndex = 0;
28
+
29
+ // Parse git grep output into structured results
30
+ function parseGitGrepOutput(output: string): GrepMatch[] {
31
+ const matches: GrepMatch[] = [];
32
+ const lines = output.split("\n").filter((line) => line.trim());
33
+
34
+ for (const line of lines) {
35
+ // git grep output format: file:line:text
36
+ const match = line.match(/^([^:]+):(\d+):(.*)$/);
37
+ if (match) {
38
+ matches.push({
39
+ file: match[1],
40
+ line: parseInt(match[2], 10),
41
+ text: match[3].trim(),
42
+ });
43
+ }
44
+ }
45
+
46
+ return matches;
47
+ }
48
+
49
+ // Action: Search for pattern in repository
50
+ globalThis.git_grep_search = async function (): Promise<void> {
51
+ // For now, search for a hardcoded pattern
52
+ // In a full implementation, this would use a prompt
53
+ const pattern = "TODO";
54
+
55
+ editor.setStatus(`Searching for "${pattern}"...`);
56
+
57
+ try {
58
+ const result = await editor.spawnProcess("git", [
59
+ "grep",
60
+ "-n", // Show line numbers
61
+ "-I", // Skip binary files
62
+ pattern,
63
+ ]);
64
+
65
+ if (result.exit_code === 0 && result.stdout.trim()) {
66
+ searchResults = parseGitGrepOutput(result.stdout);
67
+ currentResultIndex = 0;
68
+
69
+ if (searchResults.length > 0) {
70
+ editor.setStatus(
71
+ `Found ${searchResults.length} matches for "${pattern}"`
72
+ );
73
+ editor.debug(`Git grep results: ${JSON.stringify(searchResults)}`);
74
+
75
+ // Jump to first result
76
+ const first = searchResults[0];
77
+ editor.openFile(first.file, first.line, 1);
78
+ editor.setStatus(
79
+ `[1/${searchResults.length}] ${first.file}:${first.line}: ${first.text}`
80
+ );
81
+ }
82
+ } else if (result.exit_code === 1) {
83
+ // git grep returns 1 when no matches found
84
+ editor.setStatus(`No matches found for "${pattern}"`);
85
+ searchResults = [];
86
+ } else {
87
+ editor.setStatus(`Git grep error: ${result.stderr || "Unknown error"}`);
88
+ editor.debug(`Git grep failed with exit code ${result.exit_code}`);
89
+ }
90
+ } catch (error) {
91
+ editor.setStatus(`Git grep failed: ${error}`);
92
+ editor.debug(`Git grep exception: ${error}`);
93
+ }
94
+ };
95
+
96
+ // Action: Go to next search result
97
+ globalThis.git_grep_next = function (): void {
98
+ if (searchResults.length === 0) {
99
+ editor.setStatus("No search results. Run git_grep_search first.");
100
+ return;
101
+ }
102
+
103
+ currentResultIndex = (currentResultIndex + 1) % searchResults.length;
104
+ const result = searchResults[currentResultIndex];
105
+
106
+ editor.openFile(result.file, result.line, 1);
107
+ editor.setStatus(
108
+ `[${currentResultIndex + 1}/${searchResults.length}] ${result.file}:${result.line}: ${result.text}`
109
+ );
110
+ };
111
+
112
+ // Action: Go to previous search result
113
+ globalThis.git_grep_prev = function (): void {
114
+ if (searchResults.length === 0) {
115
+ editor.setStatus("No search results. Run git_grep_search first.");
116
+ return;
117
+ }
118
+
119
+ currentResultIndex =
120
+ (currentResultIndex - 1 + searchResults.length) % searchResults.length;
121
+ const result = searchResults[currentResultIndex];
122
+
123
+ editor.openFile(result.file, result.line, 1);
124
+ editor.setStatus(
125
+ `[${currentResultIndex + 1}/${searchResults.length}] ${result.file}:${result.line}: ${result.text}`
126
+ );
127
+ };
128
+
129
+ // Action: Show current git status
130
+ globalThis.git_status = async function (): Promise<void> {
131
+ editor.setStatus("Getting git status...");
132
+
133
+ try {
134
+ const result = await editor.spawnProcess("git", ["status", "--short"]);
135
+
136
+ if (result.exit_code === 0) {
137
+ const lines = result.stdout.trim().split("\n").filter((l) => l);
138
+ if (lines.length === 0) {
139
+ editor.setStatus("Git: Clean working directory");
140
+ } else {
141
+ editor.setStatus(`Git: ${lines.length} changed file(s)`);
142
+ editor.debug(`Git status:\n${result.stdout}`);
143
+ }
144
+ } else {
145
+ editor.setStatus(`Not a git repository or git error`);
146
+ }
147
+ } catch (error) {
148
+ editor.setStatus(`Git status failed: ${error}`);
149
+ }
150
+ };
151
+
152
+ // Action: Show current branch
153
+ globalThis.git_branch = async function (): Promise<void> {
154
+ try {
155
+ const result = await editor.spawnProcess("git", [
156
+ "rev-parse",
157
+ "--abbrev-ref",
158
+ "HEAD",
159
+ ]);
160
+
161
+ if (result.exit_code === 0) {
162
+ const branch = result.stdout.trim();
163
+ editor.setStatus(`Git branch: ${branch}`);
164
+ } else {
165
+ editor.setStatus("Not a git repository");
166
+ }
167
+ } catch (error) {
168
+ editor.setStatus(`Git branch failed: ${error}`);
169
+ }
170
+ };
171
+
172
+ // Action: Show recent commits
173
+ globalThis.git_log = async function (): Promise<void> {
174
+ editor.setStatus("Fetching recent commits...");
175
+
176
+ try {
177
+ const result = await editor.spawnProcess("git", [
178
+ "log",
179
+ "--oneline",
180
+ "-10", // Last 10 commits
181
+ ]);
182
+
183
+ if (result.exit_code === 0) {
184
+ const lines = result.stdout.trim().split("\n");
185
+ editor.setStatus(`Git: ${lines.length} recent commits`);
186
+ editor.debug(`Recent commits:\n${result.stdout}`);
187
+
188
+ // Show first commit in status
189
+ if (lines.length > 0) {
190
+ editor.setStatus(`Latest: ${lines[0]}`);
191
+ }
192
+ } else {
193
+ editor.setStatus("Git log failed");
194
+ }
195
+ } catch (error) {
196
+ editor.setStatus(`Git log failed: ${error}`);
197
+ }
198
+ };
199
+
200
+ // Register commands on plugin load
201
+ editor.registerCommand(
202
+ "Git Grep: Search TODOs",
203
+ "Search for TODO comments in the repository",
204
+ "git_grep_search",
205
+ "normal"
206
+ );
207
+
208
+ editor.registerCommand(
209
+ "Git Grep: Next Result",
210
+ "Jump to next search result",
211
+ "git_grep_next",
212
+ "normal"
213
+ );
214
+
215
+ editor.registerCommand(
216
+ "Git Grep: Previous Result",
217
+ "Jump to previous search result",
218
+ "git_grep_prev",
219
+ "normal"
220
+ );
221
+
222
+ editor.registerCommand(
223
+ "Git: Show Status",
224
+ "Display git status summary",
225
+ "git_status",
226
+ "" // Available in all contexts
227
+ );
228
+
229
+ editor.registerCommand(
230
+ "Git: Show Branch",
231
+ "Display current git branch",
232
+ "git_branch",
233
+ ""
234
+ );
235
+
236
+ editor.registerCommand(
237
+ "Git: Recent Commits",
238
+ "Show recent commit history",
239
+ "git_log",
240
+ ""
241
+ );
242
+
243
+ // Plugin initialized
244
+ editor.setStatus("Git Grep plugin loaded - 6 commands registered");
245
+ editor.debug("Git Grep TypeScript plugin initialized");
246
+
247
+ // Automatically show git branch on load
248
+ (async () => {
249
+ try {
250
+ const result = await editor.spawnProcess("git", [
251
+ "rev-parse",
252
+ "--abbrev-ref",
253
+ "HEAD",
254
+ ]);
255
+ if (result.exit_code === 0) {
256
+ const branch = result.stdout.trim();
257
+ editor.setStatus(`Git Grep plugin ready | Branch: ${branch}`);
258
+ }
259
+ } catch {
260
+ // Silently fail if not in a git repo
261
+ }
262
+ })();