@bhsd/codemirror-stickyscroll 0.1.0 → 0.1.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/README.md CHANGED
@@ -2,11 +2,7 @@
2
2
 
3
3
  > VS Code / Monaco-style **sticky scroll** (sticky lines) for [CodeMirror 6](https://codemirror.net/).
4
4
 
5
- <p align="center">
6
- <img src="preview/image.png" alt="Sticky Scroll Preview" width="750" />
7
- </p>
8
-
9
- This is a fork of [@fazelstudio/codemirror-stickyscroll](https://github.com/fazel-studio/codemirror-stickyscroll).
5
+ This is a fork of [@fazelstudio/codemirror-stickyscroll](https://github.com/fazelstudio/codemirror-stickyscroll) that adds support for [foldService](https://codemirror.net/docs/ref/#language.foldService), which makes it compatible with legacy [StreamParser](https://codemirror.net/docs/ref/#language.StreamParser) languages that register folding.
10
6
 
11
7
  Sticky lines keep the *opening* lines of the enclosing scopes (function, class,
12
8
  if/loop blocks, …) pinned at the top of the editor while you scroll — exactly
@@ -24,7 +20,7 @@ extension** (no fork of `@codemirror/*`).
24
20
  *active* highlight styles of the editor (`highlightingFor`), or clones the
25
21
  already-rendered DOM line when available. The package **never** registers its
26
22
  own `syntaxHighlighting(...)`.
27
- - **Language-agnostic** — detection is based on `foldable()` from
23
+ - **Language-agnostic** — detection is based on `foldNodeProp` or `foldService` from
28
24
  `@codemirror/language` (the fold services / fold node props that every
29
25
  `@codemirror/lang-*` already registers). It includes a smart, generic denylist
30
26
  that works across multiple languages (JS/TS, Python, Rust, Go, etc.) out of the box,
@@ -45,11 +41,9 @@ has a working CodeMirror 6 editor):
45
41
 
46
42
  | Package | Minimum |
47
43
  | --- | --- |
48
- | `@codemirror/view` | ^6.0.0 |
44
+ | `@codemirror/view` | ^6.3.0 |
49
45
  | `@codemirror/state` | ^6.0.0 |
50
46
  | `@codemirror/language` | ^6.0.0 |
51
- | `@lezer/common` | ^1.0.0 |
52
- | `@lezer/highlight` | ^1.0.0 |
53
47
 
54
48
  ## API
55
49
 
@@ -59,7 +53,7 @@ has a working CodeMirror 6 editor):
59
53
  interface StickyScrollOptions {
60
54
  /** Maximum sticky lines shown at once (dynamically clamped to ~40% of editor height). Default: 4 */
61
55
  maxStickyLines?: number;
62
- /** Minimum lines a scope must span to become sticky. Default: 2 */
56
+ /** Minimum lines a scope must span to become sticky. Default: 6 */
63
57
  minBlockLines?: number;
64
58
  /**
65
59
  * Denylist predicate: return true to never pin a foldable node of that type.
@@ -67,11 +61,7 @@ interface StickyScrollOptions {
67
61
  * It uses exact node names for JS/TS and generic regex patterns for other
68
62
  * languages, while automatically bypassing the literal denylist for JSON.
69
63
  */
70
- excludeNode?: (nodeName: string, langName: string | undefined) => boolean;
71
- /** Extra HighlightStyle merged in when a line is re-highlighted from scratch. */
72
- highlightStyle?: HighlightStyle;
73
- /** Called after a sticky line is clicked (after the jump is dispatched). */
74
- onLineClick?: (lineNumber: number) => void;
64
+ excludeNode?: (nodeName?: string, langName?: string, ownerName?: string) => boolean;
75
65
  /** Extra CSS class(es) for the bar container. */
76
66
  class?: string;
77
67
  }
@@ -105,15 +95,14 @@ Per-row hooks:
105
95
  | `.cm-stickyscroll-line:hover` | hover highlight |
106
96
  | `.cm-stickyscroll-line.cm-stickyscroll-current` | block containing the cursor |
107
97
  | `.cm-stickyscroll-gutter` | line-number cell |
108
- | `.cm-stickyscroll-text` | code column (horizontally synced) |
98
+ | `.cm-stickyscroll-code` | code column (horizontally synced) |
109
99
 
110
100
  ## How it works
111
101
 
112
- 1. **Detect the top line** — `view.lineBlockAtHeight(scrollTop - documentTop)`.
102
+ 1. **Detect the top line** — `view.lineBlockAtHeight(clientTop - documentTop)`.
113
103
  2. **Walk the syntax tree** — from `syntaxTree(state).resolveInner(topPos, 0)`
114
104
  up through `node.parent`.
115
- 3. **A scope qualifies when** its opening line is *foldable*
116
- (`foldable(state, line.from, line.to)` from `@codemirror/language`), its fold
105
+ 3. **A scope qualifies when** its opening line is *foldable*, its fold
117
106
  anchor node is not denylisted, and it spans ≥ `minBlockLines`.
118
107
  4. **Render** — a `ViewPlugin` owns an absolutely-positioned overlay
119
108
  (`position: absolute; top: 0` inside `view.dom`), updated per-frame from the
package/dist/compute.js CHANGED
@@ -7,6 +7,11 @@ import { ensureSyntaxTree, foldNodeProp, foldService, language, syntaxTree } fro
7
7
  * reveal; once the tree covers the position the cost is O(1).
8
8
  */
9
9
  const PARSE_TIMEOUT = 25;
10
+ /**
11
+ * Maximum number of lines to scan for foldable blocks when any fold service is
12
+ * registered.
13
+ */
14
+ const MAX_SERVICE_SCAN_LINES = 100;
10
15
  /**
11
16
  * Return the best syntax tree we can answer a query at `pos` with right now.
12
17
  *
@@ -57,7 +62,7 @@ export function getStickyContext(view, config) {
57
62
  const lineHeight = Math.round(view.defaultLineHeight) || 16;
58
63
  const maxDynamic = Math.max(1, Math.floor(view.scrollDOM.clientHeight * 0.4 / lineHeight));
59
64
  const maxSticky = Math.min(config.maxStickyLines, maxDynamic);
60
- return getStickyContextForRange(view, topBlock.from, config, parseTree, maxSticky);
65
+ return getStickyContextForRange(state, topBlock.from, config, parseTree, maxSticky);
61
66
  }
62
67
  /**
63
68
  * Pure version of the algorithm.
@@ -66,7 +71,7 @@ export function getStickyContext(view, config) {
66
71
  * already-extended tree (see `getStickyContext`) to compute against a parse
67
72
  * that is known to cover `fromPos`.
68
73
  */
69
- function getStickyContextForRange({ state, viewport }, fromPos, config, t, maxSticky) {
74
+ function getStickyContextForRange(state, fromPos, config, t, maxSticky) {
70
75
  const lang = state.facet(language);
71
76
  if (!lang)
72
77
  return [];
@@ -129,10 +134,9 @@ function getStickyContextForRange({ state, viewport }, fromPos, config, t, maxSt
129
134
  }
130
135
  }
131
136
  else {
132
- for (let openLine = topLineNumber - 1; openLine > 0; openLine--) {
137
+ const minLineNumber = Math.max(0, topLineNumber - MAX_SERVICE_SCAN_LINES);
138
+ for (let openLine = topLineNumber - 1; openLine > minLineNumber; openLine--) {
133
139
  const open = doc.line(openLine);
134
- if (open.to < viewport.from)
135
- break;
136
140
  const ownerName = open.text.trim();
137
141
  if (!exclude(undefined, langName, ownerName)) {
138
142
  for (const service of services) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bhsd/codemirror-stickyscroll",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "VS Code / Monaco-style sticky scroll (sticky lines) extension for CodeMirror 6",
5
5
  "keywords": [
6
6
  "codemirror",
@@ -44,9 +44,9 @@
44
44
  "@codemirror/language": "^6.12.4",
45
45
  "@codemirror/state": "^6.7.1",
46
46
  "@codemirror/view": "^6.43.9",
47
- "eslint": "^10.9.1",
47
+ "eslint": "^10.10.0",
48
48
  "markdownlint-cli2": "^0.23.2",
49
- "stylelint": "^17.14.1",
49
+ "stylelint": "^17.15.0",
50
50
  "typescript": "^6.0.3"
51
51
  }
52
52
  }