Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/codeEditor/electron-browser/selectionClipboard.ts
3296 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 * as nls from '../../../../nls.js';
7
import { RunOnceScheduler } from '../../../../base/common/async.js';
8
import { Disposable } from '../../../../base/common/lifecycle.js';
9
import * as platform from '../../../../base/common/platform.js';
10
import { ICodeEditor } from '../../../../editor/browser/editorBrowser.js';
11
import { registerEditorContribution, EditorAction, ServicesAccessor, registerEditorAction, EditorContributionInstantiation } from '../../../../editor/browser/editorExtensions.js';
12
import { ConfigurationChangedEvent, EditorOption } from '../../../../editor/common/config/editorOptions.js';
13
import { ICursorSelectionChangedEvent } from '../../../../editor/common/cursorEvents.js';
14
import { Range } from '../../../../editor/common/core/range.js';
15
import { IEditorContribution, Handler } from '../../../../editor/common/editorCommon.js';
16
import { EndOfLinePreference } from '../../../../editor/common/model.js';
17
import { IClipboardService } from '../../../../platform/clipboard/common/clipboardService.js';
18
import { SelectionClipboardContributionID } from '../browser/selectionClipboard.js';
19
import { IWorkbenchContribution, WorkbenchPhase, registerWorkbenchContribution2 } from '../../../common/contributions.js';
20
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
21
import { EditorContextKeys } from '../../../../editor/common/editorContextKeys.js';
22
import { mainWindow } from '../../../../base/browser/window.js';
23
import { Event } from '../../../../base/common/event.js';
24
import { addDisposableListener, onDidRegisterWindow } from '../../../../base/browser/dom.js';
25
26
export class SelectionClipboard extends Disposable implements IEditorContribution {
27
private static readonly SELECTION_LENGTH_LIMIT = 65536;
28
29
constructor(editor: ICodeEditor, @IClipboardService clipboardService: IClipboardService) {
30
super();
31
32
if (platform.isLinux) {
33
let isEnabled = editor.getOption(EditorOption.selectionClipboard);
34
35
this._register(editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => {
36
if (e.hasChanged(EditorOption.selectionClipboard)) {
37
isEnabled = editor.getOption(EditorOption.selectionClipboard);
38
}
39
}));
40
41
const setSelectionToClipboard = this._register(new RunOnceScheduler(() => {
42
if (!editor.hasModel()) {
43
return;
44
}
45
const model = editor.getModel();
46
let selections = editor.getSelections();
47
selections = selections.slice(0);
48
selections.sort(Range.compareRangesUsingStarts);
49
50
let resultLength = 0;
51
for (const sel of selections) {
52
if (sel.isEmpty()) {
53
// Only write if all cursors have selection
54
return;
55
}
56
resultLength += model.getValueLengthInRange(sel);
57
}
58
59
if (resultLength > SelectionClipboard.SELECTION_LENGTH_LIMIT) {
60
// This is a large selection!
61
// => do not write it to the selection clipboard
62
return;
63
}
64
65
const result: string[] = [];
66
for (const sel of selections) {
67
result.push(model.getValueInRange(sel, EndOfLinePreference.TextDefined));
68
}
69
70
const textToCopy = result.join(model.getEOL());
71
clipboardService.writeText(textToCopy, 'selection');
72
}, 100));
73
74
this._register(editor.onDidChangeCursorSelection((e: ICursorSelectionChangedEvent) => {
75
if (!isEnabled) {
76
return;
77
}
78
if (e.source === 'restoreState') {
79
// do not set selection to clipboard if this selection change
80
// was caused by restoring editors...
81
return;
82
}
83
setSelectionToClipboard.schedule();
84
}));
85
}
86
}
87
88
public override dispose(): void {
89
super.dispose();
90
}
91
}
92
93
class LinuxSelectionClipboardPastePreventer extends Disposable implements IWorkbenchContribution {
94
95
static readonly ID = 'workbench.contrib.linuxSelectionClipboardPastePreventer';
96
97
constructor(
98
@IConfigurationService configurationService: IConfigurationService
99
) {
100
super();
101
102
this._register(Event.runAndSubscribe(onDidRegisterWindow, ({ window, disposables }) => {
103
disposables.add(addDisposableListener(window.document, 'mouseup', e => {
104
if (e.button === 1) {
105
// middle button
106
const config = configurationService.getValue<{ selectionClipboard: boolean }>('editor');
107
if (!config.selectionClipboard) {
108
// selection clipboard is disabled
109
// try to stop the upcoming paste
110
e.preventDefault();
111
}
112
}
113
}));
114
}, { window: mainWindow, disposables: this._store }));
115
}
116
}
117
118
class PasteSelectionClipboardAction extends EditorAction {
119
120
constructor() {
121
super({
122
id: 'editor.action.selectionClipboardPaste',
123
label: nls.localize2('actions.pasteSelectionClipboard', "Paste Selection Clipboard"),
124
precondition: EditorContextKeys.writable
125
});
126
}
127
128
public async run(accessor: ServicesAccessor, editor: ICodeEditor, args: any): Promise<void> {
129
const clipboardService = accessor.get(IClipboardService);
130
131
// read selection clipboard
132
const text = await clipboardService.readText('selection');
133
134
editor.trigger('keyboard', Handler.Paste, {
135
text: text,
136
pasteOnNewLine: false,
137
multicursorText: null
138
});
139
}
140
}
141
142
registerEditorContribution(SelectionClipboardContributionID, SelectionClipboard, EditorContributionInstantiation.Eager); // eager because it needs to listen to selection change events
143
if (platform.isLinux) {
144
registerWorkbenchContribution2(LinuxSelectionClipboardPastePreventer.ID, LinuxSelectionClipboardPastePreventer, WorkbenchPhase.BlockRestore); // eager because it listens to mouse-up events globally
145
registerEditorAction(PasteSelectionClipboardAction);
146
}
147
148