@fresh-editor/fresh-editor 0.1.88 → 0.1.93

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.
@@ -1,262 +0,0 @@
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
- })();
@@ -1,184 +0,0 @@
1
- {
2
- "en": {
3
- "cmd.enable": "TODO Highlighter: Enable",
4
- "cmd.enable_desc": "Enable TODO keyword highlighting",
5
- "cmd.disable": "TODO Highlighter: Disable",
6
- "cmd.disable_desc": "Disable TODO keyword highlighting",
7
- "cmd.toggle": "TODO Highlighter: Toggle",
8
- "cmd.toggle_desc": "Toggle TODO keyword highlighting",
9
- "cmd.show_keywords": "TODO Highlighter: Show Keywords",
10
- "cmd.show_keywords_desc": "Show currently tracked keywords",
11
- "status.enabled": "TODO Highlighter: Enabled",
12
- "status.disabled": "TODO Highlighter: Disabled",
13
- "status.loaded": "TODO Highlighter plugin loaded (TypeScript)",
14
- "status.keywords": "TODO Keywords: %{keywords}"
15
- },
16
- "cs": {
17
- "cmd.enable": "TODO zvyraznovac: Povolit",
18
- "cmd.enable_desc": "Povolit zvyraznovani klicovych slov TODO",
19
- "cmd.disable": "TODO zvyraznovac: Zakázat",
20
- "cmd.disable_desc": "Zakazat zvyraznovani klicovych slov TODO",
21
- "cmd.toggle": "TODO zvyraznovac: Prepnout",
22
- "cmd.toggle_desc": "Prepnout zvyraznovani klicovych slov TODO",
23
- "cmd.show_keywords": "TODO zvyraznovac: Zobrazit klicova slova",
24
- "cmd.show_keywords_desc": "Zobrazit aktualne sledovana klicova slova",
25
- "status.enabled": "TODO zvyraznovac: Povolen",
26
- "status.disabled": "TODO zvyraznovac: Zakazan",
27
- "status.loaded": "Plugin TODO zvyraznovace nacten (TypeScript)",
28
- "status.keywords": "TODO klicova slova: %{keywords}"
29
- },
30
- "de": {
31
- "cmd.enable": "TODO-Hervorhebung: Aktivieren",
32
- "cmd.enable_desc": "TODO-Schluesselwort-Hervorhebung aktivieren",
33
- "cmd.disable": "TODO-Hervorhebung: Deaktivieren",
34
- "cmd.disable_desc": "TODO-Schluesselwort-Hervorhebung deaktivieren",
35
- "cmd.toggle": "TODO-Hervorhebung: Umschalten",
36
- "cmd.toggle_desc": "TODO-Schluesselwort-Hervorhebung umschalten",
37
- "cmd.show_keywords": "TODO-Hervorhebung: Schluesselwoerter Anzeigen",
38
- "cmd.show_keywords_desc": "Aktuell verfolgte Schluesselwoerter anzeigen",
39
- "status.enabled": "TODO-Hervorhebung: Aktiviert",
40
- "status.disabled": "TODO-Hervorhebung: Deaktiviert",
41
- "status.loaded": "TODO-Hervorhebung-Plugin geladen (TypeScript)",
42
- "status.keywords": "TODO-Schluesselwoerter: %{keywords}"
43
- },
44
- "es": {
45
- "cmd.enable": "Resaltador TODO: Activar",
46
- "cmd.enable_desc": "Activar resaltado de palabras clave TODO",
47
- "cmd.disable": "Resaltador TODO: Desactivar",
48
- "cmd.disable_desc": "Desactivar resaltado de palabras clave TODO",
49
- "cmd.toggle": "Resaltador TODO: Alternar",
50
- "cmd.toggle_desc": "Alternar resaltado de palabras clave TODO",
51
- "cmd.show_keywords": "Resaltador TODO: Mostrar Palabras Clave",
52
- "cmd.show_keywords_desc": "Mostrar palabras clave rastreadas actualmente",
53
- "status.enabled": "Resaltador TODO: Activado",
54
- "status.disabled": "Resaltador TODO: Desactivado",
55
- "status.loaded": "Plugin Resaltador TODO cargado (TypeScript)",
56
- "status.keywords": "Palabras Clave TODO: %{keywords}"
57
- },
58
- "fr": {
59
- "cmd.enable": "Surligneur TODO: Activer",
60
- "cmd.enable_desc": "Activer le surlignage des mots-cles TODO",
61
- "cmd.disable": "Surligneur TODO: Desactiver",
62
- "cmd.disable_desc": "Desactiver le surlignage des mots-cles TODO",
63
- "cmd.toggle": "Surligneur TODO: Basculer",
64
- "cmd.toggle_desc": "Basculer le surlignage des mots-cles TODO",
65
- "cmd.show_keywords": "Surligneur TODO: Afficher les Mots-cles",
66
- "cmd.show_keywords_desc": "Afficher les mots-cles actuellement suivis",
67
- "status.enabled": "Surligneur TODO: Active",
68
- "status.disabled": "Surligneur TODO: Desactive",
69
- "status.loaded": "Plugin Surligneur TODO charge (TypeScript)",
70
- "status.keywords": "Mots-cles TODO: %{keywords}"
71
- },
72
- "it": {
73
- "cmd.enable": "Evidenziatore TODO: Attiva",
74
- "cmd.enable_desc": "Attiva l'evidenziazione delle parole chiave TODO",
75
- "cmd.disable": "Evidenziatore TODO: Disattiva",
76
- "cmd.disable_desc": "Disattiva l'evidenziazione delle parole chiave TODO",
77
- "cmd.toggle": "Evidenziatore TODO: Alterna",
78
- "cmd.toggle_desc": "Alterna l'evidenziazione delle parole chiave TODO",
79
- "cmd.show_keywords": "Evidenziatore TODO: Mostra parole chiave",
80
- "cmd.show_keywords_desc": "Mostra le parole chiave attualmente monitorate",
81
- "status.enabled": "Evidenziatore TODO: Attivato",
82
- "status.disabled": "Evidenziatore TODO: Disattivato",
83
- "status.loaded": "Plugin Evidenziatore TODO caricato (TypeScript)",
84
- "status.keywords": "Parole chiave TODO: %{keywords}"
85
- },
86
- "ja": {
87
- "cmd.enable": "TODOハイライター: 有効化",
88
- "cmd.enable_desc": "TODOキーワードのハイライトを有効化",
89
- "cmd.disable": "TODOハイライター: 無効化",
90
- "cmd.disable_desc": "TODOキーワードのハイライトを無効化",
91
- "cmd.toggle": "TODOハイライター: 切り替え",
92
- "cmd.toggle_desc": "TODOキーワードのハイライトを切り替え",
93
- "cmd.show_keywords": "TODOハイライター: キーワード表示",
94
- "cmd.show_keywords_desc": "現在追跡中のキーワードを表示",
95
- "status.enabled": "TODOハイライター: 有効",
96
- "status.disabled": "TODOハイライター: 無効",
97
- "status.loaded": "TODOハイライタープラグインを読み込みました (TypeScript)",
98
- "status.keywords": "TODOキーワード: %{keywords}"
99
- },
100
- "ko": {
101
- "cmd.enable": "TODO 하이라이터: 활성화",
102
- "cmd.enable_desc": "TODO 키워드 강조 표시 활성화",
103
- "cmd.disable": "TODO 하이라이터: 비활성화",
104
- "cmd.disable_desc": "TODO 키워드 강조 표시 비활성화",
105
- "cmd.toggle": "TODO 하이라이터: 전환",
106
- "cmd.toggle_desc": "TODO 키워드 강조 표시 전환",
107
- "cmd.show_keywords": "TODO 하이라이터: 키워드 표시",
108
- "cmd.show_keywords_desc": "현재 추적 중인 키워드 표시",
109
- "status.enabled": "TODO 하이라이터: 활성화됨",
110
- "status.disabled": "TODO 하이라이터: 비활성화됨",
111
- "status.loaded": "TODO 하이라이터 플러그인 로드됨 (TypeScript)",
112
- "status.keywords": "TODO 키워드: %{keywords}"
113
- },
114
- "pt-BR": {
115
- "cmd.enable": "Realcador TODO: Ativar",
116
- "cmd.enable_desc": "Ativar realce de palavras-chave TODO",
117
- "cmd.disable": "Realcador TODO: Desativar",
118
- "cmd.disable_desc": "Desativar realce de palavras-chave TODO",
119
- "cmd.toggle": "Realcador TODO: Alternar",
120
- "cmd.toggle_desc": "Alternar realce de palavras-chave TODO",
121
- "cmd.show_keywords": "Realcador TODO: Mostrar Palavras-chave",
122
- "cmd.show_keywords_desc": "Mostrar palavras-chave atualmente rastreadas",
123
- "status.enabled": "Realcador TODO: Ativado",
124
- "status.disabled": "Realcador TODO: Desativado",
125
- "status.loaded": "Plugin Realcador TODO carregado (TypeScript)",
126
- "status.keywords": "Palavras-chave TODO: %{keywords}"
127
- },
128
- "ru": {
129
- "cmd.enable": "Подсветка TODO: Включить",
130
- "cmd.enable_desc": "Включить подсветку ключевых слов TODO",
131
- "cmd.disable": "Подсветка TODO: Выключить",
132
- "cmd.disable_desc": "Выключить подсветку ключевых слов TODO",
133
- "cmd.toggle": "Подсветка TODO: Переключить",
134
- "cmd.toggle_desc": "Переключить подсветку ключевых слов TODO",
135
- "cmd.show_keywords": "Подсветка TODO: Показать ключевые слова",
136
- "cmd.show_keywords_desc": "Показать текущие отслеживаемые ключевые слова",
137
- "status.enabled": "Подсветка TODO: Включена",
138
- "status.disabled": "Подсветка TODO: Выключена",
139
- "status.loaded": "Плагин подсветки TODO загружен (TypeScript)",
140
- "status.keywords": "Ключевые слова TODO: %{keywords}"
141
- },
142
- "th": {
143
- "cmd.enable": "ตัวเน้น TODO: เปิดใช้งาน",
144
- "cmd.enable_desc": "เปิดใช้งานการเน้นคำสำคัญ TODO",
145
- "cmd.disable": "ตัวเน้น TODO: ปิดใช้งาน",
146
- "cmd.disable_desc": "ปิดใช้งานการเน้นคำสำคัญ TODO",
147
- "cmd.toggle": "ตัวเน้น TODO: สลับ",
148
- "cmd.toggle_desc": "สลับการเน้นคำสำคัญ TODO",
149
- "cmd.show_keywords": "ตัวเน้น TODO: แสดงคำสำคัญ",
150
- "cmd.show_keywords_desc": "แสดงคำสำคัญที่กำลังติดตาม",
151
- "status.enabled": "ตัวเน้น TODO: เปิดใช้งานแล้ว",
152
- "status.disabled": "ตัวเน้น TODO: ปิดใช้งานแล้ว",
153
- "status.loaded": "โหลดปลั๊กอินตัวเน้น TODO แล้ว (TypeScript)",
154
- "status.keywords": "คำสำคัญ TODO: %{keywords}"
155
- },
156
- "uk": {
157
- "cmd.enable": "Підсвічування TODO: Увімкнути",
158
- "cmd.enable_desc": "Увімкнути підсвічування ключових слів TODO",
159
- "cmd.disable": "Підсвічування TODO: Вимкнути",
160
- "cmd.disable_desc": "Вимкнути підсвічування ключових слів TODO",
161
- "cmd.toggle": "Підсвічування TODO: Перемкнути",
162
- "cmd.toggle_desc": "Перемкнути підсвічування ключових слів TODO",
163
- "cmd.show_keywords": "Підсвічування TODO: Показати ключові слова",
164
- "cmd.show_keywords_desc": "Показати поточні відстежувані ключові слова",
165
- "status.enabled": "Підсвічування TODO: Увімкнено",
166
- "status.disabled": "Підсвічування TODO: Вимкнено",
167
- "status.loaded": "Плагін підсвічування TODO завантажено (TypeScript)",
168
- "status.keywords": "Ключові слова TODO: %{keywords}"
169
- },
170
- "zh-CN": {
171
- "cmd.enable": "TODO高亮器: 启用",
172
- "cmd.enable_desc": "启用TODO关键字高亮显示",
173
- "cmd.disable": "TODO高亮器: 禁用",
174
- "cmd.disable_desc": "禁用TODO关键字高亮显示",
175
- "cmd.toggle": "TODO高亮器: 切换",
176
- "cmd.toggle_desc": "切换TODO关键字高亮显示",
177
- "cmd.show_keywords": "TODO高亮器: 显示关键字",
178
- "cmd.show_keywords_desc": "显示当前跟踪的关键字",
179
- "status.enabled": "TODO高亮器: 已启用",
180
- "status.disabled": "TODO高亮器: 已禁用",
181
- "status.loaded": "TODO高亮器插件已加载 (TypeScript)",
182
- "status.keywords": "TODO关键字: %{keywords}"
183
- }
184
- }
@@ -1,206 +0,0 @@
1
- /// <reference path="./lib/fresh.d.ts" />
2
- // TypeScript TODO Highlighter Plugin
3
- // Highlights TODO, FIXME, XXX keywords in source code
4
- // Uses targeted overlay invalidation for efficient updates on edits
5
- const editor = getEditor();
6
-
7
-
8
- interface HighlightConfig {
9
- enabled: boolean;
10
- keywords: Array<{
11
- word: string;
12
- color: [number, number, number];
13
- }>;
14
- }
15
-
16
- // Plugin configuration
17
- const config: HighlightConfig = {
18
- enabled: false, // Start disabled, use Enable or Toggle to activate
19
- keywords: [
20
- { word: "TODO", color: [255, 200, 50] }, // Yellow
21
- { word: "FIXME", color: [255, 100, 100] }, // Red
22
- { word: "XXX", color: [255, 150, 50] }, // Orange
23
- { word: "HACK", color: [200, 100, 255] }, // Purple
24
- { word: "NOTE", color: [100, 200, 255] }, // Blue
25
- ],
26
- };
27
-
28
- // Namespace for all TODO highlighter overlays
29
- const NAMESPACE = "todo";
30
-
31
- // Process a single line for keyword highlighting
32
- function highlightLine(
33
- bufferId: number,
34
- byteStart: number,
35
- content: string
36
- ): void {
37
- // Search for keywords
38
- for (const keyword of config.keywords) {
39
- let searchStart = 0;
40
- while (true) {
41
- const pos = content.indexOf(keyword.word, searchStart);
42
- if (pos === -1) break;
43
-
44
- // Check if it's a whole word (preceded by non-word char or start)
45
- const isWordStart = pos === 0 || !/\w/.test(content[pos - 1]);
46
- const isWordEnd = pos + keyword.word.length >= content.length ||
47
- !/\w/.test(content[pos + keyword.word.length]);
48
-
49
- if (isWordStart && isWordEnd) {
50
- const absoluteStart = byteStart + pos;
51
- const absoluteEnd = absoluteStart + keyword.word.length;
52
-
53
- // Add overlay with namespace for efficient batch removal
54
- editor.addOverlay(
55
- bufferId,
56
- NAMESPACE,
57
- absoluteStart,
58
- absoluteEnd,
59
- keyword.color[0],
60
- keyword.color[1],
61
- keyword.color[2],
62
- false // background color, not underline
63
- );
64
- }
65
-
66
- searchStart = pos + 1;
67
- }
68
- }
69
- }
70
-
71
- // Clear highlights for a buffer using namespace
72
- function clearHighlights(bufferId: number): void {
73
- editor.clearNamespace(bufferId, NAMESPACE);
74
- }
75
-
76
- // Handle lines_changed events (batched for efficiency)
77
- // This is called for lines that need (re)processing
78
- globalThis.onLinesChanged = function(data: {
79
- buffer_id: number;
80
- lines: Array<{
81
- line_number: number;
82
- byte_start: number;
83
- byte_end: number;
84
- content: string;
85
- }>;
86
- }): void {
87
- if (!config.enabled) return;
88
-
89
- // Process all changed lines and create overlays for them
90
- for (const line of data.lines) {
91
- highlightLine(data.buffer_id, line.byte_start, line.content);
92
- }
93
- };
94
-
95
- // Handle buffer content changes - clear only affected overlays
96
- // The editor will automatically re-send the affected lines via lines_changed
97
- globalThis.onAfterInsert = function(data: {
98
- buffer_id: number;
99
- position: number;
100
- text: string;
101
- affected_start: number;
102
- affected_end: number;
103
- }): void {
104
- if (!config.enabled) return;
105
-
106
- // Clear only overlays that overlap with the insertion range
107
- // These overlays may now span corrupted content (e.g., "TODO" -> "TOxDO")
108
- // The affected lines will be re-sent via lines_changed with correct content
109
- editor.clearOverlaysInRange(data.buffer_id, data.affected_start, data.affected_end);
110
- };
111
-
112
- globalThis.onAfterDelete = function(data: {
113
- buffer_id: number;
114
- start: number;
115
- end: number;
116
- deleted_text: string;
117
- affected_start: number;
118
- deleted_len: number;
119
- }): void {
120
- if (!config.enabled) return;
121
-
122
- // Clear overlays that overlapped with the deleted range
123
- // Overlays that were entirely within the deleted range are already gone
124
- // (their markers were deleted), but overlays that spanned the deletion
125
- // boundary may now be incorrect
126
- // Use a slightly expanded range to catch boundary cases
127
- const clearStart = data.affected_start > 0 ? data.affected_start - 1 : 0;
128
- const clearEnd = data.affected_start + 1;
129
- editor.clearOverlaysInRange(data.buffer_id, clearStart, clearEnd);
130
- };
131
-
132
- // Handle buffer close events
133
- globalThis.onBufferClosed = function(data: { buffer_id: number }): void {
134
- // No cleanup needed - overlays are automatically cleaned up with the buffer
135
- };
136
-
137
- // Register hooks
138
- editor.on("lines_changed", "onLinesChanged");
139
- editor.on("after_insert", "onAfterInsert");
140
- editor.on("after_delete", "onAfterDelete");
141
- editor.on("buffer_closed", "onBufferClosed");
142
-
143
- // Plugin commands
144
- globalThis.todoHighlighterEnable = function(): void {
145
- config.enabled = true;
146
- // Refresh lines so next render processes all visible lines
147
- const bufferId = editor.getActiveBufferId();
148
- editor.refreshLines(bufferId);
149
- editor.setStatus(editor.t("status.enabled"));
150
- };
151
-
152
- globalThis.todoHighlighterDisable = function(): void {
153
- config.enabled = false;
154
- const bufferId = editor.getActiveBufferId();
155
- clearHighlights(bufferId);
156
- editor.setStatus(editor.t("status.disabled"));
157
- };
158
-
159
- globalThis.todoHighlighterToggle = function(): void {
160
- config.enabled = !config.enabled;
161
- const bufferId = editor.getActiveBufferId();
162
- if (config.enabled) {
163
- // Refresh lines so next render processes all visible lines
164
- editor.refreshLines(bufferId);
165
- } else {
166
- clearHighlights(bufferId);
167
- }
168
- editor.setStatus(config.enabled ? editor.t("status.enabled") : editor.t("status.disabled"));
169
- };
170
-
171
- globalThis.todoHighlighterShowKeywords = function(): void {
172
- const keywords = config.keywords.map(k => k.word).join(", ");
173
- editor.setStatus(editor.t("status.keywords", { keywords }));
174
- };
175
-
176
- // Register commands
177
- editor.registerCommand(
178
- "%cmd.enable",
179
- "%cmd.enable_desc",
180
- "todoHighlighterEnable",
181
- "normal"
182
- );
183
-
184
- editor.registerCommand(
185
- "%cmd.disable",
186
- "%cmd.disable_desc",
187
- "todoHighlighterDisable",
188
- "normal"
189
- );
190
-
191
- editor.registerCommand(
192
- "%cmd.toggle",
193
- "%cmd.toggle_desc",
194
- "todoHighlighterToggle",
195
- "normal"
196
- );
197
-
198
- editor.registerCommand(
199
- "%cmd.show_keywords",
200
- "%cmd.show_keywords_desc",
201
- "todoHighlighterShowKeywords",
202
- "normal"
203
- );
204
-
205
- // Initialization
206
- editor.debug("TODO Highlighter initialized with keywords: " + config.keywords.map(k => k.word).join(", "));