|
1 | 1 | import { useEffect, useState } from 'react'; |
2 | | -import { EditorState, StateEffect } from '@codemirror/state'; |
| 2 | +import { Annotation, EditorState, StateEffect } from '@codemirror/state'; |
3 | 3 | import { indentWithTab } from '@codemirror/commands'; |
4 | 4 | import { EditorView, keymap, ViewUpdate, placeholder } from '@codemirror/view'; |
5 | 5 | import { basicSetup } from '@uiw/codemirror-extensions-basic-setup'; |
6 | 6 | import { oneDark } from '@codemirror/theme-one-dark'; |
7 | 7 | import { getStatistics } from './utils'; |
8 | 8 | import { ReactCodeMirrorProps } from '.'; |
9 | 9 |
|
| 10 | +const External = Annotation.define<boolean>(); |
| 11 | + |
10 | 12 | export interface UseCodeMirror extends ReactCodeMirrorProps { |
11 | 13 | container?: HTMLDivElement | null; |
12 | 14 | } |
@@ -60,7 +62,13 @@ export function useCodeMirror(props: UseCodeMirror) { |
60 | 62 | }, |
61 | 63 | }); |
62 | 64 | const updateListener = EditorView.updateListener.of((vu: ViewUpdate) => { |
63 | | - if (vu.docChanged && typeof onChange === 'function') { |
| 65 | + if ( |
| 66 | + vu.docChanged && |
| 67 | + typeof onChange === 'function' && |
| 68 | + // Fix echoing of the remote changes: |
| 69 | + // If transaction is market as remote we don't have to call `onChange` handler again |
| 70 | + !vu.transactions.some((tr) => tr.annotation(External)) |
| 71 | + ) { |
64 | 72 | const doc = vu.state.doc; |
65 | 73 | const value = doc.toString(); |
66 | 74 | onChange(value, vu); |
@@ -188,6 +196,7 @@ export function useCodeMirror(props: UseCodeMirror) { |
188 | 196 | if (view && value !== currentValue) { |
189 | 197 | view.dispatch({ |
190 | 198 | changes: { from: 0, to: currentValue.length, insert: value || '' }, |
| 199 | + annotations: [External.of(true)], |
191 | 200 | }); |
192 | 201 | } |
193 | 202 | }, [value, view]); |
|
0 commit comments