@typbase/codemirror 0.4.0 → 0.4.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/dist/index.d.mts CHANGED
@@ -171,6 +171,7 @@ interface TextRef {
171
171
  type TypstRequestHandler = (requests: import("@typbase/engine").TypstRequest[], spaceId: string) => Promise<boolean> | boolean;
172
172
  //#endregion
173
173
  //#region src/plugin.d.ts
174
+ export declare const typstEditingExtensions: Extension;
174
175
  export interface TypstPluginOptions {
175
176
  /**
176
177
  * Called when Typst needs a source, file, or package that is not loaded
@@ -331,6 +332,17 @@ export declare const typstHoverTooltip: (fileId: FileId, typstState: TypstState)
331
332
  };
332
333
  //#endregion
333
334
  //#region src/keymap.d.ts
335
+ /**
336
+ * Whether the editor is running vim bindings. Vim handles keys from a DOM
337
+ * listener that CodeMirror's keymap runs before, so Escape has to be left
338
+ * unhandled or it never reaches the vim plugin. Set through the same
339
+ * compartment as the vim extension.
340
+ */
341
+ export declare const vimKeymapFacet: Facet<boolean, boolean>;
342
+ /**
343
+ * The app's shortcuts dialog mirrors the common entries here. When a chord
344
+ * changes, update `EDITOR_SHORTCUTS` in `apps/web/src/lib/keybindings.ts` too.
345
+ */
334
346
  export declare const typstKeymap: import("@codemirror/state").Extension;
335
347
  //#endregion
336
348
  //#region src/language.d.ts
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { acceptCompletion, autocompletion, closeBracketsKeymap, completionKeymap, snippet, startCompletion } from "@codemirror/autocomplete";
1
+ import { acceptCompletion, autocompletion, closeBracketsKeymap, closeCompletion, completionKeymap, snippet, startCompletion } from "@codemirror/autocomplete";
2
2
  import { indentService } from "@codemirror/language";
3
3
  import { Decoration, EditorView, ViewPlugin, WidgetType, hoverTooltip, keymap, showTooltip } from "@codemirror/view";
4
4
  import { ChangeSet, EditorSelection, EditorState, Facet, RangeSetBuilder, StateEffect, StateField, countColumn, findColumn } from "@codemirror/state";
@@ -20,15 +20,29 @@ const typstSyntaxHighlighting = (fileId, typstState) => StateField.define({
20
20
  }
21
21
  });
22
22
  function buildDecorations$2(state, fileId, typstState) {
23
- const builder = new RangeSetBuilder();
24
23
  let tokens;
24
+ let equations;
25
25
  try {
26
26
  tokens = typstState.highlight(fileId, state.doc.toString());
27
+ equations = typstState.extractEquations(fileId, state.doc.toString());
27
28
  } catch (error) {
28
29
  console.error("[typst] highlight panicked:", error);
29
30
  return Decoration.none;
30
31
  }
31
- for (const token of tokens) builder.add(token.range.start, token.range.end, Decoration.mark({ class: token.tag }));
32
+ const builder = new RangeSetBuilder();
33
+ const equationMark = Decoration.mark({ class: "typ-equation" });
34
+ let nextEquation = 0;
35
+ for (const token of tokens) {
36
+ while (nextEquation < equations.length && equations[nextEquation].from <= token.range.start) {
37
+ const equation = equations[nextEquation++];
38
+ builder.add(equation.from, equation.to, equationMark);
39
+ }
40
+ builder.add(token.range.start, token.range.end, Decoration.mark({ class: token.tag }));
41
+ }
42
+ for (; nextEquation < equations.length; nextEquation++) {
43
+ const equation = equations[nextEquation];
44
+ builder.add(equation.from, equation.to, equationMark);
45
+ }
32
46
  return builder.finish();
33
47
  }
34
48
  const parseBackticks = (str, into) => {
@@ -372,8 +386,19 @@ function cursorAddVertical(view, offset) {
372
386
  }
373
387
  //#endregion
374
388
  //#region src/keymap.ts
389
+ /**
390
+ * Whether the editor is running vim bindings. Vim handles keys from a DOM
391
+ * listener that CodeMirror's keymap runs before, so Escape has to be left
392
+ * unhandled or it never reaches the vim plugin. Set through the same
393
+ * compartment as the vim extension.
394
+ */
395
+ const vimKeymapFacet = Facet.define({ combine: (values) => values.some(Boolean) });
396
+ /**
397
+ * The app's shortcuts dialog mirrors the common entries here. When a chord
398
+ * changes, update `EDITOR_SHORTCUTS` in `apps/web/src/lib/keybindings.ts` too.
399
+ */
375
400
  const typstKeymap = keymap.of([
376
- ...completionKeymap,
401
+ ...completionKeymap.filter((binding) => binding.key !== "Escape"),
377
402
  ...closeBracketsKeymap,
378
403
  {
379
404
  key: "Tab",
@@ -488,7 +513,13 @@ const typstKeymap = keymap.of([
488
513
  },
489
514
  {
490
515
  key: "Escape",
491
- run: simplifySelection
516
+ run: (view) => {
517
+ if (view.state.facet(vimKeymapFacet)) {
518
+ closeCompletion(view);
519
+ return false;
520
+ }
521
+ return closeCompletion(view) || simplifySelection(view);
522
+ }
492
523
  },
493
524
  {
494
525
  key: "Mod-Alt-ArrowUp",
@@ -524,7 +555,7 @@ const typstKeymap = keymap.of([
524
555
  run: selectNextOccurrence,
525
556
  preventDefault: true
526
557
  },
527
- ...standardKeymap
558
+ ...standardKeymap.filter((binding) => binding.key !== "Escape")
528
559
  ]);
529
560
  //#endregion
530
561
  //#region src/language.ts
@@ -1950,8 +1981,35 @@ const tooltipViewPlugin = () => ViewPlugin.define((view) => ({ update(update) {
1950
1981
  view.dispatch({ effects: tooltipStateEffect.of(tooltip) });
1951
1982
  });
1952
1983
  } }));
1953
- //#endregion
1954
- //#region src/plugin.ts
1984
+ const typstEditingExtensions = [EditorView.inputHandler.of((view, from, to, text) => {
1985
+ if (text !== " " || from !== to) return false;
1986
+ const { state } = view;
1987
+ const pos = from;
1988
+ const bracketPairs = {
1989
+ "(": ")",
1990
+ "[": "]",
1991
+ "{": "}",
1992
+ $: "$"
1993
+ };
1994
+ const before = state.doc.sliceString(pos - 1, pos);
1995
+ const after = state.doc.sliceString(pos, pos + 1);
1996
+ if (!bracketPairs[before] || after !== bracketPairs[before]) return false;
1997
+ view.dispatch({
1998
+ changes: {
1999
+ from: pos,
2000
+ to: pos,
2001
+ insert: " "
2002
+ },
2003
+ selection: { anchor: pos + 1 }
2004
+ });
2005
+ return true;
2006
+ }), indentService.of((ctx, pos) => {
2007
+ const last = Math.max(0, pos - 1);
2008
+ const prev = ctx.lineAt(last).text;
2009
+ if (prev.endsWith("$") && prev !== "$") return 0;
2010
+ const indent = /[{[($]\s*$/.test(prev);
2011
+ return ctx.lineIndent(last) + (indent ? ctx.unit : 0);
2012
+ })];
1955
2013
  const typstPlugin = (fileId, spaceId, path, text, prelude, locked, typstState, options = {}) => {
1956
2014
  const extensions = [
1957
2015
  typstStateField,
@@ -1965,41 +2023,11 @@ const typstPlugin = (fileId, spaceId, path, text, prelude, locked, typstState, o
1965
2023
  typstSourceSync(fileId, prelude, typstState),
1966
2024
  typstSyntaxHighlighting(fileId, typstState),
1967
2025
  typstHoverTooltip(fileId, typstState),
1968
- addSpaceBeforeClosingBracket,
1969
- indentService.of((ctx, pos) => {
1970
- const last = Math.max(0, pos - 1);
1971
- const prev = ctx.lineAt(last).text;
1972
- if (prev.endsWith("$") && prev !== "$") return 0;
1973
- const indent = /[{[($]\s*$/.test(prev);
1974
- return ctx.lineIndent(last) + (indent ? ctx.unit : 0);
1975
- })
2026
+ typstEditingExtensions
1976
2027
  ];
1977
2028
  if (options.notebook) extensions.push(notebookOptionsFacet.of(options.notebook), notebookKeymap);
1978
2029
  return extensions;
1979
2030
  };
1980
- const addSpaceBeforeClosingBracket = EditorView.inputHandler.of((view, from, to, text) => {
1981
- if (text === " ") {
1982
- const { state } = view;
1983
- const pos = from;
1984
- const bracketPairs = {
1985
- "(": ")",
1986
- "[": "]",
1987
- "{": "}",
1988
- $: "$"
1989
- };
1990
- const before = state.doc.sliceString(pos - 1, pos);
1991
- const after = state.doc.sliceString(pos, pos + 1);
1992
- if (bracketPairs[before] && after === bracketPairs[before]) view.dispatch({
1993
- changes: {
1994
- from: pos,
1995
- to: pos,
1996
- insert: " "
1997
- },
1998
- selection: { anchor: pos + 1 }
1999
- });
2000
- }
2001
- return false;
2002
- });
2003
2031
  //#endregion
2004
2032
  //#region src/static-highlight.ts
2005
2033
  const KEYWORDS = /* @__PURE__ */ new Set([
@@ -2331,4 +2359,4 @@ function stringEnd(line, from) {
2331
2359
  return line.length;
2332
2360
  }
2333
2361
  //#endregion
2334
- export { NOTEBOOK_CELL_TYPES, TypstWidget, attachFrameInteractions, attributeText, autocomplete, cellIndexAt, cellStart, cellsOf, compileCache, createFrameContainer, currentCell, cursorAddVertical, cycleHeading, deleteCell, deleteCellText, duplicateCell, duplicateCellText, focusCell, frameActiveDecorations, frameIsInactive, frameSize, hasAttribute, hasOutput, hidesSource, insertAtCursor, insertCell, insertCellText, insertFontFamily, insertTabLike, installSharedDefs, mergeCell, mergeCellText, moveCell, notebookKeymap, notebookOptions, notebookOptionsFacet, notebookRefreshEffect, parseBackticks, rememberDiagnostics, rendersInPlace, setCellType, setCellTypeText, splitCell, splitCellText, stripCellAttributes, syncFrameContainer, toLintDiagnostics, toggleAroundSelection, toggleCode, toggleEmph, toggleEnum, toggleList, toggleListLike, toggleMath, toggleStrike, toggleStrong, toggleUnderline, tooltipStateField, tooltipViewPlugin, tooltipsStateEffect, tooltipsStateField, typstHoverTooltip, typstKeymap, typstLanguageData, typstLinter, typstPlugin, typstRecompileEffect, typstSourceSync, typstStateField, typstStaticHighlighting, typstSyntaxHighlighting, typstViewPlugin, wrapOrInsert };
2362
+ export { NOTEBOOK_CELL_TYPES, TypstWidget, attachFrameInteractions, attributeText, autocomplete, cellIndexAt, cellStart, cellsOf, compileCache, createFrameContainer, currentCell, cursorAddVertical, cycleHeading, deleteCell, deleteCellText, duplicateCell, duplicateCellText, focusCell, frameActiveDecorations, frameIsInactive, frameSize, hasAttribute, hasOutput, hidesSource, insertAtCursor, insertCell, insertCellText, insertFontFamily, insertTabLike, installSharedDefs, mergeCell, mergeCellText, moveCell, notebookKeymap, notebookOptions, notebookOptionsFacet, notebookRefreshEffect, parseBackticks, rememberDiagnostics, rendersInPlace, setCellType, setCellTypeText, splitCell, splitCellText, stripCellAttributes, syncFrameContainer, toLintDiagnostics, toggleAroundSelection, toggleCode, toggleEmph, toggleEnum, toggleList, toggleListLike, toggleMath, toggleStrike, toggleStrong, toggleUnderline, tooltipStateField, tooltipViewPlugin, tooltipsStateEffect, tooltipsStateField, typstEditingExtensions, typstHoverTooltip, typstKeymap, typstLanguageData, typstLinter, typstPlugin, typstRecompileEffect, typstSourceSync, typstStateField, typstStaticHighlighting, typstSyntaxHighlighting, typstViewPlugin, vimKeymapFacet, wrapOrInsert };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typbase/codemirror",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "CodeMirror 6 editing experience for Typst: WYSIWYG inline preview, highlighting, hover, autocomplete.",
5
5
  "keywords": [
6
6
  "atproto",
@@ -40,7 +40,7 @@
40
40
  "typescript": "^5.9.3"
41
41
  },
42
42
  "peerDependencies": {
43
- "@typbase/engine": "^0.4.0"
43
+ "@typbase/engine": "^0.4.1"
44
44
  },
45
45
  "scripts": {
46
46
  "build": "tsdown",