Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/frontend/editors/slate/cursors/broadcast.ts
1697 views
1
/*
2
* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.
3
* License: MS-RSL – see LICENSE.md for details
4
*/
5
6
// Broadcast of own cursor.
7
8
// NOTE: We use plural "cursors" here in the optimistic hope that
9
// we'll somehow implement a notion of multiple cursors for slate.
10
// Hmm, that already exists for a single code cell, doesn't it, due
11
// to codemirror.
12
13
import { debounce } from "lodash";
14
import * as CodeMirror from "codemirror";
15
import { useCallback, useRef } from "react";
16
import { Point } from "slate";
17
import { ReactEditor } from "../slate-react";
18
import { slatePointToMarkdownPosition } from "../sync";
19
20
// Cursor broadcast can be expensive since we convert the cursor
21
// from slate coordinates to markdown coordinates each time,
22
// and we currently do this by converting the entire slate
23
// document to markdown, which can take a few ms.
24
const UPDATE_DEBOUNCE_MS = 1500;
25
26
interface Options {
27
editor: ReactEditor;
28
broadcastCursors: (locs: any[]) => void;
29
}
30
31
export const useBroadcastCursors: (Options) => () => void = ({
32
editor,
33
broadcastCursors,
34
}) => {
35
const focusPointRef = useRef<Point | undefined>(undefined);
36
const markdownPositionRef = useRef<CodeMirror.Position | undefined>(
37
undefined
38
);
39
40
const update = useCallback(
41
debounce(() => {
42
markdownPositionRef.current = slatePointToMarkdownPosition(
43
editor,
44
focusPointRef.current
45
);
46
if (
47
markdownPositionRef.current != null &&
48
focusPointRef.current != null
49
) {
50
const { line, ch } = markdownPositionRef.current;
51
broadcastCursors([{ x: ch, y: line }]);
52
}
53
}, UPDATE_DEBOUNCE_MS),
54
[]
55
);
56
57
const onChange = () => {
58
if (!ReactEditor.isFocused(editor)) return;
59
const newFocus = editor.selection?.focus;
60
if (newFocus == null) return;
61
if (
62
focusPointRef.current != null &&
63
Point.equals(newFocus, focusPointRef.current)
64
) {
65
// cursor didn't change (or not collapsed)
66
return;
67
}
68
focusPointRef.current = newFocus;
69
// update/broadcast out cursor position.
70
update();
71
};
72
73
return onChange;
74
};
75
76