Skip to content

Commit cf2acc5

Browse files
committed
fix fold all command same line thing
1 parent e0a6c26 commit cf2acc5

2 files changed

Lines changed: 58 additions & 14 deletions

File tree

‎src/cm/foldingCommands.js‎

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,67 @@
11
import {
22
codeFolding,
33
ensureSyntaxTree,
4-
foldable,
54
foldEffect,
65
foldedRanges,
6+
foldNodeProp,
7+
foldService,
78
foldState,
9+
syntaxTree,
810
unfoldEffect,
911
} from "@codemirror/language";
1012
import { StateEffect } from "@codemirror/state";
1113

1214
const FULL_PARSE_BUDGET_MS = 100;
15+
const INCOMPLETE_PARSE_MARGIN = 50;
16+
17+
function findServiceFold(state, line) {
18+
for (const service of state.facet(foldService)) {
19+
const range = service(state, line.from, line.to);
20+
if (range) return range;
21+
}
22+
return null;
23+
}
24+
25+
function addSyntaxFolds(state, tree, line, addRange) {
26+
if (!tree || tree.length < line.to) return;
27+
28+
for (let iter = tree.resolveStack(line.to, 1); iter; iter = iter.next) {
29+
const node = iter.node;
30+
if (node.to <= line.to || node.from > line.to) continue;
31+
const lastChild = node.lastChild;
32+
if (
33+
tree.length !== state.doc.length &&
34+
node.to >= tree.length - INCOMPLETE_PARSE_MARGIN &&
35+
lastChild?.to === node.to &&
36+
lastChild.type.isError
37+
) {
38+
continue;
39+
}
40+
41+
const fold = node.type.prop(foldNodeProp);
42+
if (!fold) continue;
43+
44+
const range = fold(node, state);
45+
if (
46+
range &&
47+
range.from >= line.from &&
48+
range.from <= line.to &&
49+
range.to > line.to
50+
) {
51+
addRange(range);
52+
}
53+
}
54+
}
1355

1456
/**
1557
* Fold every foldable block, including nested blocks. CodeMirror's built-in
1658
* foldAll intentionally skips nested ranges after finding a top-level fold.
1759
*/
1860
export function foldAllCodeBlocks(view) {
1961
const { state } = view;
20-
ensureSyntaxTree(state, state.doc.length, FULL_PARSE_BUDGET_MS);
62+
const tree =
63+
ensureSyntaxTree(state, state.doc.length, FULL_PARSE_BUDGET_MS) ??
64+
syntaxTree(state);
2165

2266
const existing = new Set();
2367
foldedRanges(state).between(0, state.doc.length, (from, to) => {
@@ -26,15 +70,18 @@ export function foldAllCodeBlocks(view) {
2670

2771
const effects = [];
2872
const discovered = new Set();
29-
for (let lineNumber = 1; lineNumber <= state.doc.lines; lineNumber += 1) {
30-
const line = state.doc.line(lineNumber);
31-
const range = foldable(state, line.from, line.to);
32-
if (!range) continue;
33-
73+
const addRange = (range) => {
3474
const id = `${range.from}:${range.to}`;
35-
if (existing.has(id) || discovered.has(id)) continue;
75+
if (existing.has(id) || discovered.has(id)) return;
3676
discovered.add(id);
3777
effects.push(foldEffect.of(range));
78+
};
79+
80+
for (let lineNumber = 1; lineNumber <= state.doc.lines; lineNumber += 1) {
81+
const line = state.doc.line(lineNumber);
82+
const serviceRange = findServiceFold(state, line);
83+
if (serviceRange) addRange(serviceRange);
84+
else addSyntaxFolds(state, tree, line, addRange);
3885
}
3986

4087
if (!effects.length) return false;

‎src/test/editor.tests.js‎

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -760,20 +760,17 @@ export async function runCodeMirrorTests(writeOutput) {
760760
);
761761

762762
runner.test(
763-
"Fold all includes nested blocks and unfold all clears them",
763+
"Fold all includes same-line nested blocks and unfold all clears them",
764764
async (test) => {
765765
await withEditor(
766766
test,
767767
async (view) => {
768768
test.assert(foldAllCodeBlocks(view), "Nested blocks should fold");
769-
test.assert(
770-
countFolds(view) >= 2,
771-
"Fold all should retain both outer and nested folds",
772-
);
769+
test.assertEqual(countFolds(view), 2);
773770
test.assert(unfoldAllCodeBlocks(view), "All folds should unfold");
774771
test.assertEqual(countFolds(view), 0);
775772
},
776-
"function outer() {\n if (true) {\n console.log('nested');\n }\n}",
773+
"function outer() { if (true) {\n console.log('nested');\n} }",
777774
[javascript()],
778775
);
779776
},

0 commit comments

Comments
 (0)