monaco-line-locks 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 +191 -0
- package/dist/index.d.ts +61 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +241 -0
- package/dist/index.js.map +1 -0
- package/dist/react.d.ts +24 -0
- package/dist/react.d.ts.map +1 -0
- package/dist/react.js +43 -0
- package/dist/react.js.map +1 -0
- package/package.json +53 -0
package/README.md
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# monaco-line-locks
|
|
2
|
+
|
|
3
|
+
Lock specific lines in Monaco Editor to prevent editing. A lightweight alternative to constrained-editor-plugin with a simpler mental model.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Lock by line number** — blacklist approach (vs editable ranges whitelist)
|
|
8
|
+
- **Prevents edits** via keyboard blocking (not undo-after-the-fact)
|
|
9
|
+
- **Auto-adjusts** locked line positions when document changes
|
|
10
|
+
- **Visual feedback** — CSS decorations for locked lines + gutter icons
|
|
11
|
+
- **React hook** included
|
|
12
|
+
- **No model monkey-patching**
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# pnpm (recommended)
|
|
18
|
+
pnpm add monaco-line-locks
|
|
19
|
+
|
|
20
|
+
# npm
|
|
21
|
+
npm install monaco-line-locks
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Basic Usage
|
|
25
|
+
|
|
26
|
+
### Vanilla JS
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
import { LineLockManager } from 'monaco-line-locks'
|
|
30
|
+
import * as monaco from 'monaco-editor'
|
|
31
|
+
|
|
32
|
+
const editor = monaco.editor.create(document.getElementById('editor'), {
|
|
33
|
+
value: '// Line 1\n// Line 2\n// Line 3',
|
|
34
|
+
language: 'javascript',
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
const locks = new LineLockManager(monaco, editor, {
|
|
38
|
+
lockedLines: [2], // Lock line 2
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
// Later: update locks
|
|
42
|
+
locks.setLockedLines([2, 3])
|
|
43
|
+
|
|
44
|
+
// Get current locks
|
|
45
|
+
console.log(locks.getLockedLines()) // [2, 3]
|
|
46
|
+
|
|
47
|
+
// Cleanup
|
|
48
|
+
locks.dispose()
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### React
|
|
52
|
+
|
|
53
|
+
```tsx
|
|
54
|
+
import { useLineLocks } from 'monaco-line-locks/react'
|
|
55
|
+
import { useState } from 'react'
|
|
56
|
+
import Editor from '@monaco-editor/react'
|
|
57
|
+
|
|
58
|
+
function MyEditor() {
|
|
59
|
+
const [lockedLines, setLockedLines] = useState([3, 5])
|
|
60
|
+
|
|
61
|
+
const handleMount = (editor, monaco) => {
|
|
62
|
+
useLineLocks(editor, monaco, lockedLines, {
|
|
63
|
+
onChange: setLockedLines,
|
|
64
|
+
})
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return <Editor onMount={handleMount} />
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## CSS
|
|
72
|
+
|
|
73
|
+
Add these classes to your stylesheet:
|
|
74
|
+
|
|
75
|
+
```css
|
|
76
|
+
/* Yellow background on locked lines */
|
|
77
|
+
.locked-line {
|
|
78
|
+
background: rgba(255, 200, 0, 0.06);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/* Lock icon in gutter (requires Codicon font) */
|
|
82
|
+
.locked-deco::before {
|
|
83
|
+
content: '\ea75';
|
|
84
|
+
font-family: 'codicon';
|
|
85
|
+
font-size: 12px;
|
|
86
|
+
color: rgba(255, 200, 0, 0.7);
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## API
|
|
91
|
+
|
|
92
|
+
### `LineLockManager`
|
|
93
|
+
|
|
94
|
+
| Method | Description |
|
|
95
|
+
| --------------------------------------- | ---------------------------------------------------------- |
|
|
96
|
+
| `constructor(monaco, editor, options?)` | Create manager |
|
|
97
|
+
| `setLockedLines(lines)` | Replace all locked lines |
|
|
98
|
+
| `getLockedLines()` | Get sorted copy of current locks |
|
|
99
|
+
| `hasLockInRange(start, end)` | Check if any line in [start, end] is locked — **O(log L)** |
|
|
100
|
+
| `dispose()` | Cleanup listeners and decorations |
|
|
101
|
+
|
|
102
|
+
### Options
|
|
103
|
+
|
|
104
|
+
| Option | Type | Default | Description |
|
|
105
|
+
| --------------------------- | --------------------------- | ----------------------- | ----------------------------------------- |
|
|
106
|
+
| `lockedLines` | `number[]` | `[]` | Initial locked line numbers |
|
|
107
|
+
| `decorationClassName` | `string` | `'locked-line'` | CSS class for line background |
|
|
108
|
+
| `decorationGutterClassName` | `string` | `'locked-deco'` | CSS class for gutter icon |
|
|
109
|
+
| `hoverMessage` | `string \| IMarkdownString` | `'This line is locked'` | Message when trying to edit a locked line |
|
|
110
|
+
| `blockKeyboard` | `boolean` | `true` | Block keyboard input on locked lines |
|
|
111
|
+
| `blockMouse` | `boolean` | `false` | Block mouse input on locked lines |
|
|
112
|
+
| `onChange` | `(lines: number[]) => void` | — | Called when locks change due to edits |
|
|
113
|
+
|
|
114
|
+
## How it works
|
|
115
|
+
|
|
116
|
+
1. **Keyboard blocking** — `onKeyDown` listener prevents typing/deleting on locked lines via binary search (O(log L))
|
|
117
|
+
2. **Line tracking** — `onDidChangeModelContent` adjusts lock positions when lines are inserted/deleted
|
|
118
|
+
3. **Decorations** — Monaco `deltaDecorations` for visual feedback
|
|
119
|
+
|
|
120
|
+
## Differences from constrained-editor-plugin
|
|
121
|
+
|
|
122
|
+
| | constrained-editor-plugin | monaco-line-locks |
|
|
123
|
+
| ---------- | --------------------------- | ------------------------- |
|
|
124
|
+
| Approach | Editable ranges (whitelist) | Locked lines (blacklist) |
|
|
125
|
+
| Validation | Undo after invalid edit | Prevent before it happens |
|
|
126
|
+
| Model | Monkey-patched | Clean |
|
|
127
|
+
| Columns | Full range support | Line-level only |
|
|
128
|
+
| Size | ~15KB | ~2KB |
|
|
129
|
+
|
|
130
|
+
## Development
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
# Clone the repo
|
|
134
|
+
git clone https://github.com/yourusername/monaco-line-locks.git
|
|
135
|
+
cd monaco-line-locks
|
|
136
|
+
|
|
137
|
+
# Install dependencies
|
|
138
|
+
pnpm install
|
|
139
|
+
|
|
140
|
+
# Run tests
|
|
141
|
+
pnpm test
|
|
142
|
+
|
|
143
|
+
# Type check
|
|
144
|
+
pnpm exec tsc --noEmit
|
|
145
|
+
|
|
146
|
+
# Check for unused code
|
|
147
|
+
pnpm knip
|
|
148
|
+
|
|
149
|
+
# Build for publish
|
|
150
|
+
pnpm run build
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Examples
|
|
154
|
+
|
|
155
|
+
### Basic (Vanilla JS)
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
# Build the library first
|
|
159
|
+
pnpm run build
|
|
160
|
+
|
|
161
|
+
# Serve the example (browsers block file:// URLs for ES modules)
|
|
162
|
+
cd examples
|
|
163
|
+
pnpm install
|
|
164
|
+
pnpm run serve:basic
|
|
165
|
+
# Open http://localhost:3000
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### React
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
cd examples
|
|
172
|
+
pnpm install
|
|
173
|
+
pnpm run serve:react
|
|
174
|
+
# Open http://localhost:5173
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Contributing
|
|
178
|
+
|
|
179
|
+
Issues and PRs welcome. Focus areas:
|
|
180
|
+
|
|
181
|
+
- Mouse/paste blocking
|
|
182
|
+
- Multi-cursor support
|
|
183
|
+
- Performance benchmarks
|
|
184
|
+
|
|
185
|
+
## Changelog
|
|
186
|
+
|
|
187
|
+
See [CHANGELOG.md](./CHANGELOG.md)
|
|
188
|
+
|
|
189
|
+
## License
|
|
190
|
+
|
|
191
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type * as monacoEditor from 'monaco-editor';
|
|
2
|
+
export interface LineLockOptions {
|
|
3
|
+
/** Initial locked line numbers (1-indexed) */
|
|
4
|
+
lockedLines?: number[];
|
|
5
|
+
/** CSS class for the line background decoration */
|
|
6
|
+
decorationClassName?: string;
|
|
7
|
+
/** CSS class for the gutter decoration (lock icon) */
|
|
8
|
+
decorationGutterClassName?: string;
|
|
9
|
+
/** Message shown when trying to edit a locked line (default: "This line is locked") */
|
|
10
|
+
hoverMessage?: string | monacoEditor.IMarkdownString;
|
|
11
|
+
/** Whether to block keyboard input on locked lines (default: true) */
|
|
12
|
+
blockKeyboard?: boolean;
|
|
13
|
+
/** Whether to block mouse input on locked lines (default: false) */
|
|
14
|
+
blockMouse?: boolean;
|
|
15
|
+
/** Called whenever locked lines change due to document edits */
|
|
16
|
+
onChange?: (lines: number[]) => void;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Variables:
|
|
20
|
+
* L = total number of lines in the document
|
|
21
|
+
* S = number of lines in the current selection (S ≤ L)
|
|
22
|
+
* D = number of deleted lines in a change (D ≤ L)
|
|
23
|
+
* C = number of changes in a batch
|
|
24
|
+
*/
|
|
25
|
+
export declare class LineLockManager {
|
|
26
|
+
private monaco;
|
|
27
|
+
private editor;
|
|
28
|
+
private options;
|
|
29
|
+
private lockedLinesSet;
|
|
30
|
+
private lockedLinesSorted;
|
|
31
|
+
private decorations;
|
|
32
|
+
private disposables;
|
|
33
|
+
constructor(monaco: typeof monacoEditor, editor: monacoEditor.editor.IStandaloneCodeEditor, options?: LineLockOptions);
|
|
34
|
+
/** Filter lines outside the current model's bounds */
|
|
35
|
+
private clampLines;
|
|
36
|
+
/** O(L log L) — sorts at most L locked lines */
|
|
37
|
+
private sortLines;
|
|
38
|
+
/** O(L) — registers listeners and applies decorations (at most L locked lines) */
|
|
39
|
+
private init;
|
|
40
|
+
/** O(log L) per keystroke — binary search over at most L locked lines */
|
|
41
|
+
private setupKeyboardBlocking;
|
|
42
|
+
/** O(1) — registers the content change listener */
|
|
43
|
+
private setupLineTracking;
|
|
44
|
+
/** O(C·(D + L) + L log L) = O(C·L + L log L) — worst case */
|
|
45
|
+
private adjustLocks;
|
|
46
|
+
/** O(L) — applies Monaco deltaDecorations for at most L locked lines */
|
|
47
|
+
private updateDecorations;
|
|
48
|
+
/** O(L log L) — replace all locked lines (at most L) and update decorations */
|
|
49
|
+
setLockedLines(lines: number[]): void;
|
|
50
|
+
/** O(log L) — check if any line in [start, end] is locked (binary search over ≤ L lines) */
|
|
51
|
+
hasLockInRange(start: number, end: number): boolean;
|
|
52
|
+
/** O(log L) — binary search over at most L locked lines */
|
|
53
|
+
private lowerBound;
|
|
54
|
+
/** Show message overlay at cursor position using Monaco's MessageController */
|
|
55
|
+
private showLockMessage;
|
|
56
|
+
/** O(L) — copy at most L locked lines */
|
|
57
|
+
getLockedLines(): number[];
|
|
58
|
+
/** O(L) — clean up listeners + decorations (at most L locked lines) */
|
|
59
|
+
dispose(): void;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,YAAY,MAAM,eAAe,CAAA;AAElD,MAAM,WAAW,eAAe;IAC9B,8CAA8C;IAC9C,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;IACtB,mDAAmD;IACnD,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,sDAAsD;IACtD,yBAAyB,CAAC,EAAE,MAAM,CAAA;IAClC,uFAAuF;IACvF,YAAY,CAAC,EAAE,MAAM,GAAG,YAAY,CAAC,eAAe,CAAA;IACpD,sEAAsE;IACtE,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,oEAAoE;IACpE,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,gEAAgE;IAChE,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAA;CACrC;AAED;;;;;;GAMG;AAEH,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,MAAM,CAA2C;IACzD,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,cAAc,CAAa;IACnC,OAAO,CAAC,iBAAiB,CAAU;IACnC,OAAO,CAAC,WAAW,CAAU;IAC7B,OAAO,CAAC,WAAW,CAAgB;gBAEjC,MAAM,EAAE,OAAO,YAAY,EAC3B,MAAM,EAAE,YAAY,CAAC,MAAM,CAAC,qBAAqB,EACjD,OAAO,GAAE,eAAoB;IAuB/B,sDAAsD;IACtD,OAAO,CAAC,UAAU;IAOlB,gDAAgD;IAChD,OAAO,CAAC,SAAS;IAIjB,kFAAkF;IAClF,OAAO,CAAC,IAAI;IAQZ,yEAAyE;IACzE,OAAO,CAAC,qBAAqB;IA0D7B,mDAAmD;IACnD,OAAO,CAAC,iBAAiB;IAQzB,6DAA6D;IAC7D,OAAO,CAAC,WAAW;IA+CnB,wEAAwE;IACxE,OAAO,CAAC,iBAAiB;IAoBzB,+EAA+E;IAC/E,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE;IAO9B,4FAA4F;IAC5F,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO;IAKnD,2DAA2D;IAC3D,OAAO,CAAC,UAAU;IAWlB,+EAA+E;IAC/E,OAAO,CAAC,eAAe;IAgBvB,yCAAyC;IACzC,cAAc,IAAI,MAAM,EAAE;IAI1B,uEAAuE;IACvE,OAAO;CAUR"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Variables:
|
|
3
|
+
* L = total number of lines in the document
|
|
4
|
+
* S = number of lines in the current selection (S ≤ L)
|
|
5
|
+
* D = number of deleted lines in a change (D ≤ L)
|
|
6
|
+
* C = number of changes in a batch
|
|
7
|
+
*/
|
|
8
|
+
export class LineLockManager {
|
|
9
|
+
monaco;
|
|
10
|
+
editor;
|
|
11
|
+
options;
|
|
12
|
+
lockedLinesSet;
|
|
13
|
+
lockedLinesSorted;
|
|
14
|
+
decorations;
|
|
15
|
+
disposables;
|
|
16
|
+
constructor(monaco, editor, options = {}) {
|
|
17
|
+
this.monaco = monaco;
|
|
18
|
+
this.editor = editor;
|
|
19
|
+
this.options = {
|
|
20
|
+
lockedLines: [],
|
|
21
|
+
decorationClassName: 'locked-line',
|
|
22
|
+
decorationGutterClassName: 'locked-deco',
|
|
23
|
+
hoverMessage: 'This line is locked',
|
|
24
|
+
blockKeyboard: true,
|
|
25
|
+
blockMouse: false,
|
|
26
|
+
onChange: () => { },
|
|
27
|
+
...options,
|
|
28
|
+
};
|
|
29
|
+
const clamped = this.clampLines(this.options.lockedLines);
|
|
30
|
+
this.lockedLinesSet = new Set(clamped);
|
|
31
|
+
this.lockedLinesSorted = this.sortLines(clamped);
|
|
32
|
+
this.decorations = [];
|
|
33
|
+
this.disposables = [];
|
|
34
|
+
this.init();
|
|
35
|
+
}
|
|
36
|
+
/** Filter lines outside the current model's bounds */
|
|
37
|
+
clampLines(lines) {
|
|
38
|
+
const model = this.editor.getModel();
|
|
39
|
+
if (!model)
|
|
40
|
+
return lines;
|
|
41
|
+
const max = model.getLineCount();
|
|
42
|
+
return lines.filter((l) => l >= 1 && l <= max);
|
|
43
|
+
}
|
|
44
|
+
/** O(L log L) — sorts at most L locked lines */
|
|
45
|
+
sortLines(lines) {
|
|
46
|
+
return [...lines].sort((a, b) => a - b);
|
|
47
|
+
}
|
|
48
|
+
/** O(L) — registers listeners and applies decorations (at most L locked lines) */
|
|
49
|
+
init() {
|
|
50
|
+
if (this.options.blockKeyboard) {
|
|
51
|
+
this.setupKeyboardBlocking();
|
|
52
|
+
}
|
|
53
|
+
this.setupLineTracking();
|
|
54
|
+
this.updateDecorations();
|
|
55
|
+
}
|
|
56
|
+
/** O(log L) per keystroke — binary search over at most L locked lines */
|
|
57
|
+
setupKeyboardBlocking() {
|
|
58
|
+
const NAV = [
|
|
59
|
+
this.monaco.KeyCode.LeftArrow,
|
|
60
|
+
this.monaco.KeyCode.RightArrow,
|
|
61
|
+
this.monaco.KeyCode.UpArrow,
|
|
62
|
+
this.monaco.KeyCode.DownArrow,
|
|
63
|
+
this.monaco.KeyCode.Home,
|
|
64
|
+
this.monaco.KeyCode.End,
|
|
65
|
+
this.monaco.KeyCode.PageUp,
|
|
66
|
+
this.monaco.KeyCode.PageDown,
|
|
67
|
+
this.monaco.KeyCode.Escape,
|
|
68
|
+
];
|
|
69
|
+
const SAFE = [
|
|
70
|
+
this.monaco.KeyCode.KeyA,
|
|
71
|
+
this.monaco.KeyCode.KeyC,
|
|
72
|
+
this.monaco.KeyCode.KeyF,
|
|
73
|
+
this.monaco.KeyCode.KeyH,
|
|
74
|
+
this.monaco.KeyCode.KeyZ,
|
|
75
|
+
];
|
|
76
|
+
const isNav = (k) => NAV.includes(k);
|
|
77
|
+
const isSafe = (k, ctrl) => ctrl && SAFE.includes(k);
|
|
78
|
+
const disposable = this.editor.onKeyDown((e) => {
|
|
79
|
+
const locks = this.lockedLinesSet;
|
|
80
|
+
if (!locks.size)
|
|
81
|
+
return;
|
|
82
|
+
const sel = this.editor.getSelection();
|
|
83
|
+
if (!sel)
|
|
84
|
+
return;
|
|
85
|
+
let start = sel.startLineNumber;
|
|
86
|
+
let end = sel.endLineNumber;
|
|
87
|
+
if (e.keyCode === this.monaco.KeyCode.Backspace) {
|
|
88
|
+
const pos = this.editor.getPosition();
|
|
89
|
+
if (pos?.column === 1)
|
|
90
|
+
start = Math.max(1, start - 1);
|
|
91
|
+
}
|
|
92
|
+
if (e.keyCode === this.monaco.KeyCode.Delete) {
|
|
93
|
+
const pos = this.editor.getPosition();
|
|
94
|
+
const model = this.editor.getModel();
|
|
95
|
+
if (pos && model && pos.column >= model.getLineMaxColumn(pos.lineNumber)) {
|
|
96
|
+
end = Math.min(model.getLineCount(), end + 1);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (this.hasLockInRange(start, end)) {
|
|
100
|
+
if (isNav(e.keyCode) || isSafe(e.keyCode, e.ctrlKey || e.metaKey))
|
|
101
|
+
return;
|
|
102
|
+
this.showLockMessage();
|
|
103
|
+
e.preventDefault();
|
|
104
|
+
e.browserEvent.preventDefault();
|
|
105
|
+
e.browserEvent.stopPropagation();
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
this.disposables.push(() => disposable.dispose());
|
|
110
|
+
}
|
|
111
|
+
/** O(1) — registers the content change listener */
|
|
112
|
+
setupLineTracking() {
|
|
113
|
+
const disposable = this.editor.onDidChangeModelContent((e) => {
|
|
114
|
+
if (e.isFlush)
|
|
115
|
+
return;
|
|
116
|
+
this.adjustLocks(e);
|
|
117
|
+
});
|
|
118
|
+
this.disposables.push(() => disposable.dispose());
|
|
119
|
+
}
|
|
120
|
+
/** O(C·(D + L) + L log L) = O(C·L + L log L) — worst case */
|
|
121
|
+
adjustLocks(e) {
|
|
122
|
+
const locks = this.lockedLinesSet;
|
|
123
|
+
if (!locks.size)
|
|
124
|
+
return;
|
|
125
|
+
let modified = false;
|
|
126
|
+
for (const change of [...e.changes].sort((a, b) => b.range.startLineNumber - a.range.startLineNumber)) {
|
|
127
|
+
const { startLineNumber: start, endLineNumber: end } = change.range;
|
|
128
|
+
const deleted = end - start;
|
|
129
|
+
const inserted = change.text.split('\n').length - 1;
|
|
130
|
+
const delta = inserted - deleted;
|
|
131
|
+
if (!delta && !deleted)
|
|
132
|
+
continue;
|
|
133
|
+
// Remove locks for deleted lines — O(deleted) with Set
|
|
134
|
+
for (let i = 0; i < deleted; i++) {
|
|
135
|
+
if (locks.delete(start + i)) {
|
|
136
|
+
modified = true;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
// Shift locks after the change range — O(locks)
|
|
140
|
+
if (delta) {
|
|
141
|
+
const toShift = [];
|
|
142
|
+
for (const line of locks) {
|
|
143
|
+
if (line >= start + deleted) {
|
|
144
|
+
toShift.push(line);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
for (const line of toShift) {
|
|
148
|
+
locks.delete(line);
|
|
149
|
+
}
|
|
150
|
+
for (const line of toShift) {
|
|
151
|
+
locks.add(line + delta);
|
|
152
|
+
}
|
|
153
|
+
if (toShift.length)
|
|
154
|
+
modified = true;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (modified) {
|
|
158
|
+
this.lockedLinesSorted = this.sortLines([...locks]);
|
|
159
|
+
this.updateDecorations();
|
|
160
|
+
this.options.onChange([...this.lockedLinesSorted]);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/** O(L) — applies Monaco deltaDecorations for at most L locked lines */
|
|
164
|
+
updateDecorations() {
|
|
165
|
+
const model = this.editor.getModel();
|
|
166
|
+
if (!model)
|
|
167
|
+
return;
|
|
168
|
+
this.decorations = model.deltaDecorations(this.decorations, []);
|
|
169
|
+
if (this.lockedLinesSorted.length) {
|
|
170
|
+
const decos = this.lockedLinesSorted.map((line) => ({
|
|
171
|
+
range: new this.monaco.Range(line, 1, line, 1),
|
|
172
|
+
options: {
|
|
173
|
+
isWholeLine: true,
|
|
174
|
+
className: this.options.decorationClassName,
|
|
175
|
+
linesDecorationsClassName: this.options.decorationGutterClassName,
|
|
176
|
+
stickiness: this.monaco.editor.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
|
|
177
|
+
},
|
|
178
|
+
}));
|
|
179
|
+
this.decorations = model.deltaDecorations([], decos);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
/** O(L log L) — replace all locked lines (at most L) and update decorations */
|
|
183
|
+
setLockedLines(lines) {
|
|
184
|
+
const clamped = this.clampLines(lines);
|
|
185
|
+
this.lockedLinesSet = new Set(clamped);
|
|
186
|
+
this.lockedLinesSorted = this.sortLines(clamped);
|
|
187
|
+
this.updateDecorations();
|
|
188
|
+
}
|
|
189
|
+
/** O(log L) — check if any line in [start, end] is locked (binary search over ≤ L lines) */
|
|
190
|
+
hasLockInRange(start, end) {
|
|
191
|
+
const idx = this.lowerBound(this.lockedLinesSorted, start);
|
|
192
|
+
return idx < this.lockedLinesSorted.length && this.lockedLinesSorted[idx] <= end;
|
|
193
|
+
}
|
|
194
|
+
/** O(log L) — binary search over at most L locked lines */
|
|
195
|
+
lowerBound(arr, target) {
|
|
196
|
+
let lo = 0;
|
|
197
|
+
let hi = arr.length;
|
|
198
|
+
while (lo < hi) {
|
|
199
|
+
const mid = (lo + hi) >> 1;
|
|
200
|
+
if (arr[mid] < target)
|
|
201
|
+
lo = mid + 1;
|
|
202
|
+
else
|
|
203
|
+
hi = mid;
|
|
204
|
+
}
|
|
205
|
+
return lo;
|
|
206
|
+
}
|
|
207
|
+
/** Show message overlay at cursor position using Monaco's MessageController */
|
|
208
|
+
showLockMessage() {
|
|
209
|
+
try {
|
|
210
|
+
const ctrl = this.editor.getContribution('editor.contrib.messageController');
|
|
211
|
+
if (ctrl) {
|
|
212
|
+
const msg = this.options.hoverMessage
|
|
213
|
+
? typeof this.options.hoverMessage === 'string'
|
|
214
|
+
? this.options.hoverMessage
|
|
215
|
+
: this.options.hoverMessage.value
|
|
216
|
+
: undefined;
|
|
217
|
+
if (msg)
|
|
218
|
+
ctrl.showMessage(msg, this.editor.getPosition());
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
catch {
|
|
222
|
+
// MessageController may not be available in some Monaco builds
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
/** O(L) — copy at most L locked lines */
|
|
226
|
+
getLockedLines() {
|
|
227
|
+
return [...this.lockedLinesSorted];
|
|
228
|
+
}
|
|
229
|
+
/** O(L) — clean up listeners + decorations (at most L locked lines) */
|
|
230
|
+
dispose() {
|
|
231
|
+
this.disposables.forEach((d) => d());
|
|
232
|
+
this.disposables = [];
|
|
233
|
+
const model = this.editor.getModel();
|
|
234
|
+
if (model) {
|
|
235
|
+
this.decorations = model.deltaDecorations(this.decorations, []);
|
|
236
|
+
}
|
|
237
|
+
this.lockedLinesSet.clear();
|
|
238
|
+
this.lockedLinesSorted = [];
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAmBA;;;;;;GAMG;AAEH,MAAM,OAAO,eAAe;IAClB,MAAM,CAAqB;IAC3B,MAAM,CAA2C;IACjD,OAAO,CAA2B;IAClC,cAAc,CAAa;IAC3B,iBAAiB,CAAU;IAC3B,WAAW,CAAU;IACrB,WAAW,CAAgB;IACnC,YACE,MAA2B,EAC3B,MAAiD,EACjD,UAA2B,EAAE;QAE7B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;QACpB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;QACpB,IAAI,CAAC,OAAO,GAAG;YACb,WAAW,EAAE,EAAE;YACf,mBAAmB,EAAE,aAAa;YAClC,yBAAyB,EAAE,aAAa;YACxC,YAAY,EAAE,qBAAqB;YACnC,aAAa,EAAE,IAAI;YACnB,UAAU,EAAE,KAAK;YACjB,QAAQ,EAAE,GAAG,EAAE,GAAE,CAAC;YAClB,GAAG,OAAO;SACX,CAAA;QACD,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAA;QACzD,IAAI,CAAC,cAAc,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAA;QACtC,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAA;QAChD,IAAI,CAAC,WAAW,GAAG,EAAE,CAAA;QACrB,IAAI,CAAC,WAAW,GAAG,EAAE,CAAA;QAErB,IAAI,CAAC,IAAI,EAAE,CAAA;IACb,CAAC;IAED,sDAAsD;IAC9C,UAAU,CAAC,KAAe;QAChC,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAA;QACpC,IAAI,CAAC,KAAK;YAAE,OAAO,KAAK,CAAA;QACxB,MAAM,GAAG,GAAG,KAAK,CAAC,YAAY,EAAE,CAAA;QAChC,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAA;IAChD,CAAC;IAED,gDAAgD;IACxC,SAAS,CAAC,KAAe;QAC/B,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;IACzC,CAAC;IAED,kFAAkF;IAC1E,IAAI;QACV,IAAI,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC;YAC/B,IAAI,CAAC,qBAAqB,EAAE,CAAA;QAC9B,CAAC;QACD,IAAI,CAAC,iBAAiB,EAAE,CAAA;QACxB,IAAI,CAAC,iBAAiB,EAAE,CAAA;IAC1B,CAAC;IAED,yEAAyE;IACjE,qBAAqB;QAC3B,MAAM,GAAG,GAAG;YACV,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS;YAC7B,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU;YAC9B,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO;YAC3B,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS;YAC7B,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI;YACxB,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG;YACvB,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM;YAC1B,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ;YAC5B,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM;SAC3B,CAAA;QACD,MAAM,IAAI,GAAG;YACX,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI;YACxB,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI;YACxB,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI;YACxB,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI;YACxB,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI;SACzB,CAAA;QAED,MAAM,KAAK,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;QAC5C,MAAM,MAAM,GAAG,CAAC,CAAS,EAAE,IAAa,EAAE,EAAE,CAAC,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;QAErE,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE;YAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,cAAc,CAAA;YACjC,IAAI,CAAC,KAAK,CAAC,IAAI;gBAAE,OAAM;YAEvB,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAA;YACtC,IAAI,CAAC,GAAG;gBAAE,OAAM;YAEhB,IAAI,KAAK,GAAG,GAAG,CAAC,eAAe,CAAA;YAC/B,IAAI,GAAG,GAAG,GAAG,CAAC,aAAa,CAAA;YAE3B,IAAI,CAAC,CAAC,OAAO,KAAK,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;gBAChD,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAA;gBACrC,IAAI,GAAG,EAAE,MAAM,KAAK,CAAC;oBAAE,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAA;YACvD,CAAC;YACD,IAAI,CAAC,CAAC,OAAO,KAAK,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;gBAC7C,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAA;gBACrC,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAA;gBACpC,IAAI,GAAG,IAAI,KAAK,IAAI,GAAG,CAAC,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;oBACzE,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,YAAY,EAAE,EAAE,GAAG,GAAG,CAAC,CAAC,CAAA;gBAC/C,CAAC;YACH,CAAC;YAED,IAAI,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,CAAC;gBACpC,IAAI,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,CAAC;oBAAE,OAAM;gBACzE,IAAI,CAAC,eAAe,EAAE,CAAA;gBACtB,CAAC,CAAC,cAAc,EAAE,CAAA;gBAClB,CAAC,CAAC,YAAY,CAAC,cAAc,EAAE,CAAA;gBAC/B,CAAC,CAAC,YAAY,CAAC,eAAe,EAAE,CAAA;gBAChC,OAAM;YACR,CAAC;QACH,CAAC,CAAC,CAAA;QAEF,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,CAAA;IACnD,CAAC;IAED,mDAAmD;IAC3C,iBAAiB;QACvB,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,uBAAuB,CAAC,CAAC,CAAC,EAAE,EAAE;YAC3D,IAAI,CAAC,CAAC,OAAO;gBAAE,OAAM;YACrB,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAA;QACrB,CAAC,CAAC,CAAA;QACF,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,CAAA;IACnD,CAAC;IAED,6DAA6D;IACrD,WAAW,CAAC,CAAgD;QAClE,MAAM,KAAK,GAAG,IAAI,CAAC,cAAc,CAAA;QACjC,IAAI,CAAC,KAAK,CAAC,IAAI;YAAE,OAAM;QAEvB,IAAI,QAAQ,GAAG,KAAK,CAAA;QAEpB,KAAK,MAAM,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CACtC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,eAAe,CAC5D,EAAE,CAAC;YACF,MAAM,EAAE,eAAe,EAAE,KAAK,EAAE,aAAa,EAAE,GAAG,EAAE,GAAG,MAAM,CAAC,KAAK,CAAA;YACnE,MAAM,OAAO,GAAG,GAAG,GAAG,KAAK,CAAA;YAC3B,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAA;YACnD,MAAM,KAAK,GAAG,QAAQ,GAAG,OAAO,CAAA;YAChC,IAAI,CAAC,KAAK,IAAI,CAAC,OAAO;gBAAE,SAAQ;YAEhC,uDAAuD;YACvD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC;gBACjC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,EAAE,CAAC;oBAC5B,QAAQ,GAAG,IAAI,CAAA;gBACjB,CAAC;YACH,CAAC;YAED,gDAAgD;YAChD,IAAI,KAAK,EAAE,CAAC;gBACV,MAAM,OAAO,GAAa,EAAE,CAAA;gBAC5B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;oBACzB,IAAI,IAAI,IAAI,KAAK,GAAG,OAAO,EAAE,CAAC;wBAC5B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;oBACpB,CAAC;gBACH,CAAC;gBACD,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;oBAC3B,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;gBACpB,CAAC;gBACD,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;oBAC3B,KAAK,CAAC,GAAG,CAAC,IAAI,GAAG,KAAK,CAAC,CAAA;gBACzB,CAAC;gBACD,IAAI,OAAO,CAAC,MAAM;oBAAE,QAAQ,GAAG,IAAI,CAAA;YACrC,CAAC;QACH,CAAC;QAED,IAAI,QAAQ,EAAE,CAAC;YACb,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAA;YACnD,IAAI,CAAC,iBAAiB,EAAE,CAAA;YACxB,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAA;QACpD,CAAC;IACH,CAAC;IAED,wEAAwE;IAChE,iBAAiB;QACvB,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAA;QACpC,IAAI,CAAC,KAAK;YAAE,OAAM;QAElB,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC,gBAAgB,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC,CAAA;QAE/D,IAAI,IAAI,CAAC,iBAAiB,CAAC,MAAM,EAAE,CAAC;YAClC,MAAM,KAAK,GAAG,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;gBAClD,KAAK,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC9C,OAAO,EAAE;oBACP,WAAW,EAAE,IAAI;oBACjB,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,mBAAmB;oBAC3C,yBAAyB,EAAE,IAAI,CAAC,OAAO,CAAC,yBAAyB;oBACjE,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,sBAAsB,CAAC,2BAA2B;iBAClF;aACF,CAAC,CAAC,CAAA;YACH,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC,gBAAgB,CAAC,EAAE,EAAE,KAAK,CAAC,CAAA;QACtD,CAAC;IACH,CAAC;IAED,+EAA+E;IAC/E,cAAc,CAAC,KAAe;QAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAA;QACtC,IAAI,CAAC,cAAc,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAA;QACtC,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAA;QAChD,IAAI,CAAC,iBAAiB,EAAE,CAAA;IAC1B,CAAC;IAED,4FAA4F;IAC5F,cAAc,CAAC,KAAa,EAAE,GAAW;QACvC,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,iBAAiB,EAAE,KAAK,CAAC,CAAA;QAC1D,OAAO,GAAG,GAAG,IAAI,CAAC,iBAAiB,CAAC,MAAM,IAAI,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,GAAG,CAAA;IAClF,CAAC;IAED,2DAA2D;IACnD,UAAU,CAAC,GAAa,EAAE,MAAc;QAC9C,IAAI,EAAE,GAAG,CAAC,CAAA;QACV,IAAI,EAAE,GAAG,GAAG,CAAC,MAAM,CAAA;QACnB,OAAO,EAAE,GAAG,EAAE,EAAE,CAAC;YACf,MAAM,GAAG,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;YAC1B,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,MAAM;gBAAE,EAAE,GAAG,GAAG,GAAG,CAAC,CAAA;;gBAC9B,EAAE,GAAG,GAAG,CAAA;QACf,CAAC;QACD,OAAO,EAAE,CAAA;IACX,CAAC;IAED,+EAA+E;IACvE,eAAe;QACrB,IAAI,CAAC;YACH,MAAM,IAAI,GAAI,IAAI,CAAC,MAAc,CAAC,eAAe,CAAC,kCAAkC,CAAC,CAAA;YACrF,IAAI,IAAI,EAAE,CAAC;gBACT,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY;oBACnC,CAAC,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,YAAY,KAAK,QAAQ;wBAC7C,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY;wBAC3B,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,KAAK;oBACnC,CAAC,CAAC,SAAS,CAAA;gBACb,IAAI,GAAG;oBAAE,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAA;YAC3D,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,+DAA+D;QACjE,CAAC;IACH,CAAC;IAED,yCAAyC;IACzC,cAAc;QACZ,OAAO,CAAC,GAAG,IAAI,CAAC,iBAAiB,CAAC,CAAA;IACpC,CAAC;IAED,uEAAuE;IACvE,OAAO;QACL,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAA;QACpC,IAAI,CAAC,WAAW,GAAG,EAAE,CAAA;QACrB,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAA;QACpC,IAAI,KAAK,EAAE,CAAC;YACV,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC,gBAAgB,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC,CAAA;QACjE,CAAC;QACD,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAA;QAC3B,IAAI,CAAC,iBAAiB,GAAG,EAAE,CAAA;IAC7B,CAAC;CACF"}
|
package/dist/react.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { LineLockOptions } from './index.js';
|
|
2
|
+
import type * as monacoEditor from 'monaco-editor';
|
|
3
|
+
/**
|
|
4
|
+
* React hook to manage line locks in a Monaco editor.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```tsx
|
|
8
|
+
* import { useLineLocks } from 'monaco-line-locks/react'
|
|
9
|
+
*
|
|
10
|
+
* function Editor() {
|
|
11
|
+
* const [lockedLines, setLockedLines] = useState([3, 5])
|
|
12
|
+
* const [editor, setEditor] = useState(null)
|
|
13
|
+
* const [monaco, setMonaco] = useState(null)
|
|
14
|
+
*
|
|
15
|
+
* useLineLocks(editor, monaco, lockedLines, {
|
|
16
|
+
* onChange: setLockedLines,
|
|
17
|
+
* })
|
|
18
|
+
*
|
|
19
|
+
* return <MonacoEditor onMount={(ed, mon) => { setEditor(ed); setMonaco(mon) }} />
|
|
20
|
+
* }
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare function useLineLocks(editor: monacoEditor.editor.IStandaloneCodeEditor | null, monaco: typeof monacoEditor | null, lockedLines: number[], options?: LineLockOptions): void;
|
|
24
|
+
//# sourceMappingURL=react.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AACA,OAAO,EAAmB,eAAe,EAAE,MAAM,YAAY,CAAA;AAC7D,OAAO,KAAK,KAAK,YAAY,MAAM,eAAe,CAAA;AAElD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,YAAY,CAAC,MAAM,CAAC,qBAAqB,GAAG,IAAI,EACxD,MAAM,EAAE,OAAO,YAAY,GAAG,IAAI,EAClC,WAAW,EAAE,MAAM,EAAE,EACrB,OAAO,CAAC,EAAE,eAAe,QAuB1B"}
|
package/dist/react.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { useEffect, useRef } from 'react';
|
|
2
|
+
import { LineLockManager } from './index.js';
|
|
3
|
+
/**
|
|
4
|
+
* React hook to manage line locks in a Monaco editor.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```tsx
|
|
8
|
+
* import { useLineLocks } from 'monaco-line-locks/react'
|
|
9
|
+
*
|
|
10
|
+
* function Editor() {
|
|
11
|
+
* const [lockedLines, setLockedLines] = useState([3, 5])
|
|
12
|
+
* const [editor, setEditor] = useState(null)
|
|
13
|
+
* const [monaco, setMonaco] = useState(null)
|
|
14
|
+
*
|
|
15
|
+
* useLineLocks(editor, monaco, lockedLines, {
|
|
16
|
+
* onChange: setLockedLines,
|
|
17
|
+
* })
|
|
18
|
+
*
|
|
19
|
+
* return <MonacoEditor onMount={(ed, mon) => { setEditor(ed); setMonaco(mon) }} />
|
|
20
|
+
* }
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export function useLineLocks(editor, monaco, lockedLines, options) {
|
|
24
|
+
const managerRef = useRef(null);
|
|
25
|
+
// Initialize manager when editor/monaco become available
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
if (!editor || !monaco)
|
|
28
|
+
return;
|
|
29
|
+
managerRef.current = new LineLockManager(monaco, editor, {
|
|
30
|
+
...options,
|
|
31
|
+
lockedLines,
|
|
32
|
+
});
|
|
33
|
+
return () => {
|
|
34
|
+
managerRef.current?.dispose();
|
|
35
|
+
managerRef.current = null;
|
|
36
|
+
};
|
|
37
|
+
}, [editor, monaco]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
38
|
+
// Update locked lines when they change externally
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
managerRef.current?.setLockedLines(lockedLines);
|
|
41
|
+
}, [lockedLines]);
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=react.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react.js","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AACzC,OAAO,EAAE,eAAe,EAAmB,MAAM,YAAY,CAAA;AAG7D;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,YAAY,CAC1B,MAAwD,EACxD,MAAkC,EAClC,WAAqB,EACrB,OAAyB;IAEzB,MAAM,UAAU,GAAG,MAAM,CAAyB,IAAI,CAAC,CAAA;IAEvD,yDAAyD;IACzD,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM;YAAE,OAAM;QAE9B,UAAU,CAAC,OAAO,GAAG,IAAI,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE;YACvD,GAAG,OAAO;YACV,WAAW;SACZ,CAAC,CAAA;QAEF,OAAO,GAAG,EAAE;YACV,UAAU,CAAC,OAAO,EAAE,OAAO,EAAE,CAAA;YAC7B,UAAU,CAAC,OAAO,GAAG,IAAI,CAAA;QAC3B,CAAC,CAAA;IACH,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA,CAAC,kDAAkD;IAEvE,kDAAkD;IAClD,SAAS,CAAC,GAAG,EAAE;QACb,UAAU,CAAC,OAAO,EAAE,cAAc,CAAC,WAAW,CAAC,CAAA;IACjD,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAA;AACnB,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "monaco-line-locks",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Lock specific lines in Monaco Editor to prevent editing",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
},
|
|
13
|
+
"./react": {
|
|
14
|
+
"import": "./dist/react.js",
|
|
15
|
+
"types": "./dist/react.d.ts"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist"
|
|
20
|
+
],
|
|
21
|
+
"keywords": [
|
|
22
|
+
"monaco-editor",
|
|
23
|
+
"readonly",
|
|
24
|
+
"locked-lines",
|
|
25
|
+
"code-editor",
|
|
26
|
+
"restrictions"
|
|
27
|
+
],
|
|
28
|
+
"author": "",
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"peerDependencies": {
|
|
31
|
+
"monaco-editor": ">=0.30.0",
|
|
32
|
+
"react": ">=16.8.0"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@types/react": "^19.2.15",
|
|
36
|
+
"knip": "^6.14.2",
|
|
37
|
+
"monaco-editor": "^0.55.0",
|
|
38
|
+
"prettier": "^3.8.3",
|
|
39
|
+
"react": "^19.2.6",
|
|
40
|
+
"typescript": "^5.0.0",
|
|
41
|
+
"vitest": "^4.1.7"
|
|
42
|
+
},
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "tsc",
|
|
45
|
+
"dev": "tsc --watch",
|
|
46
|
+
"test": "vitest run",
|
|
47
|
+
"test:watch": "vitest",
|
|
48
|
+
"knip": "knip",
|
|
49
|
+
"fmt": "prettier --write .",
|
|
50
|
+
"example:react": "pnpm run build && cd examples/react && rm -rf node_modules && pnpm install && pnpm run dev",
|
|
51
|
+
"example:basic": "pnpm run build && python3 -m http.server 3000"
|
|
52
|
+
}
|
|
53
|
+
}
|