Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/test/simulation/workbench/components/diffEditor.tsx
13399 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import type * as monaco from 'monaco-editor';
7
import * as React from 'react';
8
import { IDiagnosticComparison, IRange } from '../../shared/sharedTypes';
9
import { monacoModule } from '../utils/utils';
10
import { DraggableBottomBorder } from './draggableBottomBorder';
11
import { createDiagnosticDecorations } from './editor';
12
import { rangeToMonacoRange } from './monacoUtils';
13
14
type Props = {
15
original: string;
16
modified: string;
17
languageId: string;
18
diagnostics?: IDiagnosticComparison;
19
selections?: {
20
before: IRange | undefined;
21
after: IRange | undefined;
22
};
23
};
24
25
const LINE_HEIGHT = 19;
26
27
export const DiffEditor = (({ original, modified, languageId, diagnostics, selections }: Props) => {
28
29
const containerRef = React.useRef<HTMLDivElement | null>(null);
30
const [diffEditor, setDiffEditor] = React.useState<monaco.editor.IStandaloneDiffEditor | null>(null);
31
const [height, setHeight] = React.useState<number>(300);
32
const [altPressed, setAltPressed] = React.useState(false);
33
34
const monaco = monacoModule.value;
35
36
React.useEffect(() => {
37
if (!containerRef.current) {
38
return;
39
}
40
41
const myEditor = monaco.editor.createDiffEditor(containerRef.current, {
42
automaticLayout: true,
43
lineHeight: LINE_HEIGHT,
44
minimap: { enabled: false },
45
readOnly: true,
46
renderLineHighlight: 'none',
47
scrollBeyondLastLine: false,
48
overviewRulerLanes: 0,
49
ignoreTrimWhitespace: false,
50
diffWordWrap: 'off',
51
scrollbar: {
52
alwaysConsumeMouseWheel: true, // setting to false allows scrolling in window when scroll reaches end of the editor
53
}
54
});
55
setDiffEditor(myEditor);
56
57
return () => {
58
const model = myEditor.getModel();
59
if (model) {
60
const { original, modified } = model;
61
original.dispose();
62
modified.dispose();
63
}
64
myEditor.dispose();
65
};
66
}, []);
67
68
React.useEffect(() => {
69
if (diffEditor) {
70
let model = diffEditor.getModel();
71
if (model) {
72
const { original: originalModel, modified: modifiedModel } = model;
73
originalModel.setValue(original);
74
monaco.editor.setModelLanguage(originalModel, languageId);
75
modifiedModel.setValue(modified);
76
monaco.editor.setModelLanguage(modifiedModel, languageId);
77
} else {
78
const model1 = monaco.editor.createModel(original, languageId);
79
const model2 = monaco.editor.createModel(modified, languageId);
80
model = { original: model1, modified: model2 };
81
diffEditor.setModel(model);
82
}
83
84
if (diagnostics) {
85
diffEditor.getModifiedEditor().createDecorationsCollection().set(createDiagnosticDecorations(diagnostics.after, model.modified));
86
diffEditor.getOriginalEditor().createDecorationsCollection().set(createDiagnosticDecorations(diagnostics.before, model.original));
87
}
88
89
if (selections) {
90
if (selections.before) {
91
const mselection = rangeToMonacoRange(selections.before);
92
diffEditor.getOriginalEditor().setSelection(mselection);
93
}
94
if (selections.after) {
95
const mselection = rangeToMonacoRange(selections.after);
96
diffEditor.getModifiedEditor().setSelection(mselection);
97
}
98
}
99
100
// Navigate to first diff
101
diffEditor.onDidUpdateDiff(() => {
102
if (diffEditor === null) { return; }
103
104
const changes = diffEditor.getLineChanges();
105
if (changes === null || changes.length === 0) {
106
return;
107
}
108
109
const change = changes[0];
110
diffEditor.getModifiedEditor().revealLinesInCenter(change.modifiedStartLineNumber, change.modifiedEndLineNumber);
111
});
112
}
113
}, [diffEditor, original, modified, languageId, diagnostics, selections]);
114
115
React.useEffect(() => {
116
const handleKeyDown = (e: KeyboardEvent) => {
117
if (e.altKey) {
118
setAltPressed(true);
119
}
120
};
121
122
const handleKeyUp = (e: KeyboardEvent) => {
123
if (!e.altKey) {
124
setAltPressed(false);
125
}
126
};
127
128
window.addEventListener('keydown', handleKeyDown);
129
window.addEventListener('keyup', handleKeyUp);
130
return () => {
131
window.removeEventListener('keydown', handleKeyDown);
132
window.removeEventListener('keyup', handleKeyUp);
133
};
134
}, []);
135
136
const handleWheel = (e: React.WheelEvent) => {
137
if (altPressed) {
138
e.preventDefault();
139
e.stopPropagation();
140
}
141
};
142
143
return (
144
<div>
145
<div className='file-editor-container' style={{ height: `${height}px`, position: 'relative' }} ref={containerRef}>
146
<div
147
className='overlay'
148
style={{
149
position: 'absolute', top: 0, left: 0, right: 0, bottom: 0,
150
pointerEvents: altPressed ? 'auto' : 'none',
151
backgroundColor: 'transparent',
152
zIndex: 1000
153
}}
154
onWheel={handleWheel}
155
/>
156
</div>
157
<DraggableBottomBorder height={height} setHeight={setHeight} />
158
</div>
159
);
160
});
161
162