-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMonacoAdapter.js
157 lines (148 loc) · 4.73 KB
/
MonacoAdapter.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
import TextOperation from './TextOperation';
import { lineAndColumnToIndex } from './utils/monaco-index-converter';
import getSelection from './utils/get-selection';
class MonacoAdapter {
constructor(monacoIns) {
this.callbacks = null;
this.monacoIns = monacoIns;
this.ignoreNextChange = false;
this.liveOperationCode = getValue(monacoIns);
monacoIns.onDidChangeModelContent(event => {
if (!this.ignoreNextChange) {
try {
const pair = this.operationFromMonacoChange(event, this.monacoIns);
this.trigger('change', pair);
} catch (err) {
console.log('错误信息', err);
throw err;
}
}
});
/**
* https://microsoft.github.io/monaco-editor/api/enums/monaco.editor.cursorchangereason.html
*/
monacoIns.onDidChangeCursorSelection(event => {
const { selection } = event;
const model = monacoIns.getModel();
const linesContent = model.getLinesContent() || [];
const selectionData = getSelection(linesContent, selection);
this.trigger('selectionChange', selectionData);
});
monacoIns.onDidBlurEditorText(() => {
this.trigger('blur');
})
}
/**
* 将编辑器操作封装成operation
* @param {*} event 编辑器change事件
* event.change.rangeLength 被替换范围的长度,
* 这里跟其他编辑器不太一样当你输入一个字母弹出提示然后回车,
* 这里的rangeLength就是那个输入的字母,
* 然后event.change.text为回车的提示文本
* @param {*} monacoIns 编辑器实例
*/
operationFromMonacoChange(event) {
let composedCode = this.liveOperationCode;
let operation;
for(let i = 0; i < event.changes.length; i++) {
const change = event.changes[i];
const cursorStartOffset = lineAndColumnToIndex(
composedCode.split(/\n/),
change.range.startLineNumber,
change.range.startColumn
);
const {
rangeLength, // 删除或替换长度
text, // 增加文本
} = change;
const newOt = new TextOperation();
newOt.retain(cursorStartOffset);
if (rangeLength > 0) {
newOt.delete(rangeLength);
}
if (text) {
newOt.insert(text);
}
const remaining = composedCode.length - newOt.baseLength;
if (remaining > 0) {
newOt.retain(remaining);
}
operation = operation ? operation.compose(newOt) : newOt;
composedCode = operation.apply(this.liveOperationCode);
}
this.liveOperationCode = composedCode;
return operation;
}
/**
* 触发当前对象注册的回调事件
* @param {*} eventName 注册给当前对象的事件名称
* @param {...any} args 传递给事件回调参数
*/
trigger(eventName, ...args) {
const action = this.callbacks && this.callbacks[eventName];
action && action.apply(this, args);
}
/**
* 注册回调函数
* @param {object} cb 一个对象key是事件名称value是事件名称对应的回调
*/
registerCallbacks(cb) {
this.callbacks = cb;
}
applyOperation(operation) {
// 因为是服务器过来的operation操作编辑器
// 所以这里我们要忽略下一次编辑器的修改
this.ignoreNextChange = true;
this.applyOperationToMonaco(operation);
this.ignoreNextChange = false;
}
applyOperationToMonaco(operation, pushStack = false) {
const { ops } = operation;
const model = this.monacoIns.getModel();
let index = 0;
const results = [];
for(let i = 0; i < ops.length; i++) {
const op = ops[i];
// 如果某个操作是保留则我们的索引保持跟进
if (TextOperation.isRetain(op)) {
index += op;
} else if (TextOperation.isInsert(op)) {
// 某个操作是插入我们替换编辑器的内容
const insert = model.getPositionAt(index);
results.push({
forceMoveMarkers: true,
range: new monaco.Range(
insert.lineNumber,
insert.column,
insert.lineNumber,
insert.column
),
text: op,
});
} else if (TextOperation.isDelete(op)) {
const start = model.getPositionAt(index);
const end = model.getPositionAt(index - op)
results.push({
forceMoveMarkers: false,
range: new monaco.Range(
start.lineNumber,
start.column,
end.lineNumber,
end.column
),
text: null,
});
index -= op;
}
}
if (pushStack) {
model.pushEditOperations([], results);
} else {
model.applyEdits(results);
}
}
}
export default MonacoAdapter;
function getValue(monacoIns) {
return monacoIns.getModel().getValue(1) || '';
}