@fresh-editor/fresh-editor 0.1.86 → 0.1.87
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 +19 -0
- package/README.md +4 -0
- package/package.json +1 -1
- package/plugins/README.md +1 -0
- package/plugins/audit_mode.ts +38 -34
- package/plugins/calculator.ts +6 -6
- package/plugins/examples/virtual_buffer_demo.ts +4 -4
- package/plugins/git_blame.ts +3 -3
- package/plugins/git_explorer.ts +3 -2
- package/plugins/git_log.ts +10 -10
- package/plugins/java-lsp.ts +65 -0
- package/plugins/latex-lsp.ts +65 -0
- package/plugins/lib/finder.ts +32 -32
- package/plugins/lib/fresh.d.ts +430 -18
- package/plugins/lib/panel-manager.ts +7 -7
- package/plugins/lib/search-utils.ts +13 -13
- package/plugins/lib/virtual-buffer-factory.ts +16 -14
- package/plugins/markdown_compose.ts +4 -4
- package/plugins/marksman-lsp.ts +65 -0
- package/plugins/merge_conflict.ts +21 -21
- package/plugins/search_replace.ts +6 -6
- package/plugins/templ-lsp.ts +65 -0
- package/plugins/theme_editor.ts +6 -5
- package/plugins/vi_mode.ts +2 -2
- package/plugins/zig-lsp.ts +65 -0
|
@@ -110,20 +110,20 @@ export class PanelManager {
|
|
|
110
110
|
const result = await this.editor.createVirtualBufferInSplit({
|
|
111
111
|
name: this.panelName,
|
|
112
112
|
mode: this.modeName,
|
|
113
|
-
|
|
113
|
+
readOnly: true,
|
|
114
114
|
entries,
|
|
115
115
|
ratio,
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
116
|
+
panelId: this.panelName,
|
|
117
|
+
showLineNumbers: showLineNumbers,
|
|
118
|
+
editingDisabled: editingDisabled,
|
|
119
119
|
});
|
|
120
120
|
|
|
121
121
|
// Track state
|
|
122
|
-
this.state.bufferId = result.
|
|
123
|
-
this.state.splitId = result.
|
|
122
|
+
this.state.bufferId = result.bufferId;
|
|
123
|
+
this.state.splitId = result.splitId ?? this.editor.getActiveSplitId();
|
|
124
124
|
this.state.isOpen = true;
|
|
125
125
|
|
|
126
|
-
return result.
|
|
126
|
+
return result.bufferId;
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
/**
|
|
@@ -41,14 +41,14 @@ interface EditorApi {
|
|
|
41
41
|
createVirtualBufferInSplit(options: {
|
|
42
42
|
name: string;
|
|
43
43
|
mode: string;
|
|
44
|
-
|
|
44
|
+
readOnly: boolean;
|
|
45
45
|
entries: TextPropertyEntry[];
|
|
46
46
|
ratio: number;
|
|
47
47
|
direction: string;
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}): Promise<{
|
|
48
|
+
panelId: string;
|
|
49
|
+
showLineNumbers: boolean;
|
|
50
|
+
editingDisabled: boolean;
|
|
51
|
+
}): Promise<{ bufferId: number; splitId?: number }>;
|
|
52
52
|
setVirtualBufferContent(bufferId: number, entries: TextPropertyEntry[]): void;
|
|
53
53
|
closeBuffer(bufferId: number): void;
|
|
54
54
|
closeSplit(splitId: number): void;
|
|
@@ -137,17 +137,17 @@ export class SearchPreview {
|
|
|
137
137
|
const result = await this.editor.createVirtualBufferInSplit({
|
|
138
138
|
name: "*Preview*",
|
|
139
139
|
mode: this.modeName,
|
|
140
|
-
|
|
140
|
+
readOnly: true,
|
|
141
141
|
entries,
|
|
142
142
|
ratio: 0.5,
|
|
143
143
|
direction: "vertical",
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
144
|
+
panelId: this.panelId,
|
|
145
|
+
showLineNumbers: false,
|
|
146
|
+
editingDisabled: true,
|
|
147
147
|
});
|
|
148
148
|
|
|
149
|
-
this.bufferId = result.
|
|
150
|
-
this.splitId = result.
|
|
149
|
+
this.bufferId = result.bufferId;
|
|
150
|
+
this.splitId = result.splitId ?? null;
|
|
151
151
|
|
|
152
152
|
// Return focus to original split so prompt stays active
|
|
153
153
|
if (this.originalSplitId !== null) {
|
|
@@ -196,7 +196,7 @@ export class SearchPreview {
|
|
|
196
196
|
* - Tracks search version to discard stale results
|
|
197
197
|
*/
|
|
198
198
|
export class DebouncedSearch {
|
|
199
|
-
private currentSearch: ProcessHandle | null = null;
|
|
199
|
+
private currentSearch: ProcessHandle<SpawnResult> | null = null;
|
|
200
200
|
private pendingKill: Promise<boolean> | null = null;
|
|
201
201
|
private searchVersion = 0;
|
|
202
202
|
private lastQuery = "";
|
|
@@ -216,7 +216,7 @@ export class DebouncedSearch {
|
|
|
216
216
|
*/
|
|
217
217
|
async search(
|
|
218
218
|
query: string,
|
|
219
|
-
executor: () => ProcessHandle
|
|
219
|
+
executor: () => ProcessHandle<SpawnResult>,
|
|
220
220
|
onResults: (result: SpawnResult) => void
|
|
221
221
|
): Promise<void> {
|
|
222
222
|
const thisVersion = ++this.searchVersion;
|
|
@@ -59,14 +59,15 @@ export function createVirtualBufferFactory(editor: EditorAPI) {
|
|
|
59
59
|
readOnly = true,
|
|
60
60
|
} = options;
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
const result = await editor.createVirtualBuffer({
|
|
63
63
|
name,
|
|
64
64
|
mode,
|
|
65
|
-
|
|
65
|
+
readOnly,
|
|
66
66
|
entries,
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
showLineNumbers,
|
|
68
|
+
editingDisabled,
|
|
69
69
|
});
|
|
70
|
+
return result.bufferId;
|
|
70
71
|
},
|
|
71
72
|
|
|
72
73
|
/**
|
|
@@ -82,15 +83,16 @@ export function createVirtualBufferFactory(editor: EditorAPI) {
|
|
|
82
83
|
readOnly = true,
|
|
83
84
|
} = options;
|
|
84
85
|
|
|
85
|
-
|
|
86
|
+
const result = await editor.createVirtualBufferInExistingSplit({
|
|
86
87
|
name,
|
|
87
88
|
mode,
|
|
88
|
-
|
|
89
|
+
readOnly,
|
|
89
90
|
entries,
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
splitId,
|
|
92
|
+
showLineNumbers,
|
|
93
|
+
editingDisabled,
|
|
93
94
|
});
|
|
95
|
+
return result.bufferId;
|
|
94
96
|
},
|
|
95
97
|
|
|
96
98
|
/**
|
|
@@ -111,14 +113,14 @@ export function createVirtualBufferFactory(editor: EditorAPI) {
|
|
|
111
113
|
const result = await editor.createVirtualBufferInSplit({
|
|
112
114
|
name,
|
|
113
115
|
mode,
|
|
114
|
-
|
|
116
|
+
readOnly,
|
|
115
117
|
entries,
|
|
116
118
|
ratio,
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
119
|
+
panelId,
|
|
120
|
+
showLineNumbers,
|
|
121
|
+
editingDisabled,
|
|
120
122
|
});
|
|
121
|
-
return result.
|
|
123
|
+
return result.bufferId;
|
|
122
124
|
},
|
|
123
125
|
|
|
124
126
|
/**
|
|
@@ -334,7 +334,7 @@ function disableMarkdownCompose(bufferId: number): void {
|
|
|
334
334
|
editor.setLineNumbers(bufferId, true);
|
|
335
335
|
|
|
336
336
|
// Clear view transform to return to normal rendering
|
|
337
|
-
editor.clearViewTransform(bufferId);
|
|
337
|
+
editor.clearViewTransform(bufferId, null);
|
|
338
338
|
|
|
339
339
|
editor.refreshLines(bufferId);
|
|
340
340
|
editor.debug(`Markdown compose disabled for buffer ${bufferId}`);
|
|
@@ -535,10 +535,10 @@ globalThis.onMarkdownViewTransform = function(data: {
|
|
|
535
535
|
data.viewport_start
|
|
536
536
|
);
|
|
537
537
|
|
|
538
|
-
// Submit the transformed tokens - keep
|
|
538
|
+
// Submit the transformed tokens - keep composeWidth for margins/centering
|
|
539
539
|
const layoutHints: LayoutHints = {
|
|
540
|
-
|
|
541
|
-
|
|
540
|
+
composeWidth: config.composeWidth,
|
|
541
|
+
columnGuides: null,
|
|
542
542
|
};
|
|
543
543
|
|
|
544
544
|
editor.submitViewTransform(
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/// <reference path="./lib/fresh.d.ts" />
|
|
2
|
+
// Provides installation help when marksman (Markdown LSP) is not found
|
|
3
|
+
const editor = getEditor();
|
|
4
|
+
|
|
5
|
+
interface LspServerErrorData {
|
|
6
|
+
language: string;
|
|
7
|
+
server_command: string;
|
|
8
|
+
error_type: string;
|
|
9
|
+
message: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface LspStatusClickedData {
|
|
13
|
+
language: string;
|
|
14
|
+
has_error: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface ActionPopupResultData {
|
|
18
|
+
popup_id: string;
|
|
19
|
+
action_id: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const INSTALL_URL = "https://github.com/artempyanykh/marksman#how-to-install";
|
|
23
|
+
let markdownLspError: { serverCommand: string; message: string } | null = null;
|
|
24
|
+
|
|
25
|
+
globalThis.on_markdown_lsp_server_error = function (data: LspServerErrorData): void {
|
|
26
|
+
if (data.language !== "markdown") return;
|
|
27
|
+
markdownLspError = { serverCommand: data.server_command, message: data.message };
|
|
28
|
+
if (data.error_type === "not_found") {
|
|
29
|
+
editor.setStatus(`Markdown LSP '${data.server_command}' not found. Click status bar for help.`);
|
|
30
|
+
} else {
|
|
31
|
+
editor.setStatus(`Markdown LSP error: ${data.message}`);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
editor.on("lsp_server_error", "on_markdown_lsp_server_error");
|
|
35
|
+
|
|
36
|
+
globalThis.on_markdown_lsp_status_clicked = function (data: LspStatusClickedData): void {
|
|
37
|
+
if (data.language !== "markdown" || !markdownLspError) return;
|
|
38
|
+
editor.showActionPopup({
|
|
39
|
+
id: "marksman-lsp-help",
|
|
40
|
+
title: "Markdown Language Server Not Found",
|
|
41
|
+
message: `Install marksman for wiki-links and navigation. Visit ${INSTALL_URL}`,
|
|
42
|
+
actions: [
|
|
43
|
+
{ id: "copy_url", label: "Copy install URL" },
|
|
44
|
+
{ id: "disable", label: "Disable Markdown LSP" },
|
|
45
|
+
{ id: "dismiss", label: "Dismiss (ESC)" },
|
|
46
|
+
],
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
editor.on("lsp_status_clicked", "on_markdown_lsp_status_clicked");
|
|
50
|
+
|
|
51
|
+
globalThis.on_markdown_lsp_action_result = function (data: ActionPopupResultData): void {
|
|
52
|
+
if (data.popup_id !== "marksman-lsp-help") return;
|
|
53
|
+
switch (data.action_id) {
|
|
54
|
+
case "copy_url":
|
|
55
|
+
editor.setClipboard(INSTALL_URL);
|
|
56
|
+
editor.setStatus("Copied: " + INSTALL_URL);
|
|
57
|
+
break;
|
|
58
|
+
case "disable":
|
|
59
|
+
editor.disableLspForLanguage("markdown");
|
|
60
|
+
editor.setStatus("Markdown LSP disabled");
|
|
61
|
+
markdownLspError = null;
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
editor.on("action_popup_result", "on_markdown_lsp_action_result");
|
|
@@ -1335,18 +1335,18 @@ async function createMergePanels(): Promise<void> {
|
|
|
1335
1335
|
|
|
1336
1336
|
// Create OURS panel first (takes over current view)
|
|
1337
1337
|
// Include extension in name so tree-sitter can apply highlighting
|
|
1338
|
-
const
|
|
1338
|
+
const oursResult = await editor.createVirtualBuffer({
|
|
1339
1339
|
name: `*OURS*${sourceExt}`,
|
|
1340
1340
|
mode: "merge-conflict",
|
|
1341
|
-
|
|
1341
|
+
readOnly: true,
|
|
1342
1342
|
entries: buildFullFileEntries("ours"),
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1343
|
+
showLineNumbers: true,
|
|
1344
|
+
showCursors: true,
|
|
1345
|
+
editingDisabled: true,
|
|
1346
1346
|
});
|
|
1347
1347
|
|
|
1348
|
-
if (
|
|
1349
|
-
mergeState.oursPanelId =
|
|
1348
|
+
if (oursResult !== null) {
|
|
1349
|
+
mergeState.oursPanelId = oursResult.bufferId;
|
|
1350
1350
|
mergeState.oursSplitId = editor.getActiveSplitId();
|
|
1351
1351
|
}
|
|
1352
1352
|
|
|
@@ -1354,19 +1354,19 @@ async function createMergePanels(): Promise<void> {
|
|
|
1354
1354
|
const theirsResult = await editor.createVirtualBufferInSplit({
|
|
1355
1355
|
name: `*THEIRS*${sourceExt}`,
|
|
1356
1356
|
mode: "merge-conflict",
|
|
1357
|
-
|
|
1357
|
+
readOnly: true,
|
|
1358
1358
|
entries: buildFullFileEntries("theirs"),
|
|
1359
1359
|
ratio: 0.5, // Will be equalized by distributeSplitsEvenly
|
|
1360
1360
|
direction: "vertical",
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1361
|
+
panelId: "merge-theirs",
|
|
1362
|
+
showLineNumbers: true,
|
|
1363
|
+
showCursors: true,
|
|
1364
|
+
editingDisabled: true,
|
|
1365
1365
|
});
|
|
1366
1366
|
|
|
1367
1367
|
if (theirsResult !== null) {
|
|
1368
|
-
mergeState.theirsPanelId = theirsResult.
|
|
1369
|
-
mergeState.theirsSplitId = theirsResult.
|
|
1368
|
+
mergeState.theirsPanelId = theirsResult.bufferId;
|
|
1369
|
+
mergeState.theirsSplitId = theirsResult.splitId ?? editor.getActiveSplitId();
|
|
1370
1370
|
}
|
|
1371
1371
|
|
|
1372
1372
|
// Focus back on OURS and create RESULT in the middle
|
|
@@ -1377,19 +1377,19 @@ async function createMergePanels(): Promise<void> {
|
|
|
1377
1377
|
const resultResult = await editor.createVirtualBufferInSplit({
|
|
1378
1378
|
name: `*RESULT*${sourceExt}`,
|
|
1379
1379
|
mode: "merge-result",
|
|
1380
|
-
|
|
1380
|
+
readOnly: false,
|
|
1381
1381
|
entries: buildResultFileEntries(),
|
|
1382
1382
|
ratio: 0.5, // Will be equalized by distributeSplitsEvenly
|
|
1383
1383
|
direction: "vertical",
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1384
|
+
panelId: "merge-result",
|
|
1385
|
+
showLineNumbers: true,
|
|
1386
|
+
showCursors: true,
|
|
1387
|
+
editingDisabled: false,
|
|
1388
1388
|
});
|
|
1389
1389
|
|
|
1390
1390
|
if (resultResult !== null) {
|
|
1391
|
-
mergeState.resultPanelId = resultResult.
|
|
1392
|
-
mergeState.resultSplitId = resultResult.
|
|
1391
|
+
mergeState.resultPanelId = resultResult.bufferId;
|
|
1392
|
+
mergeState.resultSplitId = resultResult.splitId ?? editor.getActiveSplitId();
|
|
1393
1393
|
}
|
|
1394
1394
|
|
|
1395
1395
|
// Distribute splits evenly so all three panels get equal width
|
|
@@ -229,15 +229,15 @@ async function showResultsPanel(): Promise<void> {
|
|
|
229
229
|
const result = await editor.createVirtualBufferInSplit({
|
|
230
230
|
name: "*Search/Replace*",
|
|
231
231
|
mode: "search-replace-list",
|
|
232
|
-
|
|
232
|
+
readOnly: true,
|
|
233
233
|
entries: entries,
|
|
234
234
|
ratio: 0.6, // 60/40 split
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
235
|
+
panelId: "search-replace-panel",
|
|
236
|
+
showLineNumbers: false,
|
|
237
|
+
showCursors: true,
|
|
238
238
|
});
|
|
239
|
-
resultsBufferId = result.
|
|
240
|
-
resultsSplitId = result.
|
|
239
|
+
resultsBufferId = result.bufferId;
|
|
240
|
+
resultsSplitId = result.splitId ?? editor.getActiveSplitId();
|
|
241
241
|
|
|
242
242
|
panelOpen = true;
|
|
243
243
|
editor.debug(`Search/Replace panel opened with buffer ID ${resultsBufferId}`);
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/// <reference path="./lib/fresh.d.ts" />
|
|
2
|
+
// Provides installation help when templ LSP is not found
|
|
3
|
+
const editor = getEditor();
|
|
4
|
+
|
|
5
|
+
interface LspServerErrorData {
|
|
6
|
+
language: string;
|
|
7
|
+
server_command: string;
|
|
8
|
+
error_type: string;
|
|
9
|
+
message: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface LspStatusClickedData {
|
|
13
|
+
language: string;
|
|
14
|
+
has_error: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface ActionPopupResultData {
|
|
18
|
+
popup_id: string;
|
|
19
|
+
action_id: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const INSTALL_URL = "https://templ.guide/quick-start/installation";
|
|
23
|
+
let templLspError: { serverCommand: string; message: string } | null = null;
|
|
24
|
+
|
|
25
|
+
globalThis.on_templ_lsp_server_error = function (data: LspServerErrorData): void {
|
|
26
|
+
if (data.language !== "templ") return;
|
|
27
|
+
templLspError = { serverCommand: data.server_command, message: data.message };
|
|
28
|
+
if (data.error_type === "not_found") {
|
|
29
|
+
editor.setStatus(`Templ LSP '${data.server_command}' not found. Click status bar for help.`);
|
|
30
|
+
} else {
|
|
31
|
+
editor.setStatus(`Templ LSP error: ${data.message}`);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
editor.on("lsp_server_error", "on_templ_lsp_server_error");
|
|
35
|
+
|
|
36
|
+
globalThis.on_templ_lsp_status_clicked = function (data: LspStatusClickedData): void {
|
|
37
|
+
if (data.language !== "templ" || !templLspError) return;
|
|
38
|
+
editor.showActionPopup({
|
|
39
|
+
id: "templ-lsp-help",
|
|
40
|
+
title: "Templ Language Server Not Found",
|
|
41
|
+
message: `Install templ for code completion and diagnostics. Visit ${INSTALL_URL}`,
|
|
42
|
+
actions: [
|
|
43
|
+
{ id: "copy_url", label: "Copy install URL" },
|
|
44
|
+
{ id: "disable", label: "Disable Templ LSP" },
|
|
45
|
+
{ id: "dismiss", label: "Dismiss (ESC)" },
|
|
46
|
+
],
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
editor.on("lsp_status_clicked", "on_templ_lsp_status_clicked");
|
|
50
|
+
|
|
51
|
+
globalThis.on_templ_lsp_action_result = function (data: ActionPopupResultData): void {
|
|
52
|
+
if (data.popup_id !== "templ-lsp-help") return;
|
|
53
|
+
switch (data.action_id) {
|
|
54
|
+
case "copy_url":
|
|
55
|
+
editor.setClipboard(INSTALL_URL);
|
|
56
|
+
editor.setStatus("Copied: " + INSTALL_URL);
|
|
57
|
+
break;
|
|
58
|
+
case "disable":
|
|
59
|
+
editor.disableLspForLanguage("templ");
|
|
60
|
+
editor.setStatus("Templ LSP disabled");
|
|
61
|
+
templLspError = null;
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
editor.on("action_popup_result", "on_templ_lsp_action_result");
|
package/plugins/theme_editor.ts
CHANGED
|
@@ -1734,15 +1734,16 @@ async function doOpenThemeEditor(): Promise<void> {
|
|
|
1734
1734
|
|
|
1735
1735
|
// Create virtual buffer in current split (no new split)
|
|
1736
1736
|
editor.debug("[theme_editor] doOpenThemeEditor: calling createVirtualBuffer...");
|
|
1737
|
-
const
|
|
1737
|
+
const result = await editor.createVirtualBuffer({
|
|
1738
1738
|
name: "*Theme Editor*",
|
|
1739
1739
|
mode: "theme-editor",
|
|
1740
|
-
|
|
1740
|
+
readOnly: true,
|
|
1741
1741
|
entries: entries,
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1742
|
+
showLineNumbers: false,
|
|
1743
|
+
showCursors: true,
|
|
1744
|
+
editingDisabled: true,
|
|
1745
1745
|
});
|
|
1746
|
+
const bufferId = result.bufferId;
|
|
1746
1747
|
editor.debug(`[theme_editor] doOpenThemeEditor: createVirtualBuffer returned bufferId=${bufferId}`);
|
|
1747
1748
|
editor.debug(`[theme_editor] doOpenThemeEditor: checking if bufferId !== null...`);
|
|
1748
1749
|
|
package/plugins/vi_mode.ts
CHANGED
|
@@ -795,7 +795,7 @@ globalThis.vi_visual_toggle_line = function (): void {
|
|
|
795
795
|
};
|
|
796
796
|
|
|
797
797
|
// Enter visual block mode (Ctrl-v)
|
|
798
|
-
globalThis.vi_visual_block = function (): void {
|
|
798
|
+
globalThis.vi_visual_block = async function (): Promise<void> {
|
|
799
799
|
// Store anchor position for block selection
|
|
800
800
|
state.visualAnchor = editor.getCursorPosition();
|
|
801
801
|
|
|
@@ -803,7 +803,7 @@ globalThis.vi_visual_block = function (): void {
|
|
|
803
803
|
const cursorPos = editor.getCursorPosition();
|
|
804
804
|
if (cursorPos !== null) {
|
|
805
805
|
const line = editor.getCursorLine() ?? 1;
|
|
806
|
-
const lineStart = editor.getLineStartPosition(line);
|
|
806
|
+
const lineStart = await editor.getLineStartPosition(line);
|
|
807
807
|
const col = lineStart !== null ? cursorPos - lineStart : 0;
|
|
808
808
|
state.visualBlockAnchor = { line, col };
|
|
809
809
|
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/// <reference path="./lib/fresh.d.ts" />
|
|
2
|
+
// Provides installation help when zls (Zig LSP) is not found
|
|
3
|
+
const editor = getEditor();
|
|
4
|
+
|
|
5
|
+
interface LspServerErrorData {
|
|
6
|
+
language: string;
|
|
7
|
+
server_command: string;
|
|
8
|
+
error_type: string;
|
|
9
|
+
message: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface LspStatusClickedData {
|
|
13
|
+
language: string;
|
|
14
|
+
has_error: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface ActionPopupResultData {
|
|
18
|
+
popup_id: string;
|
|
19
|
+
action_id: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const INSTALL_URL = "https://github.com/zigtools/zls#installation";
|
|
23
|
+
let zigLspError: { serverCommand: string; message: string } | null = null;
|
|
24
|
+
|
|
25
|
+
globalThis.on_zig_lsp_server_error = function (data: LspServerErrorData): void {
|
|
26
|
+
if (data.language !== "zig") return;
|
|
27
|
+
zigLspError = { serverCommand: data.server_command, message: data.message };
|
|
28
|
+
if (data.error_type === "not_found") {
|
|
29
|
+
editor.setStatus(`Zig LSP '${data.server_command}' not found. Click status bar for help.`);
|
|
30
|
+
} else {
|
|
31
|
+
editor.setStatus(`Zig LSP error: ${data.message}`);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
editor.on("lsp_server_error", "on_zig_lsp_server_error");
|
|
35
|
+
|
|
36
|
+
globalThis.on_zig_lsp_status_clicked = function (data: LspStatusClickedData): void {
|
|
37
|
+
if (data.language !== "zig" || !zigLspError) return;
|
|
38
|
+
editor.showActionPopup({
|
|
39
|
+
id: "zig-lsp-help",
|
|
40
|
+
title: "Zig Language Server Not Found",
|
|
41
|
+
message: `Install zls for code completion and diagnostics. Visit ${INSTALL_URL}`,
|
|
42
|
+
actions: [
|
|
43
|
+
{ id: "copy_url", label: "Copy install URL" },
|
|
44
|
+
{ id: "disable", label: "Disable Zig LSP" },
|
|
45
|
+
{ id: "dismiss", label: "Dismiss (ESC)" },
|
|
46
|
+
],
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
editor.on("lsp_status_clicked", "on_zig_lsp_status_clicked");
|
|
50
|
+
|
|
51
|
+
globalThis.on_zig_lsp_action_result = function (data: ActionPopupResultData): void {
|
|
52
|
+
if (data.popup_id !== "zig-lsp-help") return;
|
|
53
|
+
switch (data.action_id) {
|
|
54
|
+
case "copy_url":
|
|
55
|
+
editor.setClipboard(INSTALL_URL);
|
|
56
|
+
editor.setStatus("Copied: " + INSTALL_URL);
|
|
57
|
+
break;
|
|
58
|
+
case "disable":
|
|
59
|
+
editor.disableLspForLanguage("zig");
|
|
60
|
+
editor.setStatus("Zig LSP disabled");
|
|
61
|
+
zigLspError = null;
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
editor.on("action_popup_result", "on_zig_lsp_action_result");
|