Skip to content

Commit 51694b0

Browse files
authored
Merge branch 'main' into main
2 parents dfddd77 + d2eb67e commit 51694b0

115 files changed

Lines changed: 7633 additions & 3850 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

_typos.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,4 @@ styl = "styl"
5353
IZ = "IZ"
5454
shft = "shft"
5555
multline = "multline"
56+
sav = "sav"

rspack.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ module.exports = (env, options) => {
114114
main: './src/main.js',
115115
console: './src/lib/console.js',
116116
searchInFilesWorker: './src/sidebarApps/searchInFiles/worker.js',
117+
searchIndexWorker: './src/sidebarApps/searchInFiles/indexWorker.js',
117118
},
118119
output: {
119120
path: path.resolve(__dirname, 'www/build/'),

src/cm/baseExtensions.ts

Lines changed: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,27 +22,55 @@ import {
2222
tooltips,
2323
} from "@codemirror/view";
2424

25+
export interface BaseExtensionOptions {
26+
autoIndent?: boolean;
27+
codeFolding?: boolean;
28+
autoCloseBrackets?: boolean;
29+
bracketMatching?: boolean;
30+
highlightActiveLine?: boolean;
31+
highlightSelectionMatches?: boolean;
32+
}
33+
2534
/**
2635
* Base extensions roughly matching the useful parts of CodeMirror's basicSetup
2736
*/
28-
export default function createBaseExtensions(): Extension[] {
29-
return [
30-
highlightActiveLineGutter(),
37+
export default function createBaseExtensions(
38+
options: BaseExtensionOptions = {},
39+
): Extension[] {
40+
const {
41+
autoIndent = true,
42+
codeFolding = true,
43+
autoCloseBrackets = true,
44+
bracketMatching: enableBracketMatching = true,
45+
highlightActiveLine: enableHighlightActiveLine = true,
46+
highlightSelectionMatches: enableHighlightSelectionMatches = true,
47+
} = options;
48+
const extensions: Extension[] = [
3149
highlightSpecialChars(),
3250
history(),
33-
foldGutter(),
34-
drawSelection(),
35-
dropCursor(),
36-
EditorState.allowMultipleSelections.of(true),
37-
indentOnInput(),
51+
];
52+
53+
if (enableHighlightActiveLine) extensions.push(highlightActiveLineGutter());
54+
if (codeFolding) extensions.push(foldGutter());
55+
extensions.push(drawSelection());
56+
extensions.push(dropCursor());
57+
extensions.push(EditorState.allowMultipleSelections.of(true));
58+
if (autoIndent) extensions.push(indentOnInput());
59+
extensions.push(
3860
syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
39-
bracketMatching(),
40-
closeBrackets(),
41-
rectangularSelection(),
42-
crosshairCursor(),
43-
highlightActiveLine(),
44-
highlightSelectionMatches(),
61+
);
62+
if (enableBracketMatching) extensions.push(bracketMatching());
63+
if (autoCloseBrackets) extensions.push(closeBrackets());
64+
extensions.push(rectangularSelection());
65+
extensions.push(crosshairCursor());
66+
if (enableHighlightActiveLine) extensions.push(highlightActiveLine());
67+
if (enableHighlightSelectionMatches) {
68+
extensions.push(highlightSelectionMatches());
69+
}
70+
extensions.push(
4571
keymap.of([...completionKeymap, ...defaultKeymap, ...historyKeymap]),
72+
);
73+
extensions.push(
4674
// This prevents tooltips from being going out of the editor area
4775
tooltips({
4876
tooltipSpace: (view) => {
@@ -55,5 +83,7 @@ export default function createBaseExtensions(): Extension[] {
5583
};
5684
},
5785
}),
58-
];
86+
);
87+
88+
return extensions;
5989
}

src/cm/commandRegistry.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1255,7 +1255,6 @@ function copyCommand(view) {
12551255
});
12561256
const textToCopy = texts.join("\n");
12571257
cordova.plugins.clipboard.copy(textToCopy);
1258-
toast?.(strings?.["copied to clipboard"] || "Copied to clipboard");
12591258
return true;
12601259
}
12611260

src/cm/indentGuides.ts

Lines changed: 130 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ const defaultConfig: Required<IndentGuidesConfig> = {
2525
};
2626

2727
const GUIDE_MARK_CLASS = "cm-indent-guides";
28-
const MAX_VISIBLE_GUIDE_LINES = 1200;
28+
const GUIDE_LINE_CLASS = "cm-indent-guides-line";
29+
const MAX_VISIBLE_GUIDE_LINES = 500;
2930
const MAX_GUIDE_LEVELS = 40;
30-
const REBUILD_DELAY_MS = 50;
3131

3232
interface IndentLineInfo {
3333
text: string;
@@ -40,6 +40,8 @@ interface IndentLineInfo {
4040
type IndentLineCache = Map<number, IndentLineInfo>;
4141
type GuideStyleCache = Map<string, string>;
4242

43+
const BLANK_LINE_SCAN_LIMIT = 100;
44+
4345
/**
4446
* Get the tab size from editor state
4547
*/
@@ -171,8 +173,47 @@ function buildDecorations(
171173
for (const { from: blockFrom, to: blockTo } of view.visibleRanges) {
172174
const startLine = state.doc.lineAt(blockFrom);
173175
const endLine = state.doc.lineAt(blockTo);
176+
const firstLineNumber = startLine.number;
177+
const lastLineNumber = endLine.number;
178+
const scanStartLine = Math.max(1, firstLineNumber - BLANK_LINE_SCAN_LIMIT);
179+
const scanEndLine = Math.min(
180+
state.doc.lines,
181+
lastLineNumber + BLANK_LINE_SCAN_LIMIT,
182+
);
183+
const prevIndentByLine = new Map<number, number>();
184+
const nextIndentByLine = new Map<number, number>();
185+
let prevIndent = -1;
186+
let prevIndentLine = -1;
187+
188+
for (let lineNum = scanStartLine; lineNum <= scanEndLine; lineNum++) {
189+
const line = state.doc.line(lineNum);
190+
const info = getCachedLineInfo(lineNum, line.text, tabSize, lineCache);
191+
prevIndentByLine.set(
192+
lineNum,
193+
lineNum - prevIndentLine <= BLANK_LINE_SCAN_LIMIT ? prevIndent : -1,
194+
);
195+
if (!info.blank) {
196+
prevIndent = info.indentColumns;
197+
prevIndentLine = lineNum;
198+
}
199+
}
200+
201+
let nextIndent = -1;
202+
let nextIndentLine = state.doc.lines + 1;
203+
for (let lineNum = scanEndLine; lineNum >= scanStartLine; lineNum--) {
204+
const line = state.doc.line(lineNum);
205+
const info = getCachedLineInfo(lineNum, line.text, tabSize, lineCache);
206+
nextIndentByLine.set(
207+
lineNum,
208+
nextIndentLine - lineNum <= BLANK_LINE_SCAN_LIMIT ? nextIndent : -1,
209+
);
210+
if (!info.blank) {
211+
nextIndent = info.indentColumns;
212+
nextIndentLine = lineNum;
213+
}
214+
}
174215

175-
for (let lineNum = startLine.number; lineNum <= endLine.number; lineNum++) {
216+
for (let lineNum = firstLineNumber; lineNum <= lastLineNumber; lineNum++) {
176217
if (processedLines >= MAX_VISIBLE_GUIDE_LINES) return builder.finish();
177218
processedLines++;
178219

@@ -183,23 +224,49 @@ function buildDecorations(
183224
continue;
184225
}
185226

227+
let indentColumns = info.indentColumns;
228+
if (info.blank) {
229+
const previousIndent = prevIndentByLine.get(lineNum) ?? -1;
230+
const followingIndent = nextIndentByLine.get(lineNum) ?? -1;
231+
if (previousIndent !== -1 && followingIndent !== -1) {
232+
indentColumns = Math.min(previousIndent, followingIndent);
233+
} else if (previousIndent !== -1) {
234+
indentColumns = previousIndent;
235+
} else if (followingIndent !== -1) {
236+
indentColumns = followingIndent;
237+
}
238+
}
239+
186240
const levels = Math.min(
187-
Math.floor(info.indentColumns / indentUnit),
241+
Math.floor(indentColumns / indentUnit),
188242
MAX_GUIDE_LEVELS,
189243
);
190244
if (levels <= 0) continue;
191-
if (info.leadingWhitespaceLength <= 0) continue;
192-
193-
builder.add(
194-
line.from,
195-
line.from + info.leadingWhitespaceLength,
196-
Decoration.mark({
197-
attributes: {
198-
class: GUIDE_MARK_CLASS,
199-
style: getGuideStyle(levels, guideStepPx, styleCache),
200-
},
201-
}),
202-
);
245+
246+
if (info.blank) {
247+
builder.add(
248+
line.from,
249+
line.from,
250+
Decoration.line({
251+
attributes: {
252+
class: GUIDE_LINE_CLASS,
253+
style: getGuideStyle(levels, guideStepPx, styleCache),
254+
},
255+
}),
256+
);
257+
} else {
258+
if (info.leadingWhitespaceLength <= 0) continue;
259+
builder.add(
260+
line.from,
261+
line.from + info.leadingWhitespaceLength,
262+
Decoration.mark({
263+
attributes: {
264+
class: GUIDE_MARK_CLASS,
265+
style: getGuideStyle(levels, guideStepPx, styleCache),
266+
},
267+
}),
268+
);
269+
}
203270
}
204271
}
205272

@@ -218,57 +285,72 @@ function createIndentGuidesPlugin(
218285
return ViewPlugin.fromClass(
219286
class {
220287
decorations: DecorationSet;
221-
rebuildTimer = 0;
222-
pendingView: EditorView | null = null;
223288
lineCache: IndentLineCache = new Map();
224289
styleCache: GuideStyleCache = new Map();
290+
lastCharWidth = 0;
291+
lastTabSize = 4;
292+
lastIndentUnit = 4;
225293

226294
constructor(view: EditorView) {
227-
this.decorations = Decoration.none;
228-
this.scheduleBuild(view);
295+
const { state } = view;
296+
this.lastCharWidth = view.defaultCharacterWidth;
297+
this.lastTabSize = getTabSize(state);
298+
this.lastIndentUnit = getIndentUnitColumns(state);
299+
300+
this.decorations = buildDecorations(
301+
view,
302+
config,
303+
this.lineCache,
304+
this.styleCache,
305+
);
229306
}
230307

231308
update(update: ViewUpdate): void {
232-
if (
233-
!update.docChanged &&
234-
!update.viewportChanged &&
235-
!update.geometryChanged
236-
) {
237-
return;
238-
}
309+
const { view, state } = update;
310+
let needsRebuild = false;
311+
239312
if (update.docChanged) {
240313
this.decorations = this.decorations.map(update.changes);
241314
this.lineCache.clear();
315+
needsRebuild = true;
316+
}
317+
318+
if (update.viewportChanged) {
319+
needsRebuild = true;
320+
}
321+
322+
const currentTabSize = getTabSize(state);
323+
const currentIndentUnit = getIndentUnitColumns(state);
324+
const currentCharWidth = view.defaultCharacterWidth;
325+
326+
if (
327+
currentTabSize !== this.lastTabSize ||
328+
currentIndentUnit !== this.lastIndentUnit
329+
) {
330+
this.lastTabSize = currentTabSize;
331+
this.lastIndentUnit = currentIndentUnit;
332+
this.lineCache.clear();
333+
this.styleCache.clear();
334+
needsRebuild = true;
242335
}
243-
if (update.geometryChanged) {
336+
337+
if (currentCharWidth !== this.lastCharWidth) {
338+
this.lastCharWidth = currentCharWidth;
244339
this.styleCache.clear();
340+
needsRebuild = true;
245341
}
246-
this.scheduleBuild(update.view);
247-
}
248342

249-
scheduleBuild(view: EditorView): void {
250-
this.pendingView = view;
251-
if (this.rebuildTimer) return;
252-
this.rebuildTimer = window.setTimeout(() => {
253-
this.rebuildTimer = 0;
254-
const pendingView = this.pendingView;
255-
this.pendingView = null;
256-
if (!pendingView) return;
343+
if (needsRebuild) {
257344
this.decorations = buildDecorations(
258-
pendingView,
345+
view,
259346
config,
260347
this.lineCache,
261348
this.styleCache,
262349
);
263-
}, REBUILD_DELAY_MS);
350+
}
264351
}
265352

266353
destroy(): void {
267-
if (this.rebuildTimer) {
268-
window.clearTimeout(this.rebuildTimer);
269-
this.rebuildTimer = 0;
270-
}
271-
this.pendingView = null;
272354
this.lineCache.clear();
273355
this.styleCache.clear();
274356
}
@@ -288,6 +370,9 @@ const indentGuidesTheme = EditorView.baseTheme({
288370
display: "inline-block",
289371
verticalAlign: "top",
290372
},
373+
".cm-indent-guides-line": {
374+
backgroundOrigin: "content-box",
375+
},
291376
"&": {
292377
"--indent-guide-color": "rgba(128, 128, 128, 0.25)",
293378
},

0 commit comments

Comments
 (0)