0
# Utilities and Statistics
1
2
Utility functions for extracting editor statistics and managing editor state information. These utilities provide detailed insights into the editor's current state and user interactions.
3
4
## Capabilities
5
6
### Statistics Extraction
7
8
Function to extract comprehensive statistics from the editor's current state.
9
10
```typescript { .api }
11
/**
12
* Extract comprehensive statistics from a ViewUpdate
13
* @param view - ViewUpdate object from CodeMirror
14
* @returns Statistics object with editor state information
15
*/
16
function getStatistics(view: ViewUpdate): Statistics;
17
```
18
19
**Usage Examples:**
20
21
```typescript
22
import React from "react";
23
import CodeMirror from "@uiw/react-codemirror";
24
import { getStatistics } from "@uiw/react-codemirror";
25
26
function StatisticsDisplay() {
27
const [stats, setStats] = React.useState(null);
28
29
const handleUpdate = (viewUpdate) => {
30
const currentStats = getStatistics(viewUpdate);
31
setStats(currentStats);
32
};
33
34
return (
35
<div>
36
<CodeMirror
37
value="console.log('Hello World');\nconst x = 42;"
38
onUpdate={handleUpdate}
39
height="200px"
40
/>
41
42
{stats && (
43
<div style={{ marginTop: 10, fontSize: 12 }}>
44
<div>Lines: {stats.lineCount}</div>
45
<div>Characters: {stats.length}</div>
46
<div>Selected: {stats.selectedText ? 'Yes' : 'No'}</div>
47
<div>Selection: {stats.selectionCode}</div>
48
<div>Read-only: {stats.readOnly ? 'Yes' : 'No'}</div>
49
<div>Tab size: {stats.tabSize}</div>
50
</div>
51
)}
52
</div>
53
);
54
}
55
```
56
57
### Statistics Interface
58
59
Comprehensive interface containing all available editor statistics.
60
61
```typescript { .api }
62
interface Statistics {
63
/** Total length of the document in characters */
64
length: number;
65
/** Total number of lines in the editor */
66
lineCount: number;
67
/** Line object at current cursor position */
68
line: Line;
69
/** Line break string used by the editor (\\n, \\r\\n, etc.) */
70
lineBreak: string;
71
/** Whether the editor is in read-only mode */
72
readOnly: boolean;
73
/** Size of tab character in columns */
74
tabSize: number;
75
/** Current selection object with all ranges */
76
selection: EditorSelection;
77
/** Primary selection range as single range */
78
selectionAsSingle: SelectionRange;
79
/** Array of all selection ranges */
80
ranges: readonly SelectionRange[];
81
/** Text content of current selection */
82
selectionCode: string;
83
/** Array of selected text for each selection range */
84
selections: string[];
85
/** Whether any text is currently selected */
86
selectedText: boolean;
87
}
88
```
89
90
**Usage Examples:**
91
92
```typescript
93
import React from "react";
94
import CodeMirror from "@uiw/react-codemirror";
95
import { getStatistics } from "@uiw/react-codemirror";
96
97
// Detailed statistics usage
98
function DetailedStatistics() {
99
const [stats, setStats] = React.useState(null);
100
101
const handleStatistics = (statistics) => {
102
setStats(statistics);
103
104
// Access specific properties
105
console.log('Document info:', {
106
totalChars: statistics.length,
107
lines: statistics.lineCount,
108
lineBreak: statistics.lineBreak === '\n' ? 'LF' : 'CRLF',
109
});
110
111
// Current line information
112
console.log('Current line:', {
113
number: statistics.line.number,
114
text: statistics.line.text,
115
from: statistics.line.from,
116
to: statistics.line.to,
117
});
118
119
// Selection information
120
if (statistics.selectedText) {
121
console.log('Selection:', {
122
text: statistics.selectionCode,
123
ranges: statistics.ranges.length,
124
multipleSelections: statistics.ranges.length > 1,
125
});
126
}
127
};
128
129
return (
130
<CodeMirror
131
value={`Line 1
132
Line 2
133
Line 3 with more content`}
134
onStatistics={handleStatistics}
135
height="150px"
136
/>
137
);
138
}
139
140
// Selection tracking
141
function SelectionTracker() {
142
const [selectionInfo, setSelectionInfo] = React.useState({
143
hasSelection: false,
144
selectedText: '',
145
ranges: 0,
146
});
147
148
const handleStatistics = (stats) => {
149
setSelectionInfo({
150
hasSelection: stats.selectedText,
151
selectedText: stats.selectionCode,
152
ranges: stats.ranges.length,
153
});
154
};
155
156
return (
157
<div>
158
<CodeMirror
159
value="Select some text in this editor to see selection details."
160
onStatistics={handleStatistics}
161
height="100px"
162
/>
163
164
<div style={{ marginTop: 10 }}>
165
<div>Has selection: {selectionInfo.hasSelection ? 'Yes' : 'No'}</div>
166
{selectionInfo.hasSelection && (
167
<>
168
<div>Selected text: "{selectionInfo.selectedText}"</div>
169
<div>Selection ranges: {selectionInfo.ranges}</div>
170
</>
171
)}
172
</div>
173
</div>
174
);
175
}
176
```
177
178
### Line Information
179
180
Details about line objects and their properties.
181
182
```typescript { .api }
183
// Line interface (from @codemirror/state)
184
interface Line {
185
/** Line number (1-based) */
186
readonly number: number;
187
/** Start position of line in document */
188
readonly from: number;
189
/** End position of line in document (excluding line break) */
190
readonly to: number;
191
/** Text content of the line */
192
readonly text: string;
193
/** Length of the line */
194
readonly length: number;
195
}
196
```
197
198
**Usage Examples:**
199
200
```typescript
201
import React from "react";
202
import CodeMirror from "@uiw/react-codemirror";
203
import { getStatistics } from "@uiw/react-codemirror";
204
205
function LineInformation() {
206
const [lineInfo, setLineInfo] = React.useState(null);
207
208
const handleStatistics = (stats) => {
209
const { line } = stats;
210
setLineInfo({
211
number: line.number,
212
text: line.text,
213
length: line.length,
214
isEmpty: line.length === 0,
215
position: {
216
from: line.from,
217
to: line.to,
218
},
219
});
220
};
221
222
return (
223
<div>
224
<CodeMirror
225
value={`First line
226
Second line with more text
227
228
Fourth line (third was empty)`}
229
onStatistics={handleStatistics}
230
height="120px"
231
/>
232
233
{lineInfo && (
234
<div style={{ marginTop: 10, fontSize: 12, fontFamily: 'monospace' }}>
235
<div>Current line: {lineInfo.number}</div>
236
<div>Line text: "{lineInfo.text}"</div>
237
<div>Line length: {lineInfo.length}</div>
238
<div>Empty line: {lineInfo.isEmpty ? 'Yes' : 'No'}</div>
239
<div>Position: {lineInfo.position.from}-{lineInfo.position.to}</div>
240
</div>
241
)}
242
</div>
243
);
244
}
245
```
246
247
### Selection Information
248
249
Details about selection ranges and their properties.
250
251
```typescript { .api }
252
// Selection interfaces (from @codemirror/state)
253
interface EditorSelection {
254
/** All selection ranges */
255
readonly ranges: readonly SelectionRange[];
256
/** Primary selection range */
257
readonly main: SelectionRange;
258
/** Convert to single range selection */
259
asSingle(): EditorSelection;
260
}
261
262
interface SelectionRange {
263
/** Start position of selection */
264
readonly from: number;
265
/** End position of selection */
266
readonly to: number;
267
/** Whether the selection is empty (cursor) */
268
readonly empty: boolean;
269
/** Anchor position (where selection started) */
270
readonly anchor: number;
271
/** Head position (where selection ends) */
272
readonly head: number;
273
}
274
```
275
276
**Usage Examples:**
277
278
```typescript
279
import React from "react";
280
import CodeMirror from "@uiw/react-codemirror";
281
282
function SelectionDetails() {
283
const [selectionDetails, setSelectionDetails] = React.useState(null);
284
285
const handleStatistics = (stats) => {
286
const { selection, ranges, selectionCode, selections } = stats;
287
288
setSelectionDetails({
289
mainRange: {
290
from: selection.main.from,
291
to: selection.main.to,
292
empty: selection.main.empty,
293
anchor: selection.main.anchor,
294
head: selection.main.head,
295
},
296
totalRanges: ranges.length,
297
allSelections: selections,
298
combinedText: selectionCode,
299
});
300
};
301
302
return (
303
<div>
304
<CodeMirror
305
value="Try selecting text with mouse or keyboard. Use Ctrl+Click for multiple selections."
306
onStatistics={handleStatistics}
307
height="100px"
308
/>
309
310
{selectionDetails && (
311
<div style={{ marginTop: 10, fontSize: 12 }}>
312
<div><strong>Main Selection:</strong></div>
313
<div> From: {selectionDetails.mainRange.from}, To: {selectionDetails.mainRange.to}</div>
314
<div> Empty: {selectionDetails.mainRange.empty ? 'Yes' : 'No'}</div>
315
<div> Anchor: {selectionDetails.mainRange.anchor}, Head: {selectionDetails.mainRange.head}</div>
316
317
<div style={{ marginTop: 8 }}><strong>All Selections:</strong></div>
318
<div> Total ranges: {selectionDetails.totalRanges}</div>
319
{selectionDetails.allSelections.map((text, index) => (
320
<div key={index}> Range {index + 1}: "{text}"</div>
321
))}
322
323
{selectionDetails.combinedText && (
324
<div style={{ marginTop: 8 }}>
325
<strong>Combined selection:</strong> "{selectionDetails.combinedText}"
326
</div>
327
)}
328
</div>
329
)}
330
</div>
331
);
332
}
333
```
334
335
### Internal Utilities
336
337
The package also exports internal utility classes for timeout management, primarily used for debouncing editor updates.
338
339
```typescript { .api }
340
/**
341
* Timeout management class for debounced callbacks
342
* Used internally by the editor for optimizing update performance
343
*/
344
class TimeoutLatch {
345
constructor(callback: Function, timeoutMS: number);
346
/** Manually trigger the timeout tick */
347
tick(): void;
348
/** Cancel the timeout */
349
cancel(): void;
350
/** Reset the timeout to its original duration */
351
reset(): void;
352
/** Check if the timeout is done (cancelled or expired) */
353
readonly isDone: boolean;
354
}
355
356
/**
357
* Get the global scheduler instance for timeout management
358
* Returns singleton for browser environments, new instance for server
359
*/
360
function getScheduler(): Scheduler;
361
```
362
363
**Note:** These utilities are primarily for internal use and advanced customization scenarios.
364