@typbase/codemirror 0.4.0 → 0.4.2

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
@@ -1593,8 +1624,9 @@ const SCROLLBAR_ALLOWANCE = 12;
1593
1624
  function editorRenderWidth(scrollDOM, contentDOM) {
1594
1625
  const pane = scrollDOM.getBoundingClientRect();
1595
1626
  const gutters = scrollDOM.querySelector(".cm-gutters");
1596
- const style = getComputedStyle(contentDOM);
1597
- return Math.max(0, pane.width - (gutters?.getBoundingClientRect().width ?? 0) - parseFloat(style.paddingLeft) - parseFloat(style.paddingRight) - SCROLLBAR_ALLOWANCE);
1627
+ const contentStyle = getComputedStyle(contentDOM);
1628
+ const scrollStyle = getComputedStyle(scrollDOM);
1629
+ return Math.max(0, pane.width - (gutters?.getBoundingClientRect().width ?? 0) - parseFloat(contentStyle.paddingLeft) - parseFloat(contentStyle.paddingRight) - parseFloat(scrollStyle.paddingLeft) - parseFloat(scrollStyle.paddingRight) - SCROLLBAR_ALLOWANCE);
1598
1630
  }
1599
1631
  const tooltipsStateEffect = StateEffect.define();
1600
1632
  const tooltipsStateField = StateField.define({
@@ -1952,6 +1984,37 @@ const tooltipViewPlugin = () => ViewPlugin.define((view) => ({ update(update) {
1952
1984
  } }));
1953
1985
  //#endregion
1954
1986
  //#region src/plugin.ts
1987
+ const bracketPairs = {
1988
+ "(": ")",
1989
+ "[": "]",
1990
+ "{": "}",
1991
+ $: "$"
1992
+ };
1993
+ const typstEditingExtensions = [EditorView.inputHandler.of((view, from, to, text) => {
1994
+ if (text !== " " || from !== to) return false;
1995
+ const { state } = view;
1996
+ const { main } = state.selection;
1997
+ if (!main.empty) return false;
1998
+ const pos = main.head;
1999
+ const before = state.doc.sliceString(pos - 1, pos);
2000
+ const after = state.doc.sliceString(pos, pos + 1);
2001
+ if (!bracketPairs[before] || after !== bracketPairs[before]) return false;
2002
+ view.dispatch({
2003
+ changes: {
2004
+ from: pos,
2005
+ to: pos,
2006
+ insert: " "
2007
+ },
2008
+ selection: { anchor: pos + 1 }
2009
+ });
2010
+ return true;
2011
+ }), indentService.of((ctx, pos) => {
2012
+ const last = Math.max(0, pos - 1);
2013
+ const prev = ctx.lineAt(last).text;
2014
+ if (prev.endsWith("$") && prev !== "$") return 0;
2015
+ const indent = /[{[($]\s*$/.test(prev);
2016
+ return ctx.lineIndent(last) + (indent ? ctx.unit : 0);
2017
+ })];
1955
2018
  const typstPlugin = (fileId, spaceId, path, text, prelude, locked, typstState, options = {}) => {
1956
2019
  const extensions = [
1957
2020
  typstStateField,
@@ -1965,41 +2028,11 @@ const typstPlugin = (fileId, spaceId, path, text, prelude, locked, typstState, o
1965
2028
  typstSourceSync(fileId, prelude, typstState),
1966
2029
  typstSyntaxHighlighting(fileId, typstState),
1967
2030
  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
- })
2031
+ typstEditingExtensions
1976
2032
  ];
1977
2033
  if (options.notebook) extensions.push(notebookOptionsFacet.of(options.notebook), notebookKeymap);
1978
2034
  return extensions;
1979
2035
  };
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
2036
  //#endregion
2004
2037
  //#region src/static-highlight.ts
2005
2038
  const KEYWORDS = /* @__PURE__ */ new Set([
@@ -2331,4 +2364,4 @@ function stringEnd(line, from) {
2331
2364
  return line.length;
2332
2365
  }
2333
2366
  //#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 };
2367
+ 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.2",
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.2"
44
44
  },
45
45
  "scripts": {
46
46
  "build": "tsdown",