docrev 0.9.13 → 0.9.14
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/.claude/settings.local.json +9 -9
- package/.gitattributes +1 -1
- package/CHANGELOG.md +149 -149
- package/PLAN-tables-and-postprocess.md +850 -850
- package/README.md +391 -391
- package/bin/rev.js +11 -11
- package/bin/rev.ts +145 -145
- package/completions/rev.bash +127 -127
- package/completions/rev.ps1 +210 -210
- package/completions/rev.zsh +207 -207
- package/dev_notes/stress2/build_adversarial.ts +186 -186
- package/dev_notes/stress2/drift_matcher.ts +62 -62
- package/dev_notes/stress2/probe_anchors.ts +35 -35
- package/dev_notes/stress2/project/discussion.before.md +3 -3
- package/dev_notes/stress2/project/discussion.md +3 -3
- package/dev_notes/stress2/project/methods.before.md +20 -20
- package/dev_notes/stress2/project/methods.md +20 -20
- package/dev_notes/stress2/project/rev.yaml +5 -5
- package/dev_notes/stress2/project/sections.yaml +4 -4
- package/dev_notes/stress2/sections.yaml +5 -5
- package/dev_notes/stress2/trace_placement.ts +50 -50
- package/dev_notes/stresstest_boundaries.ts +27 -27
- package/dev_notes/stresstest_drift_apply.ts +43 -43
- package/dev_notes/stresstest_drift_compare.ts +43 -43
- package/dev_notes/stresstest_drift_v2.ts +54 -54
- package/dev_notes/stresstest_inspect.ts +54 -54
- package/dev_notes/stresstest_pstyle.ts +55 -55
- package/dev_notes/stresstest_section_debug.ts +23 -23
- package/dev_notes/stresstest_split.ts +70 -70
- package/dev_notes/stresstest_trace.ts +19 -19
- package/dev_notes/stresstest_verify_no_overwrite.ts +40 -40
- package/dist/lib/build.d.ts +38 -1
- package/dist/lib/build.d.ts.map +1 -1
- package/dist/lib/build.js +68 -30
- package/dist/lib/build.js.map +1 -1
- package/dist/lib/commands/build.d.ts.map +1 -1
- package/dist/lib/commands/build.js +38 -5
- package/dist/lib/commands/build.js.map +1 -1
- package/dist/lib/commands/utilities.js +164 -164
- package/dist/lib/commands/word-tools.js +8 -8
- package/dist/lib/grammar.js +3 -3
- package/dist/lib/pdf-comments.js +44 -44
- package/dist/lib/plugins.js +57 -57
- package/dist/lib/pptx-themes.js +115 -115
- package/dist/lib/spelling.js +2 -2
- package/dist/lib/templates.js +387 -387
- package/dist/lib/themes.js +51 -51
- package/eslint.config.js +27 -27
- package/lib/anchor-match.ts +276 -276
- package/lib/annotations.ts +644 -644
- package/lib/build.ts +1300 -1251
- package/lib/citations.ts +160 -160
- package/lib/commands/build.ts +833 -801
- package/lib/commands/citations.ts +515 -515
- package/lib/commands/comments.ts +1050 -1050
- package/lib/commands/context.ts +174 -174
- package/lib/commands/core.ts +309 -309
- package/lib/commands/doi.ts +435 -435
- package/lib/commands/file-ops.ts +372 -372
- package/lib/commands/history.ts +320 -320
- package/lib/commands/index.ts +87 -87
- package/lib/commands/init.ts +259 -259
- package/lib/commands/merge-resolve.ts +378 -378
- package/lib/commands/preview.ts +178 -178
- package/lib/commands/project-info.ts +244 -244
- package/lib/commands/quality.ts +517 -517
- package/lib/commands/response.ts +454 -454
- package/lib/commands/section-boundaries.ts +82 -82
- package/lib/commands/sections.ts +451 -451
- package/lib/commands/sync.ts +706 -706
- package/lib/commands/text-ops.ts +449 -449
- package/lib/commands/utilities.ts +448 -448
- package/lib/commands/verify-anchors.ts +272 -272
- package/lib/commands/word-tools.ts +340 -340
- package/lib/comment-realign.ts +517 -517
- package/lib/config.ts +84 -84
- package/lib/crossref.ts +781 -781
- package/lib/csl.ts +191 -191
- package/lib/dependencies.ts +98 -98
- package/lib/diff-engine.ts +465 -465
- package/lib/doi-cache.ts +115 -115
- package/lib/doi.ts +897 -897
- package/lib/equations.ts +506 -506
- package/lib/errors.ts +346 -346
- package/lib/format.ts +541 -541
- package/lib/git.ts +326 -326
- package/lib/grammar.ts +303 -303
- package/lib/image-registry.ts +180 -180
- package/lib/import.ts +911 -911
- package/lib/journals.ts +543 -543
- package/lib/merge.ts +633 -633
- package/lib/orcid.ts +144 -144
- package/lib/pdf-comments.ts +263 -263
- package/lib/pdf-import.ts +524 -524
- package/lib/plugins.ts +362 -362
- package/lib/postprocess.ts +188 -188
- package/lib/pptx-color-filter.lua +37 -37
- package/lib/pptx-template.ts +469 -469
- package/lib/pptx-themes.ts +483 -483
- package/lib/protect-restore.ts +520 -520
- package/lib/rate-limiter.ts +94 -94
- package/lib/response.ts +197 -197
- package/lib/restore-references.ts +240 -240
- package/lib/review.ts +327 -327
- package/lib/schema.ts +417 -417
- package/lib/scientific-words.ts +73 -73
- package/lib/sections.ts +335 -335
- package/lib/slides.ts +756 -756
- package/lib/spelling.ts +334 -334
- package/lib/templates.ts +526 -526
- package/lib/themes.ts +742 -742
- package/lib/trackchanges.ts +247 -247
- package/lib/tui.ts +450 -450
- package/lib/types.ts +550 -550
- package/lib/undo.ts +250 -250
- package/lib/utils.ts +69 -69
- package/lib/variables.ts +179 -179
- package/lib/word-extraction.ts +806 -806
- package/lib/word.ts +643 -643
- package/lib/wordcomments.ts +817 -817
- package/package.json +137 -137
- package/scripts/postbuild.js +28 -28
- package/skill/REFERENCE.md +431 -431
- package/skill/SKILL.md +258 -258
- package/tsconfig.json +26 -26
- package/types/index.d.ts +525 -525
package/lib/undo.ts
CHANGED
|
@@ -1,250 +1,250 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* In-session undo stack for comment/annotation operations
|
|
3
|
-
*
|
|
4
|
-
* Provides undo/redo functionality during interactive sessions
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
interface StackEntry {
|
|
8
|
-
state: string | object;
|
|
9
|
-
description: string;
|
|
10
|
-
timestamp: number;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
interface HistoryEntry {
|
|
14
|
-
description: string;
|
|
15
|
-
current: boolean;
|
|
16
|
-
index: number;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export interface StackInfo {
|
|
20
|
-
position: number;
|
|
21
|
-
size: number;
|
|
22
|
-
undoSteps: number;
|
|
23
|
-
redoSteps: number;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
interface UndoStack {
|
|
27
|
-
push(state: string | object, description?: string): void;
|
|
28
|
-
undo(): StackEntry | null;
|
|
29
|
-
redo(): StackEntry | null;
|
|
30
|
-
current(): StackEntry | null;
|
|
31
|
-
canUndo(): boolean;
|
|
32
|
-
canRedo(): boolean;
|
|
33
|
-
info(): StackInfo;
|
|
34
|
-
history(limit?: number): HistoryEntry[];
|
|
35
|
-
getStack(): StackEntry[];
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export interface DocumentChange {
|
|
39
|
-
text: string;
|
|
40
|
-
description: string;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export interface DocumentSession {
|
|
44
|
-
getText(): string;
|
|
45
|
-
applyChange(newText: string, description: string): void;
|
|
46
|
-
undo(): DocumentChange | null;
|
|
47
|
-
redo(): DocumentChange | null;
|
|
48
|
-
canUndo(): boolean;
|
|
49
|
-
canRedo(): boolean;
|
|
50
|
-
info(): StackInfo;
|
|
51
|
-
history(limit?: number): HistoryEntry[];
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Create an undo stack
|
|
56
|
-
*/
|
|
57
|
-
export function createUndoStack(maxSize: number = 50): UndoStack {
|
|
58
|
-
const stack: StackEntry[] = [];
|
|
59
|
-
let position = -1;
|
|
60
|
-
|
|
61
|
-
return {
|
|
62
|
-
/**
|
|
63
|
-
* Push a new state onto the stack
|
|
64
|
-
*/
|
|
65
|
-
push(state: string | object, description: string = ''): void {
|
|
66
|
-
// Remove any states after current position (for redo)
|
|
67
|
-
if (position < stack.length - 1) {
|
|
68
|
-
stack.splice(position + 1);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Add new state
|
|
72
|
-
stack.push({
|
|
73
|
-
state: typeof state === 'string' ? state : JSON.parse(JSON.stringify(state)),
|
|
74
|
-
description,
|
|
75
|
-
timestamp: Date.now(),
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
// Enforce max size
|
|
79
|
-
while (stack.length > maxSize) {
|
|
80
|
-
stack.shift();
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
position = stack.length - 1;
|
|
84
|
-
},
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Undo to previous state
|
|
88
|
-
*/
|
|
89
|
-
undo(): StackEntry | null {
|
|
90
|
-
if (position <= 0) {
|
|
91
|
-
return null;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
position--;
|
|
95
|
-
return stack[position] || null;
|
|
96
|
-
},
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Redo to next state
|
|
100
|
-
*/
|
|
101
|
-
redo(): StackEntry | null {
|
|
102
|
-
if (position >= stack.length - 1) {
|
|
103
|
-
return null;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
position++;
|
|
107
|
-
return stack[position] || null;
|
|
108
|
-
},
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Get current state
|
|
112
|
-
*/
|
|
113
|
-
current(): StackEntry | null {
|
|
114
|
-
if (position < 0 || position >= stack.length) {
|
|
115
|
-
return null;
|
|
116
|
-
}
|
|
117
|
-
return stack[position] || null;
|
|
118
|
-
},
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Check if undo is available
|
|
122
|
-
*/
|
|
123
|
-
canUndo(): boolean {
|
|
124
|
-
return position > 0;
|
|
125
|
-
},
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Check if redo is available
|
|
129
|
-
*/
|
|
130
|
-
canRedo(): boolean {
|
|
131
|
-
return position < stack.length - 1;
|
|
132
|
-
},
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Get stack info
|
|
136
|
-
*/
|
|
137
|
-
info(): StackInfo {
|
|
138
|
-
return {
|
|
139
|
-
position,
|
|
140
|
-
size: stack.length,
|
|
141
|
-
undoSteps: position,
|
|
142
|
-
redoSteps: stack.length - position - 1,
|
|
143
|
-
};
|
|
144
|
-
},
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Get history of changes
|
|
148
|
-
*/
|
|
149
|
-
history(limit: number = 10): HistoryEntry[] {
|
|
150
|
-
const start = Math.max(0, position - Math.floor(limit / 2));
|
|
151
|
-
const end = Math.min(stack.length, start + limit);
|
|
152
|
-
|
|
153
|
-
return stack.slice(start, end).map((item, i) => ({
|
|
154
|
-
description: item.description,
|
|
155
|
-
current: start + i === position,
|
|
156
|
-
index: start + i,
|
|
157
|
-
}));
|
|
158
|
-
},
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Get the full stack (for debugging)
|
|
162
|
-
*/
|
|
163
|
-
getStack(): StackEntry[] {
|
|
164
|
-
return [...stack];
|
|
165
|
-
},
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Create a document session with undo support
|
|
171
|
-
*/
|
|
172
|
-
export function createDocumentSession(initialText: string): DocumentSession {
|
|
173
|
-
const undoStack = createUndoStack();
|
|
174
|
-
|
|
175
|
-
// Save initial state
|
|
176
|
-
undoStack.push(initialText, 'Initial state');
|
|
177
|
-
|
|
178
|
-
return {
|
|
179
|
-
/**
|
|
180
|
-
* Get current text
|
|
181
|
-
*/
|
|
182
|
-
getText(): string {
|
|
183
|
-
const current = undoStack.current();
|
|
184
|
-
return current ? current.state as string : initialText;
|
|
185
|
-
},
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* Apply a change
|
|
189
|
-
*/
|
|
190
|
-
applyChange(newText: string, description: string): void {
|
|
191
|
-
undoStack.push(newText, description);
|
|
192
|
-
},
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Undo last change
|
|
196
|
-
*/
|
|
197
|
-
undo(): DocumentChange | null {
|
|
198
|
-
const result = undoStack.undo();
|
|
199
|
-
if (result) {
|
|
200
|
-
return {
|
|
201
|
-
text: result.state as string,
|
|
202
|
-
description: result.description,
|
|
203
|
-
};
|
|
204
|
-
}
|
|
205
|
-
return null;
|
|
206
|
-
},
|
|
207
|
-
|
|
208
|
-
/**
|
|
209
|
-
* Redo last undone change
|
|
210
|
-
*/
|
|
211
|
-
redo(): DocumentChange | null {
|
|
212
|
-
const result = undoStack.redo();
|
|
213
|
-
if (result) {
|
|
214
|
-
return {
|
|
215
|
-
text: result.state as string,
|
|
216
|
-
description: result.description,
|
|
217
|
-
};
|
|
218
|
-
}
|
|
219
|
-
return null;
|
|
220
|
-
},
|
|
221
|
-
|
|
222
|
-
/**
|
|
223
|
-
* Check if undo is available
|
|
224
|
-
*/
|
|
225
|
-
canUndo(): boolean {
|
|
226
|
-
return undoStack.canUndo();
|
|
227
|
-
},
|
|
228
|
-
|
|
229
|
-
/**
|
|
230
|
-
* Check if redo is available
|
|
231
|
-
*/
|
|
232
|
-
canRedo(): boolean {
|
|
233
|
-
return undoStack.canRedo();
|
|
234
|
-
},
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* Get stack info
|
|
238
|
-
*/
|
|
239
|
-
info(): StackInfo {
|
|
240
|
-
return undoStack.info();
|
|
241
|
-
},
|
|
242
|
-
|
|
243
|
-
/**
|
|
244
|
-
* Get change history
|
|
245
|
-
*/
|
|
246
|
-
history(limit: number = 10): HistoryEntry[] {
|
|
247
|
-
return undoStack.history(limit);
|
|
248
|
-
},
|
|
249
|
-
};
|
|
250
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* In-session undo stack for comment/annotation operations
|
|
3
|
+
*
|
|
4
|
+
* Provides undo/redo functionality during interactive sessions
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
interface StackEntry {
|
|
8
|
+
state: string | object;
|
|
9
|
+
description: string;
|
|
10
|
+
timestamp: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface HistoryEntry {
|
|
14
|
+
description: string;
|
|
15
|
+
current: boolean;
|
|
16
|
+
index: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface StackInfo {
|
|
20
|
+
position: number;
|
|
21
|
+
size: number;
|
|
22
|
+
undoSteps: number;
|
|
23
|
+
redoSteps: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface UndoStack {
|
|
27
|
+
push(state: string | object, description?: string): void;
|
|
28
|
+
undo(): StackEntry | null;
|
|
29
|
+
redo(): StackEntry | null;
|
|
30
|
+
current(): StackEntry | null;
|
|
31
|
+
canUndo(): boolean;
|
|
32
|
+
canRedo(): boolean;
|
|
33
|
+
info(): StackInfo;
|
|
34
|
+
history(limit?: number): HistoryEntry[];
|
|
35
|
+
getStack(): StackEntry[];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface DocumentChange {
|
|
39
|
+
text: string;
|
|
40
|
+
description: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface DocumentSession {
|
|
44
|
+
getText(): string;
|
|
45
|
+
applyChange(newText: string, description: string): void;
|
|
46
|
+
undo(): DocumentChange | null;
|
|
47
|
+
redo(): DocumentChange | null;
|
|
48
|
+
canUndo(): boolean;
|
|
49
|
+
canRedo(): boolean;
|
|
50
|
+
info(): StackInfo;
|
|
51
|
+
history(limit?: number): HistoryEntry[];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Create an undo stack
|
|
56
|
+
*/
|
|
57
|
+
export function createUndoStack(maxSize: number = 50): UndoStack {
|
|
58
|
+
const stack: StackEntry[] = [];
|
|
59
|
+
let position = -1;
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
/**
|
|
63
|
+
* Push a new state onto the stack
|
|
64
|
+
*/
|
|
65
|
+
push(state: string | object, description: string = ''): void {
|
|
66
|
+
// Remove any states after current position (for redo)
|
|
67
|
+
if (position < stack.length - 1) {
|
|
68
|
+
stack.splice(position + 1);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Add new state
|
|
72
|
+
stack.push({
|
|
73
|
+
state: typeof state === 'string' ? state : JSON.parse(JSON.stringify(state)),
|
|
74
|
+
description,
|
|
75
|
+
timestamp: Date.now(),
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// Enforce max size
|
|
79
|
+
while (stack.length > maxSize) {
|
|
80
|
+
stack.shift();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
position = stack.length - 1;
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Undo to previous state
|
|
88
|
+
*/
|
|
89
|
+
undo(): StackEntry | null {
|
|
90
|
+
if (position <= 0) {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
position--;
|
|
95
|
+
return stack[position] || null;
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Redo to next state
|
|
100
|
+
*/
|
|
101
|
+
redo(): StackEntry | null {
|
|
102
|
+
if (position >= stack.length - 1) {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
position++;
|
|
107
|
+
return stack[position] || null;
|
|
108
|
+
},
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Get current state
|
|
112
|
+
*/
|
|
113
|
+
current(): StackEntry | null {
|
|
114
|
+
if (position < 0 || position >= stack.length) {
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
return stack[position] || null;
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Check if undo is available
|
|
122
|
+
*/
|
|
123
|
+
canUndo(): boolean {
|
|
124
|
+
return position > 0;
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Check if redo is available
|
|
129
|
+
*/
|
|
130
|
+
canRedo(): boolean {
|
|
131
|
+
return position < stack.length - 1;
|
|
132
|
+
},
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Get stack info
|
|
136
|
+
*/
|
|
137
|
+
info(): StackInfo {
|
|
138
|
+
return {
|
|
139
|
+
position,
|
|
140
|
+
size: stack.length,
|
|
141
|
+
undoSteps: position,
|
|
142
|
+
redoSteps: stack.length - position - 1,
|
|
143
|
+
};
|
|
144
|
+
},
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Get history of changes
|
|
148
|
+
*/
|
|
149
|
+
history(limit: number = 10): HistoryEntry[] {
|
|
150
|
+
const start = Math.max(0, position - Math.floor(limit / 2));
|
|
151
|
+
const end = Math.min(stack.length, start + limit);
|
|
152
|
+
|
|
153
|
+
return stack.slice(start, end).map((item, i) => ({
|
|
154
|
+
description: item.description,
|
|
155
|
+
current: start + i === position,
|
|
156
|
+
index: start + i,
|
|
157
|
+
}));
|
|
158
|
+
},
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Get the full stack (for debugging)
|
|
162
|
+
*/
|
|
163
|
+
getStack(): StackEntry[] {
|
|
164
|
+
return [...stack];
|
|
165
|
+
},
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Create a document session with undo support
|
|
171
|
+
*/
|
|
172
|
+
export function createDocumentSession(initialText: string): DocumentSession {
|
|
173
|
+
const undoStack = createUndoStack();
|
|
174
|
+
|
|
175
|
+
// Save initial state
|
|
176
|
+
undoStack.push(initialText, 'Initial state');
|
|
177
|
+
|
|
178
|
+
return {
|
|
179
|
+
/**
|
|
180
|
+
* Get current text
|
|
181
|
+
*/
|
|
182
|
+
getText(): string {
|
|
183
|
+
const current = undoStack.current();
|
|
184
|
+
return current ? current.state as string : initialText;
|
|
185
|
+
},
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Apply a change
|
|
189
|
+
*/
|
|
190
|
+
applyChange(newText: string, description: string): void {
|
|
191
|
+
undoStack.push(newText, description);
|
|
192
|
+
},
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Undo last change
|
|
196
|
+
*/
|
|
197
|
+
undo(): DocumentChange | null {
|
|
198
|
+
const result = undoStack.undo();
|
|
199
|
+
if (result) {
|
|
200
|
+
return {
|
|
201
|
+
text: result.state as string,
|
|
202
|
+
description: result.description,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
return null;
|
|
206
|
+
},
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Redo last undone change
|
|
210
|
+
*/
|
|
211
|
+
redo(): DocumentChange | null {
|
|
212
|
+
const result = undoStack.redo();
|
|
213
|
+
if (result) {
|
|
214
|
+
return {
|
|
215
|
+
text: result.state as string,
|
|
216
|
+
description: result.description,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
return null;
|
|
220
|
+
},
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Check if undo is available
|
|
224
|
+
*/
|
|
225
|
+
canUndo(): boolean {
|
|
226
|
+
return undoStack.canUndo();
|
|
227
|
+
},
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Check if redo is available
|
|
231
|
+
*/
|
|
232
|
+
canRedo(): boolean {
|
|
233
|
+
return undoStack.canRedo();
|
|
234
|
+
},
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Get stack info
|
|
238
|
+
*/
|
|
239
|
+
info(): StackInfo {
|
|
240
|
+
return undoStack.info();
|
|
241
|
+
},
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Get change history
|
|
245
|
+
*/
|
|
246
|
+
history(limit: number = 10): HistoryEntry[] {
|
|
247
|
+
return undoStack.history(limit);
|
|
248
|
+
},
|
|
249
|
+
};
|
|
250
|
+
}
|
package/lib/utils.ts
CHANGED
|
@@ -1,69 +1,69 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared utility functions
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Count words in text (excluding markdown syntax)
|
|
7
|
-
* @param text - Markdown text
|
|
8
|
-
* @returns Word count
|
|
9
|
-
*/
|
|
10
|
-
export function countWords(text: string): number {
|
|
11
|
-
return text
|
|
12
|
-
.replace(/^---[\s\S]*?---/m, '') // Remove YAML frontmatter
|
|
13
|
-
.replace(/!\[.*?\]\(.*?\)/g, '') // Remove images
|
|
14
|
-
.replace(/\[([^\]]+)\]\([^)]+\)/g, '$1') // Keep link text
|
|
15
|
-
.replace(/#+\s*/g, '') // Remove headers
|
|
16
|
-
.replace(/\*\*|__|[*_`]/g, '') // Remove formatting
|
|
17
|
-
.replace(/```[\s\S]*?```/g, '') // Remove code blocks
|
|
18
|
-
.replace(/\{[^}]+\}/g, '') // Remove CriticMarkup and attributes
|
|
19
|
-
.replace(/@\w+:\w+/g, '') // Remove cross-references
|
|
20
|
-
.replace(/@\w+/g, '') // Remove citations
|
|
21
|
-
.replace(/\|[^|]+\|/g, ' ') // Remove table cells
|
|
22
|
-
.replace(/[-=]{3,}/g, '') // Remove horizontal rules
|
|
23
|
-
.replace(/\n+/g, ' ') // Newlines to spaces
|
|
24
|
-
.replace(/\s+/g, ' ') // Collapse multiple spaces
|
|
25
|
-
.trim()
|
|
26
|
-
.split(/\s+/)
|
|
27
|
-
.filter(w => w.length > 0).length;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Normalize whitespace in text
|
|
32
|
-
* @param text - Input text
|
|
33
|
-
* @returns Normalized text
|
|
34
|
-
*/
|
|
35
|
-
export function normalizeWhitespace(text: string): string {
|
|
36
|
-
return text
|
|
37
|
-
.replace(/\r\n/g, '\n')
|
|
38
|
-
.replace(/\t/g, ' ')
|
|
39
|
-
.replace(/ +/g, ' ')
|
|
40
|
-
.trim();
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Escape XML special characters
|
|
45
|
-
* @param str - Input string
|
|
46
|
-
* @returns XML-safe string
|
|
47
|
-
*/
|
|
48
|
-
export function escapeXml(str: string): string {
|
|
49
|
-
return str
|
|
50
|
-
.replace(/&/g, '&')
|
|
51
|
-
.replace(/</g, '<')
|
|
52
|
-
.replace(/>/g, '>')
|
|
53
|
-
.replace(/"/g, '"')
|
|
54
|
-
.replace(/'/g, ''');
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Escape LaTeX special characters
|
|
59
|
-
* @param text - Text to escape
|
|
60
|
-
* @returns Escaped text
|
|
61
|
-
*/
|
|
62
|
-
export function escapeLatex(text: string): string {
|
|
63
|
-
return text
|
|
64
|
-
.replace(/\\/g, '\\textbackslash{}')
|
|
65
|
-
.replace(/([#$%&_{}])/g, '\\$1')
|
|
66
|
-
.replace(/\^/g, '\\textasciicircum{}')
|
|
67
|
-
.replace(/~/g, '\\textasciitilde{}')
|
|
68
|
-
.replace(/\n/g, ' ');
|
|
69
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Shared utility functions
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Count words in text (excluding markdown syntax)
|
|
7
|
+
* @param text - Markdown text
|
|
8
|
+
* @returns Word count
|
|
9
|
+
*/
|
|
10
|
+
export function countWords(text: string): number {
|
|
11
|
+
return text
|
|
12
|
+
.replace(/^---[\s\S]*?---/m, '') // Remove YAML frontmatter
|
|
13
|
+
.replace(/!\[.*?\]\(.*?\)/g, '') // Remove images
|
|
14
|
+
.replace(/\[([^\]]+)\]\([^)]+\)/g, '$1') // Keep link text
|
|
15
|
+
.replace(/#+\s*/g, '') // Remove headers
|
|
16
|
+
.replace(/\*\*|__|[*_`]/g, '') // Remove formatting
|
|
17
|
+
.replace(/```[\s\S]*?```/g, '') // Remove code blocks
|
|
18
|
+
.replace(/\{[^}]+\}/g, '') // Remove CriticMarkup and attributes
|
|
19
|
+
.replace(/@\w+:\w+/g, '') // Remove cross-references
|
|
20
|
+
.replace(/@\w+/g, '') // Remove citations
|
|
21
|
+
.replace(/\|[^|]+\|/g, ' ') // Remove table cells
|
|
22
|
+
.replace(/[-=]{3,}/g, '') // Remove horizontal rules
|
|
23
|
+
.replace(/\n+/g, ' ') // Newlines to spaces
|
|
24
|
+
.replace(/\s+/g, ' ') // Collapse multiple spaces
|
|
25
|
+
.trim()
|
|
26
|
+
.split(/\s+/)
|
|
27
|
+
.filter(w => w.length > 0).length;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Normalize whitespace in text
|
|
32
|
+
* @param text - Input text
|
|
33
|
+
* @returns Normalized text
|
|
34
|
+
*/
|
|
35
|
+
export function normalizeWhitespace(text: string): string {
|
|
36
|
+
return text
|
|
37
|
+
.replace(/\r\n/g, '\n')
|
|
38
|
+
.replace(/\t/g, ' ')
|
|
39
|
+
.replace(/ +/g, ' ')
|
|
40
|
+
.trim();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Escape XML special characters
|
|
45
|
+
* @param str - Input string
|
|
46
|
+
* @returns XML-safe string
|
|
47
|
+
*/
|
|
48
|
+
export function escapeXml(str: string): string {
|
|
49
|
+
return str
|
|
50
|
+
.replace(/&/g, '&')
|
|
51
|
+
.replace(/</g, '<')
|
|
52
|
+
.replace(/>/g, '>')
|
|
53
|
+
.replace(/"/g, '"')
|
|
54
|
+
.replace(/'/g, ''');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Escape LaTeX special characters
|
|
59
|
+
* @param text - Text to escape
|
|
60
|
+
* @returns Escaped text
|
|
61
|
+
*/
|
|
62
|
+
export function escapeLatex(text: string): string {
|
|
63
|
+
return text
|
|
64
|
+
.replace(/\\/g, '\\textbackslash{}')
|
|
65
|
+
.replace(/([#$%&_{}])/g, '\\$1')
|
|
66
|
+
.replace(/\^/g, '\\textasciicircum{}')
|
|
67
|
+
.replace(/~/g, '\\textasciitilde{}')
|
|
68
|
+
.replace(/\n/g, ' ');
|
|
69
|
+
}
|