@fresh-editor/fresh-editor 0.2.25 → 0.3.1
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 +216 -0
- package/README.md +6 -0
- package/package.json +1 -1
- package/plugins/astro-lsp.ts +6 -12
- package/plugins/audit_mode.i18n.json +14 -14
- package/plugins/audit_mode.ts +182 -146
- package/plugins/bash-lsp.ts +15 -22
- package/plugins/clangd-lsp.ts +15 -24
- package/plugins/clojure-lsp.ts +9 -12
- package/plugins/cmake-lsp.ts +9 -12
- package/plugins/code-tour.ts +15 -16
- package/plugins/config-schema.json +79 -6
- package/plugins/csharp_support.ts +25 -30
- package/plugins/css-lsp.ts +15 -22
- package/plugins/dart-lsp.ts +9 -12
- package/plugins/dashboard.ts +1903 -0
- package/plugins/devcontainer.i18n.json +1472 -0
- package/plugins/devcontainer.ts +2793 -0
- package/plugins/diagnostics_panel.ts +10 -17
- package/plugins/elixir-lsp.ts +9 -12
- package/plugins/erlang-lsp.ts +9 -12
- package/plugins/examples/bookmarks.ts +10 -16
- package/plugins/find_references.ts +5 -9
- package/plugins/flash.ts +577 -0
- package/plugins/fsharp-lsp.ts +9 -12
- package/plugins/git_explorer.ts +16 -20
- package/plugins/git_gutter.ts +65 -79
- package/plugins/git_log.i18n.json +14 -42
- package/plugins/git_log.ts +19 -9
- package/plugins/gleam-lsp.ts +9 -12
- package/plugins/go-lsp.ts +15 -22
- package/plugins/graphql-lsp.ts +9 -12
- package/plugins/haskell-lsp.ts +9 -12
- package/plugins/html-lsp.ts +15 -24
- package/plugins/java-lsp.ts +9 -12
- package/plugins/json-lsp.ts +15 -24
- package/plugins/julia-lsp.ts +9 -12
- package/plugins/kotlin-lsp.ts +15 -22
- package/plugins/latex-lsp.ts +9 -12
- package/plugins/lib/fresh.d.ts +603 -0
- package/plugins/lua-lsp.ts +15 -22
- package/plugins/markdown_compose.ts +132 -128
- package/plugins/markdown_source.ts +8 -10
- package/plugins/marksman-lsp.ts +9 -12
- package/plugins/merge_conflict.ts +15 -17
- package/plugins/nim-lsp.ts +9 -12
- package/plugins/nix-lsp.ts +9 -12
- package/plugins/nushell-lsp.ts +9 -12
- package/plugins/ocaml-lsp.ts +9 -12
- package/plugins/odin-lsp.ts +15 -22
- package/plugins/path_complete.ts +5 -6
- package/plugins/perl-lsp.ts +9 -12
- package/plugins/php-lsp.ts +15 -22
- package/plugins/pkg.ts +10 -21
- package/plugins/protobuf-lsp.ts +9 -12
- package/plugins/python-lsp.ts +15 -24
- package/plugins/r-lsp.ts +9 -12
- package/plugins/ruby-lsp.ts +15 -22
- package/plugins/rust-lsp.ts +18 -28
- package/plugins/scala-lsp.ts +9 -12
- package/plugins/schemas/theme.schema.json +126 -0
- package/plugins/search_replace.ts +10 -13
- package/plugins/solidity-lsp.ts +9 -12
- package/plugins/sql-lsp.ts +9 -12
- package/plugins/svelte-lsp.ts +9 -12
- package/plugins/swift-lsp.ts +9 -12
- package/plugins/tailwindcss-lsp.ts +9 -12
- package/plugins/templ-lsp.ts +9 -12
- package/plugins/terraform-lsp.ts +9 -12
- package/plugins/theme_editor.i18n.json +98 -14
- package/plugins/theme_editor.ts +156 -209
- package/plugins/toml-lsp.ts +15 -22
- package/plugins/tsconfig.json +100 -0
- package/plugins/typescript-lsp.ts +15 -24
- package/plugins/typst-lsp.ts +15 -22
- package/plugins/vi_mode.ts +77 -290
- package/plugins/vue-lsp.ts +9 -12
- package/plugins/yaml-lsp.ts +15 -22
- package/plugins/zig-lsp.ts +9 -12
- package/themes/high-contrast.json +2 -2
- package/themes/nord.json +4 -0
- package/themes/solarized-dark.json +4 -0
package/plugins/audit_mode.ts
CHANGED
|
@@ -54,6 +54,7 @@ interface Hunk {
|
|
|
54
54
|
oldRange: { start: number; end: number }; // old file line range
|
|
55
55
|
type: 'add' | 'remove' | 'modify';
|
|
56
56
|
lines: string[];
|
|
57
|
+
status?: string;
|
|
57
58
|
contextHeader: string;
|
|
58
59
|
byteOffset: number; // Position in the virtual buffer
|
|
59
60
|
gitStatus?: 'staged' | 'unstaged' | 'untracked';
|
|
@@ -1579,7 +1580,7 @@ function on_review_mouse_click(data: {
|
|
|
1579
1580
|
else state.collapsedSections.add(cat);
|
|
1580
1581
|
applyFolds();
|
|
1581
1582
|
const sectionRow = state.sectionHeaderRows[cat];
|
|
1582
|
-
if (sectionRow !== undefined) jumpDiffCursorToRow(sectionRow);
|
|
1583
|
+
if (sectionRow !== undefined) jumpDiffCursorToRow(sectionRow, { recenter: false });
|
|
1583
1584
|
return;
|
|
1584
1585
|
}
|
|
1585
1586
|
}
|
|
@@ -1591,7 +1592,7 @@ function on_review_mouse_click(data: {
|
|
|
1591
1592
|
else state.collapsedFiles.add(key);
|
|
1592
1593
|
applyFolds();
|
|
1593
1594
|
const headerRow = state.fileHeaderRows[key];
|
|
1594
|
-
if (headerRow !== undefined) jumpDiffCursorToRow(headerRow);
|
|
1595
|
+
if (headerRow !== undefined) jumpDiffCursorToRow(headerRow, { recenter: false });
|
|
1595
1596
|
return;
|
|
1596
1597
|
}
|
|
1597
1598
|
}
|
|
@@ -1602,7 +1603,7 @@ function on_review_mouse_click(data: {
|
|
|
1602
1603
|
else state.collapsedHunks.add(hunkId);
|
|
1603
1604
|
applyFolds();
|
|
1604
1605
|
const hunkRow = state.hunkRowByHunkId[hunkId];
|
|
1605
|
-
if (hunkRow !== undefined) jumpDiffCursorToRow(hunkRow);
|
|
1606
|
+
if (hunkRow !== undefined) jumpDiffCursorToRow(hunkRow, { recenter: false });
|
|
1606
1607
|
return;
|
|
1607
1608
|
}
|
|
1608
1609
|
}
|
|
@@ -1812,7 +1813,7 @@ function review_toggle_file_collapse() {
|
|
|
1812
1813
|
else state.collapsedSections.add(section);
|
|
1813
1814
|
applyFolds();
|
|
1814
1815
|
const sectionRow = state.sectionHeaderRows[section];
|
|
1815
|
-
if (sectionRow !== undefined) jumpDiffCursorToRow(sectionRow);
|
|
1816
|
+
if (sectionRow !== undefined) jumpDiffCursorToRow(sectionRow, { recenter: false });
|
|
1816
1817
|
return;
|
|
1817
1818
|
}
|
|
1818
1819
|
|
|
@@ -1824,7 +1825,7 @@ function review_toggle_file_collapse() {
|
|
|
1824
1825
|
else state.collapsedFiles.add(key);
|
|
1825
1826
|
applyFolds();
|
|
1826
1827
|
const headerRow = state.fileHeaderRows[key];
|
|
1827
|
-
if (headerRow !== undefined) jumpDiffCursorToRow(headerRow);
|
|
1828
|
+
if (headerRow !== undefined) jumpDiffCursorToRow(headerRow, { recenter: false });
|
|
1828
1829
|
return;
|
|
1829
1830
|
}
|
|
1830
1831
|
|
|
@@ -1835,7 +1836,7 @@ function review_toggle_file_collapse() {
|
|
|
1835
1836
|
else state.collapsedHunks.add(hunk.id);
|
|
1836
1837
|
applyFolds();
|
|
1837
1838
|
const hunkRow = state.hunkRowByHunkId[hunk.id];
|
|
1838
|
-
if (hunkRow !== undefined) jumpDiffCursorToRow(hunkRow);
|
|
1839
|
+
if (hunkRow !== undefined) jumpDiffCursorToRow(hunkRow, { recenter: false });
|
|
1839
1840
|
return;
|
|
1840
1841
|
}
|
|
1841
1842
|
|
|
@@ -1848,7 +1849,7 @@ function review_toggle_file_collapse() {
|
|
|
1848
1849
|
else state.collapsedFiles.add(key);
|
|
1849
1850
|
applyFolds();
|
|
1850
1851
|
const headerRow = state.fileHeaderRows[key];
|
|
1851
|
-
if (headerRow !== undefined) jumpDiffCursorToRow(headerRow);
|
|
1852
|
+
if (headerRow !== undefined) jumpDiffCursorToRow(headerRow, { recenter: false });
|
|
1852
1853
|
}
|
|
1853
1854
|
registerHandler("review_toggle_file_collapse", review_toggle_file_collapse);
|
|
1854
1855
|
|
|
@@ -2462,48 +2463,9 @@ function review_discard_file() {
|
|
|
2462
2463
|
}
|
|
2463
2464
|
registerHandler("review_discard_file", review_discard_file);
|
|
2464
2465
|
|
|
2465
|
-
async function on_review_discard_hunk_confirm(args: { prompt_type: string; input: string; selected_index: number | null }): Promise<boolean> {
|
|
2466
|
-
if (args.prompt_type !== "review-discard-hunk-confirm") return true;
|
|
2467
|
-
const response = args.input.trim().toLowerCase();
|
|
2468
|
-
if (response === "discard" || args.selected_index === 0) {
|
|
2469
|
-
const hunk = getHunkAtDiffCursor();
|
|
2470
|
-
if (hunk && hunk.file) {
|
|
2471
|
-
const patch = buildHunkPatch(hunk.file, hunk);
|
|
2472
|
-
const ok = await applyHunkPatch(patch, ["--reverse"]);
|
|
2473
|
-
if (ok) {
|
|
2474
|
-
editor.setStatus(editor.t("status.hunk_discarded") || "Hunk discarded");
|
|
2475
|
-
await refreshMagitData();
|
|
2476
|
-
}
|
|
2477
|
-
}
|
|
2478
|
-
} else {
|
|
2479
|
-
editor.setStatus("Discard cancelled");
|
|
2480
|
-
}
|
|
2481
|
-
return false;
|
|
2482
|
-
}
|
|
2483
|
-
registerHandler("on_review_discard_hunk_confirm", on_review_discard_hunk_confirm);
|
|
2484
2466
|
|
|
2485
|
-
async function on_review_discard_confirm(args: { prompt_type: string; input: string; selected_index: number | null }): Promise<boolean> {
|
|
2486
|
-
if (args.prompt_type !== "review-discard-confirm") return true;
|
|
2487
2467
|
|
|
2488
|
-
|
|
2489
|
-
if (response === "discard" || args.selected_index === 0) {
|
|
2490
|
-
const f = pendingDiscardFile;
|
|
2491
|
-
if (f) {
|
|
2492
|
-
if (f.category === 'untracked') {
|
|
2493
|
-
await editor.spawnProcess("rm", ["--", f.path]);
|
|
2494
|
-
} else {
|
|
2495
|
-
await editor.spawnProcess("git", ["checkout", "--", f.path]);
|
|
2496
|
-
}
|
|
2497
|
-
await refreshMagitData();
|
|
2498
|
-
editor.setStatus(`Discarded: ${f.path}`);
|
|
2499
|
-
}
|
|
2500
|
-
} else {
|
|
2501
|
-
editor.setStatus("Discard cancelled");
|
|
2502
|
-
}
|
|
2503
|
-
pendingDiscardFile = null;
|
|
2504
|
-
return false;
|
|
2505
|
-
}
|
|
2506
|
-
registerHandler("on_review_discard_confirm", on_review_discard_confirm);
|
|
2468
|
+
|
|
2507
2469
|
|
|
2508
2470
|
/**
|
|
2509
2471
|
* Refresh file list and diffs using the new git status approach, then re-render.
|
|
@@ -3147,23 +3109,31 @@ registerHandler("review_drill_down", review_drill_down);
|
|
|
3147
3109
|
// --- Hunk navigation for side-by-side diff view ---
|
|
3148
3110
|
|
|
3149
3111
|
/**
|
|
3150
|
-
* Move the diff panel's native cursor to the given 1-indexed row
|
|
3151
|
-
*
|
|
3112
|
+
* Move the diff panel's native cursor to the given 1-indexed row.
|
|
3113
|
+
*
|
|
3114
|
+
* `options.recenter` controls whether the viewport is re-centered on the
|
|
3115
|
+
* target row. The default is `true` for user-initiated navigation (next
|
|
3116
|
+
* hunk, jump-to-comment, jump-to-file) — there the caller wants the
|
|
3117
|
+
* target to land at a predictable position in the viewport. Callers
|
|
3118
|
+
* that merely re-anchor the cursor to a nearby header (e.g. after a
|
|
3119
|
+
* collapse/expand toggle) should pass `recenter: false` so the viewport
|
|
3120
|
+
* stays put; `setBufferCursor` still runs `ensure_cursor_visible`, so
|
|
3121
|
+
* the cursor is scrolled into view only when it would otherwise move
|
|
3122
|
+
* off-screen. Without this opt-out every fold toggle re-centers the
|
|
3123
|
+
* cursor's row at ~1/3 from the top of the viewport, which makes the
|
|
3124
|
+
* diff jump around whenever the user is reading anywhere else.
|
|
3152
3125
|
*/
|
|
3153
|
-
function jumpDiffCursorToRow(row: number): void {
|
|
3126
|
+
function jumpDiffCursorToRow(row: number, options?: { recenter?: boolean }): void {
|
|
3154
3127
|
const diffId = state.panelBuffers["diff"];
|
|
3155
3128
|
if (diffId === undefined) return;
|
|
3156
3129
|
const idx = row - 1;
|
|
3157
3130
|
if (idx < 0 || idx >= state.diffLineByteOffsets.length) return;
|
|
3158
3131
|
|
|
3159
|
-
// Set the cursor by absolute byte offset + scroll the viewport.
|
|
3160
|
-
// Trust setBufferCursor — the previous N × executeAction("move_down")
|
|
3161
|
-
// walk was O(target_row) round-trips into the editor and made
|
|
3162
|
-
// collapsing big diffs visibly slow (thousands of round trips just
|
|
3163
|
-
// to land the cursor on a header).
|
|
3164
3132
|
const byteOffset = state.diffLineByteOffsets[idx];
|
|
3165
3133
|
editor.setBufferCursor(diffId, byteOffset);
|
|
3166
|
-
|
|
3134
|
+
if (options?.recenter !== false) {
|
|
3135
|
+
editor.scrollBufferToLine(diffId, idx);
|
|
3136
|
+
}
|
|
3167
3137
|
state.diffCursorRow = row;
|
|
3168
3138
|
applyCursorLineOverlay('diff');
|
|
3169
3139
|
refreshStickyHeader(idx);
|
|
@@ -3448,28 +3418,15 @@ async function review_delete_comment() {
|
|
|
3448
3418
|
}
|
|
3449
3419
|
registerHandler("review_delete_comment", review_delete_comment);
|
|
3450
3420
|
|
|
3451
|
-
|
|
3452
|
-
if (args.prompt_type !== "review-delete-comment-confirm") return true;
|
|
3453
|
-
const response = args.input.trim().toLowerCase();
|
|
3454
|
-
if ((response === "delete" || args.selected_index === 0) && pendingDeleteCommentId) {
|
|
3455
|
-
if (pendingDeleteCommentId === '__note__') {
|
|
3456
|
-
state.note = '';
|
|
3457
|
-
} else {
|
|
3458
|
-
state.comments = state.comments.filter(c => c.id !== pendingDeleteCommentId);
|
|
3459
|
-
}
|
|
3460
|
-
persistReview();
|
|
3461
|
-
updateMagitDisplay();
|
|
3462
|
-
editor.setStatus("Deleted");
|
|
3463
|
-
} else {
|
|
3464
|
-
editor.setStatus("Delete cancelled");
|
|
3465
|
-
}
|
|
3466
|
-
pendingDeleteCommentId = null;
|
|
3467
|
-
return false;
|
|
3468
|
-
}
|
|
3469
|
-
registerHandler("on_review_delete_comment_confirm", on_review_delete_comment_confirm);
|
|
3421
|
+
|
|
3470
3422
|
|
|
3471
3423
|
// Prompt event handlers
|
|
3472
|
-
|
|
3424
|
+
|
|
3425
|
+
|
|
3426
|
+
|
|
3427
|
+
|
|
3428
|
+
// Register prompt event handlers
|
|
3429
|
+
editor.on("prompt_confirmed", (args) => {
|
|
3473
3430
|
if (args.prompt_type !== "review-comment") {
|
|
3474
3431
|
return true;
|
|
3475
3432
|
}
|
|
@@ -3532,38 +3489,47 @@ function on_review_prompt_confirm(args: { prompt_type: string; input: string }):
|
|
|
3532
3489
|
}
|
|
3533
3490
|
pendingCommentInfo = null;
|
|
3534
3491
|
return true;
|
|
3535
|
-
}
|
|
3536
|
-
|
|
3492
|
+
});
|
|
3493
|
+
editor.on("prompt_confirmed", async (args) => {
|
|
3494
|
+
if (args.prompt_type !== "review-discard-confirm") return true;
|
|
3537
3495
|
|
|
3538
|
-
|
|
3539
|
-
if (args.
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
|
|
3496
|
+
const response = args.input.trim().toLowerCase();
|
|
3497
|
+
if (response === "discard" || args.selected_index === 0) {
|
|
3498
|
+
const f = pendingDiscardFile;
|
|
3499
|
+
if (f) {
|
|
3500
|
+
if (f.category === 'untracked') {
|
|
3501
|
+
await editor.spawnProcess("rm", ["--", f.path]);
|
|
3502
|
+
} else {
|
|
3503
|
+
await editor.spawnProcess("git", ["checkout", "--", f.path]);
|
|
3504
|
+
}
|
|
3505
|
+
await refreshMagitData();
|
|
3506
|
+
editor.setStatus(`Discarded: ${f.path}`);
|
|
3507
|
+
}
|
|
3508
|
+
} else {
|
|
3509
|
+
editor.setStatus("Discard cancelled");
|
|
3543
3510
|
}
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3511
|
+
pendingDiscardFile = null;
|
|
3512
|
+
return false;
|
|
3513
|
+
});
|
|
3514
|
+
editor.on("prompt_confirmed", async (args) => {
|
|
3515
|
+
if (args.prompt_type !== "review-discard-hunk-confirm") return true;
|
|
3516
|
+
const response = args.input.trim().toLowerCase();
|
|
3517
|
+
if (response === "discard" || args.selected_index === 0) {
|
|
3518
|
+
const hunk = getHunkAtDiffCursor();
|
|
3519
|
+
if (hunk && hunk.file) {
|
|
3520
|
+
const patch = buildHunkPatch(hunk.file, hunk);
|
|
3521
|
+
const ok = await applyHunkPatch(patch, ["--reverse"]);
|
|
3522
|
+
if (ok) {
|
|
3523
|
+
editor.setStatus(editor.t("status.hunk_discarded") || "Hunk discarded");
|
|
3524
|
+
await refreshMagitData();
|
|
3525
|
+
}
|
|
3526
|
+
}
|
|
3560
3527
|
} else {
|
|
3561
|
-
editor.
|
|
3528
|
+
editor.setStatus("Discard cancelled");
|
|
3562
3529
|
}
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
function on_review_edit_note_confirm(args: { prompt_type: string; input: string }): boolean {
|
|
3530
|
+
return false;
|
|
3531
|
+
});
|
|
3532
|
+
editor.on("prompt_confirmed", (args) => {
|
|
3567
3533
|
if (args.prompt_type !== "review-edit-note") return true;
|
|
3568
3534
|
if (args.input && args.input.trim()) {
|
|
3569
3535
|
state.note = args.input.trim();
|
|
@@ -3577,8 +3543,45 @@ function on_review_edit_note_confirm(args: { prompt_type: string; input: string
|
|
|
3577
3543
|
}
|
|
3578
3544
|
}
|
|
3579
3545
|
return true;
|
|
3546
|
+
});
|
|
3547
|
+
editor.on("prompt_confirmed", (args) => {
|
|
3548
|
+
if (args.prompt_type !== "review-delete-comment-confirm") return true;
|
|
3549
|
+
const response = args.input.trim().toLowerCase();
|
|
3550
|
+
if ((response === "delete" || args.selected_index === 0) && pendingDeleteCommentId) {
|
|
3551
|
+
if (pendingDeleteCommentId === '__note__') {
|
|
3552
|
+
state.note = '';
|
|
3553
|
+
} else {
|
|
3554
|
+
state.comments = state.comments.filter(c => c.id !== pendingDeleteCommentId);
|
|
3555
|
+
}
|
|
3556
|
+
persistReview();
|
|
3557
|
+
updateMagitDisplay();
|
|
3558
|
+
editor.setStatus("Deleted");
|
|
3559
|
+
} else {
|
|
3560
|
+
editor.setStatus("Delete cancelled");
|
|
3561
|
+
}
|
|
3562
|
+
pendingDeleteCommentId = null;
|
|
3563
|
+
return false;
|
|
3564
|
+
});
|
|
3565
|
+
editor.on("prompt_cancelled", (args) => {
|
|
3566
|
+
if (args.prompt_type === "review-comment") {
|
|
3567
|
+
pendingCommentInfo = null;
|
|
3568
|
+
editingCommentId = null;
|
|
3569
|
+
editor.setStatus(editor.t("status.comment_cancelled"));
|
|
3570
|
+
}
|
|
3571
|
+
return true;
|
|
3572
|
+
});
|
|
3573
|
+
|
|
3574
|
+
async function review_edit_note() {
|
|
3575
|
+
const label = editor.t("prompt.overall_comment") || "Note: ";
|
|
3576
|
+
if (state.note) {
|
|
3577
|
+
editor.startPromptWithInitial(label, "review-edit-note", state.note);
|
|
3578
|
+
} else {
|
|
3579
|
+
editor.startPrompt(label, "review-edit-note");
|
|
3580
|
+
}
|
|
3580
3581
|
}
|
|
3581
|
-
registerHandler("
|
|
3582
|
+
registerHandler("review_edit_note", review_edit_note);
|
|
3583
|
+
|
|
3584
|
+
|
|
3582
3585
|
|
|
3583
3586
|
async function review_export_session() {
|
|
3584
3587
|
const cwd = editor.getCwd();
|
|
@@ -3728,15 +3731,15 @@ async function openReviewPanels(groupName: string): Promise<boolean> {
|
|
|
3728
3731
|
|
|
3729
3732
|
updateMagitDisplay();
|
|
3730
3733
|
|
|
3731
|
-
editor.focusBufferGroupPanel(state.groupId
|
|
3734
|
+
editor.focusBufferGroupPanel(state.groupId!, "diff");
|
|
3732
3735
|
|
|
3733
|
-
editor.on("resize",
|
|
3736
|
+
editor.on("resize", onReviewDiffResize);
|
|
3734
3737
|
updateReviewStatus();
|
|
3735
|
-
editor.on("buffer_activated",
|
|
3736
|
-
editor.on("buffer_closed",
|
|
3737
|
-
editor.on("cursor_moved",
|
|
3738
|
-
editor.on("viewport_changed",
|
|
3739
|
-
editor.on("mouse_click",
|
|
3738
|
+
editor.on("buffer_activated", on_review_buffer_activated);
|
|
3739
|
+
editor.on("buffer_closed", on_review_buffer_closed);
|
|
3740
|
+
editor.on("cursor_moved", on_review_cursor_moved);
|
|
3741
|
+
editor.on("viewport_changed", on_review_viewport_changed);
|
|
3742
|
+
editor.on("mouse_click", on_review_mouse_click);
|
|
3740
3743
|
return true;
|
|
3741
3744
|
}
|
|
3742
3745
|
|
|
@@ -3812,12 +3815,12 @@ function stop_review_diff() {
|
|
|
3812
3815
|
}
|
|
3813
3816
|
state.reviewBufferId = null;
|
|
3814
3817
|
editor.setContext("review-mode", false);
|
|
3815
|
-
editor.off("resize",
|
|
3816
|
-
editor.off("buffer_activated",
|
|
3817
|
-
editor.off("buffer_closed",
|
|
3818
|
-
editor.off("cursor_moved",
|
|
3819
|
-
editor.off("viewport_changed",
|
|
3820
|
-
editor.off("mouse_click",
|
|
3818
|
+
editor.off("resize", onReviewDiffResize);
|
|
3819
|
+
editor.off("buffer_activated", on_review_buffer_activated);
|
|
3820
|
+
editor.off("buffer_closed", on_review_buffer_closed);
|
|
3821
|
+
editor.off("cursor_moved", on_review_cursor_moved);
|
|
3822
|
+
editor.off("viewport_changed", on_review_viewport_changed);
|
|
3823
|
+
editor.off("mouse_click", on_review_mouse_click);
|
|
3821
3824
|
editor.setStatus(editor.t("status.stopped"));
|
|
3822
3825
|
}
|
|
3823
3826
|
registerHandler("stop_review_diff", stop_review_diff);
|
|
@@ -3960,7 +3963,8 @@ async function start_review_range(): Promise<void> {
|
|
|
3960
3963
|
}
|
|
3961
3964
|
registerHandler("start_review_range", start_review_range);
|
|
3962
3965
|
|
|
3963
|
-
|
|
3966
|
+
|
|
3967
|
+
editor.on("prompt_confirmed", (args) => {
|
|
3964
3968
|
if (args.prompt_type !== "review-range") return true;
|
|
3965
3969
|
const range = parseRangeInput(args.input);
|
|
3966
3970
|
if (!range) {
|
|
@@ -3971,9 +3975,7 @@ function on_review_range_confirm(args: { prompt_type: string; input: string }):
|
|
|
3971
3975
|
// can return immediately.
|
|
3972
3976
|
bootstrapRangeReview(range);
|
|
3973
3977
|
return true;
|
|
3974
|
-
}
|
|
3975
|
-
registerHandler("on_review_range_confirm", on_review_range_confirm);
|
|
3976
|
-
editor.on("prompt_confirmed", "on_review_range_confirm");
|
|
3978
|
+
});
|
|
3977
3979
|
|
|
3978
3980
|
async function bootstrapRangeReview(range: ReviewRange): Promise<void> {
|
|
3979
3981
|
editor.setStatus(editor.t("status.generating") || "Generating diff…");
|
|
@@ -4388,12 +4390,47 @@ const branchState: ReviewBranchState = {
|
|
|
4388
4390
|
detailBufferId: null,
|
|
4389
4391
|
commits: [],
|
|
4390
4392
|
selectedIndex: 0,
|
|
4391
|
-
|
|
4393
|
+
// Empty means "not yet detected"; start_review_branch fills this in
|
|
4394
|
+
// from the repo's actual default branch (main, master, or whatever
|
|
4395
|
+
// origin/HEAD points at) before showing the prompt.
|
|
4396
|
+
baseRef: "",
|
|
4392
4397
|
detailCache: null,
|
|
4393
4398
|
pendingDetailId: 0,
|
|
4394
4399
|
logRowByteOffsets: [],
|
|
4395
4400
|
};
|
|
4396
4401
|
|
|
4402
|
+
/**
|
|
4403
|
+
* Best-effort detection of the repo's default branch. Checks, in order:
|
|
4404
|
+
* 1. `origin/HEAD` (the remote's notion of the default branch)
|
|
4405
|
+
* 2. local `main`
|
|
4406
|
+
* 3. local `master`
|
|
4407
|
+
* Falls back to `main` if none match, so the prompt still has a sensible
|
|
4408
|
+
* default in an empty / unusual repo.
|
|
4409
|
+
*/
|
|
4410
|
+
async function detectDefaultBranch(): Promise<string> {
|
|
4411
|
+
try {
|
|
4412
|
+
const r = await editor.spawnProcess("git", [
|
|
4413
|
+
"symbolic-ref", "--short", "refs/remotes/origin/HEAD",
|
|
4414
|
+
]);
|
|
4415
|
+
if (r.exit_code === 0) {
|
|
4416
|
+
const name = r.stdout.trim();
|
|
4417
|
+
// Output looks like "origin/main"; strip the remote prefix.
|
|
4418
|
+
const slash = name.indexOf("/");
|
|
4419
|
+
const branch = slash >= 0 ? name.slice(slash + 1) : name;
|
|
4420
|
+
if (branch) return branch;
|
|
4421
|
+
}
|
|
4422
|
+
} catch { /* fall through */ }
|
|
4423
|
+
for (const candidate of ["main", "master"]) {
|
|
4424
|
+
try {
|
|
4425
|
+
const r = await editor.spawnProcess("git", [
|
|
4426
|
+
"show-ref", "--verify", "--quiet", `refs/heads/${candidate}`,
|
|
4427
|
+
]);
|
|
4428
|
+
if (r.exit_code === 0) return candidate;
|
|
4429
|
+
} catch { /* fall through */ }
|
|
4430
|
+
}
|
|
4431
|
+
return "main";
|
|
4432
|
+
}
|
|
4433
|
+
|
|
4397
4434
|
// UTF-8 byte length helper, local copy so audit_mode doesn't pull in the one
|
|
4398
4435
|
// from git_history (keeps the import list tiny).
|
|
4399
4436
|
function branchUtf8Len(s: string): number {
|
|
@@ -4501,16 +4538,20 @@ async function start_review_branch(): Promise<void> {
|
|
|
4501
4538
|
return;
|
|
4502
4539
|
}
|
|
4503
4540
|
// Prompt for the base ref so the user can review any PR, not just
|
|
4504
|
-
// one branched off main.
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
);
|
|
4541
|
+
// one branched off main. The default offered is either what the user
|
|
4542
|
+
// picked last time in this session, or the repo's actual default
|
|
4543
|
+
// branch (main/master/etc.) on first use.
|
|
4544
|
+
const suggested = branchState.baseRef || await detectDefaultBranch();
|
|
4545
|
+
const rawPromptText = editor.t("prompt.branch_base", { default: suggested });
|
|
4546
|
+
const promptText = (rawPromptText && !rawPromptText.startsWith("prompt."))
|
|
4547
|
+
? rawPromptText
|
|
4548
|
+
: `Base ref to compare against (default: ${suggested}):`;
|
|
4549
|
+
const input = await editor.prompt(promptText + " ", suggested);
|
|
4509
4550
|
if (input === null) {
|
|
4510
4551
|
editor.setStatus(editor.t("status.cancelled") || "Cancelled");
|
|
4511
4552
|
return;
|
|
4512
4553
|
}
|
|
4513
|
-
const base = input.trim() ||
|
|
4554
|
+
const base = input.trim() || suggested;
|
|
4514
4555
|
branchState.baseRef = base;
|
|
4515
4556
|
|
|
4516
4557
|
editor.setStatus(editor.t("status.loading") || "Loading commits…");
|
|
@@ -4560,7 +4601,7 @@ async function start_review_branch(): Promise<void> {
|
|
|
4560
4601
|
if (branchState.groupId !== null) {
|
|
4561
4602
|
editor.focusBufferGroupPanel(branchState.groupId, "log");
|
|
4562
4603
|
}
|
|
4563
|
-
editor.on("cursor_moved",
|
|
4604
|
+
editor.on("cursor_moved", on_review_branch_cursor_moved);
|
|
4564
4605
|
|
|
4565
4606
|
editor.setStatus(
|
|
4566
4607
|
editor.t("status.review_branch_ready", {
|
|
@@ -4574,7 +4615,7 @@ registerHandler("start_review_branch", start_review_branch);
|
|
|
4574
4615
|
function stop_review_branch(): void {
|
|
4575
4616
|
if (!branchState.isOpen) return;
|
|
4576
4617
|
if (branchState.groupId !== null) editor.closeBufferGroup(branchState.groupId);
|
|
4577
|
-
editor.off("cursor_moved",
|
|
4618
|
+
editor.off("cursor_moved", on_review_branch_cursor_moved);
|
|
4578
4619
|
branchState.isOpen = false;
|
|
4579
4620
|
branchState.groupId = null;
|
|
4580
4621
|
branchState.logBufferId = null;
|
|
@@ -4637,17 +4678,11 @@ registerHandler("on_review_branch_cursor_moved", on_review_branch_cursor_moved);
|
|
|
4637
4678
|
editor.defineMode(
|
|
4638
4679
|
"review-branch",
|
|
4639
4680
|
[
|
|
4640
|
-
//
|
|
4641
|
-
//
|
|
4642
|
-
//
|
|
4643
|
-
["Up", "move_up"],
|
|
4644
|
-
["Down", "move_down"],
|
|
4681
|
+
// vi-style aliases for Up/Down. Everything else (arrows,
|
|
4682
|
+
// Page{Up,Down}, Home/End, selection motion, …) is inherited
|
|
4683
|
+
// from the Normal keymap via `inheritNormalBindings: true`.
|
|
4645
4684
|
["k", "move_up"],
|
|
4646
4685
|
["j", "move_down"],
|
|
4647
|
-
["PageUp", "page_up"],
|
|
4648
|
-
["PageDown", "page_down"],
|
|
4649
|
-
["Home", "move_line_start"],
|
|
4650
|
-
["End", "move_line_end"],
|
|
4651
4686
|
// Enter: focus the right-hand detail panel.
|
|
4652
4687
|
["Return", "review_branch_enter"],
|
|
4653
4688
|
["Tab", "review_branch_enter"],
|
|
@@ -4655,7 +4690,9 @@ editor.defineMode(
|
|
|
4655
4690
|
["q", "review_branch_close_or_back"],
|
|
4656
4691
|
["Escape", "review_branch_close_or_back"],
|
|
4657
4692
|
],
|
|
4658
|
-
true,
|
|
4693
|
+
true, // readOnly
|
|
4694
|
+
false, // allowTextInput — keeps plain letters from inserting into the RO buffer
|
|
4695
|
+
true, // inheritNormalBindings — PageUp/PageDown/arrows/Home/End come from Normal
|
|
4659
4696
|
);
|
|
4660
4697
|
|
|
4661
4698
|
// Register Modes and Commands
|
|
@@ -4674,7 +4711,9 @@ editor.registerCommand("%cmd.export_markdown", "%cmd.export_markdown_desc", "rev
|
|
|
4674
4711
|
editor.registerCommand("%cmd.export_json", "%cmd.export_json_desc", "review_export_json", "review-mode");
|
|
4675
4712
|
|
|
4676
4713
|
// Handler for when buffers are closed - cleans up scroll sync groups and composite buffers
|
|
4677
|
-
|
|
4714
|
+
|
|
4715
|
+
|
|
4716
|
+
editor.on("buffer_closed", (data) => {
|
|
4678
4717
|
// If one of the diff view buffers is closed, clean up the scroll sync group
|
|
4679
4718
|
if (activeSideBySideState) {
|
|
4680
4719
|
if (data.buffer_id === activeSideBySideState.oldBufferId ||
|
|
@@ -4701,10 +4740,7 @@ function on_buffer_closed(data: any) {
|
|
|
4701
4740
|
activeCompositeDiffState = null;
|
|
4702
4741
|
}
|
|
4703
4742
|
}
|
|
4704
|
-
}
|
|
4705
|
-
registerHandler("on_buffer_closed", on_buffer_closed);
|
|
4706
|
-
|
|
4707
|
-
editor.on("buffer_closed", "on_buffer_closed");
|
|
4743
|
+
});
|
|
4708
4744
|
|
|
4709
4745
|
editor.defineMode("review-mode", [
|
|
4710
4746
|
// Native cursor motion in the unified diff stream.
|
package/plugins/bash-lsp.ts
CHANGED
|
@@ -49,7 +49,10 @@ let bashLspError: { serverCommand: string; message: string } | null = null;
|
|
|
49
49
|
/**
|
|
50
50
|
* Handle LSP server errors for Bash
|
|
51
51
|
*/
|
|
52
|
-
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
// Register hook for LSP server errors
|
|
55
|
+
editor.on("lsp_server_error", (data) => {
|
|
53
56
|
// Only handle Bash language errors
|
|
54
57
|
if (data.language !== "bash") {
|
|
55
58
|
return;
|
|
@@ -71,18 +74,15 @@ function on_bash_lsp_server_error(data: LspServerErrorData): void {
|
|
|
71
74
|
} else {
|
|
72
75
|
editor.setStatus(`Bash LSP error: ${data.message}`);
|
|
73
76
|
}
|
|
74
|
-
}
|
|
75
|
-
registerHandler("on_bash_lsp_server_error", on_bash_lsp_server_error);
|
|
76
|
-
|
|
77
|
-
// Register hook for LSP server errors
|
|
78
|
-
editor.on("lsp_server_error", "on_bash_lsp_server_error");
|
|
77
|
+
});
|
|
79
78
|
|
|
80
79
|
/**
|
|
81
80
|
* Handle status bar click when there's a Bash LSP error
|
|
82
81
|
*/
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
// Register hook for status bar clicks
|
|
85
|
+
editor.on("lsp_status_clicked", (data) => {
|
|
86
86
|
// Only handle Bash language clicks when there's an error
|
|
87
87
|
if (data.language !== "bash" || !bashLspError) {
|
|
88
88
|
return;
|
|
@@ -103,18 +103,15 @@ function on_bash_lsp_status_clicked(
|
|
|
103
103
|
{ id: "dismiss", label: "Dismiss (ESC)" },
|
|
104
104
|
],
|
|
105
105
|
});
|
|
106
|
-
}
|
|
107
|
-
registerHandler("on_bash_lsp_status_clicked", on_bash_lsp_status_clicked);
|
|
108
|
-
|
|
109
|
-
// Register hook for status bar clicks
|
|
110
|
-
editor.on("lsp_status_clicked", "on_bash_lsp_status_clicked");
|
|
106
|
+
});
|
|
111
107
|
|
|
112
108
|
/**
|
|
113
109
|
* Handle action popup results for Bash LSP help
|
|
114
110
|
*/
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
// Register hook for action popup results
|
|
114
|
+
editor.on("action_popup_result", (data) => {
|
|
118
115
|
// Only handle our popup
|
|
119
116
|
if (data.popup_id !== "bash-lsp-help") {
|
|
120
117
|
return;
|
|
@@ -152,10 +149,6 @@ function on_bash_lsp_action_result(
|
|
|
152
149
|
default:
|
|
153
150
|
editor.debug(`bash-lsp: Unknown action: ${data.action_id}`);
|
|
154
151
|
}
|
|
155
|
-
}
|
|
156
|
-
registerHandler("on_bash_lsp_action_result", on_bash_lsp_action_result);
|
|
157
|
-
|
|
158
|
-
// Register hook for action popup results
|
|
159
|
-
editor.on("action_popup_result", "on_bash_lsp_action_result");
|
|
152
|
+
});
|
|
160
153
|
|
|
161
154
|
editor.debug("bash-lsp: Plugin loaded");
|
package/plugins/clangd-lsp.ts
CHANGED
|
@@ -54,9 +54,10 @@ let clangdLspError: {
|
|
|
54
54
|
/**
|
|
55
55
|
* Handle LSP server errors for C/C++
|
|
56
56
|
*/
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
// Register hook for LSP server errors
|
|
60
|
+
editor.on("lsp_server_error", (data) => {
|
|
60
61
|
// Only handle C/C++ language errors
|
|
61
62
|
if (!HANDLED_LANGUAGES.includes(data.language)) {
|
|
62
63
|
return;
|
|
@@ -79,18 +80,15 @@ function on_clangd_lsp_server_error(
|
|
|
79
80
|
} else {
|
|
80
81
|
editor.setStatus(`C/C++ LSP error: ${data.message}`);
|
|
81
82
|
}
|
|
82
|
-
}
|
|
83
|
-
registerHandler("on_clangd_lsp_server_error", on_clangd_lsp_server_error);
|
|
84
|
-
|
|
85
|
-
// Register hook for LSP server errors
|
|
86
|
-
editor.on("lsp_server_error", "on_clangd_lsp_server_error");
|
|
83
|
+
});
|
|
87
84
|
|
|
88
85
|
/**
|
|
89
86
|
* Handle status bar click when there's a C/C++ LSP error
|
|
90
87
|
*/
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
// Register hook for status bar clicks
|
|
91
|
+
editor.on("lsp_status_clicked", (data) => {
|
|
94
92
|
// Only handle C/C++ language clicks when there's an error
|
|
95
93
|
if (!HANDLED_LANGUAGES.includes(data.language) || !clangdLspError) {
|
|
96
94
|
return;
|
|
@@ -111,18 +109,15 @@ function on_clangd_lsp_status_clicked(
|
|
|
111
109
|
{ id: "dismiss", label: "Dismiss (ESC)" },
|
|
112
110
|
],
|
|
113
111
|
});
|
|
114
|
-
}
|
|
115
|
-
registerHandler("on_clangd_lsp_status_clicked", on_clangd_lsp_status_clicked);
|
|
116
|
-
|
|
117
|
-
// Register hook for status bar clicks
|
|
118
|
-
editor.on("lsp_status_clicked", "on_clangd_lsp_status_clicked");
|
|
112
|
+
});
|
|
119
113
|
|
|
120
114
|
/**
|
|
121
115
|
* Handle action popup results for C/C++ LSP help
|
|
122
116
|
*/
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
// Register hook for action popup results
|
|
120
|
+
editor.on("action_popup_result", (data) => {
|
|
126
121
|
// Only handle our popup
|
|
127
122
|
if (data.popup_id !== "clangd-lsp-help") {
|
|
128
123
|
return;
|
|
@@ -162,10 +157,6 @@ function on_clangd_lsp_action_result(
|
|
|
162
157
|
default:
|
|
163
158
|
editor.debug(`clangd-lsp: Unknown action: ${data.action_id}`);
|
|
164
159
|
}
|
|
165
|
-
}
|
|
166
|
-
registerHandler("on_clangd_lsp_action_result", on_clangd_lsp_action_result);
|
|
167
|
-
|
|
168
|
-
// Register hook for action popup results
|
|
169
|
-
editor.on("action_popup_result", "on_clangd_lsp_action_result");
|
|
160
|
+
});
|
|
170
161
|
|
|
171
162
|
editor.debug("clangd-lsp: Plugin loaded");
|