48880961b3f2b2a842df53e2bc985253091ba29356eccc47bafeb3c80b2901e04b375f75c5f272a0c88ee0fcce574a569ca65bebdcaaa4f2e223c7fbafe397 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  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. var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
  6. var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
  7. if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
  8. else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
  9. return c > 3 && r && Object.defineProperty(target, key, r), r;
  10. };
  11. var __param = (this && this.__param) || function (paramIndex, decorator) {
  12. return function (target, key) { decorator(target, key, paramIndex); }
  13. };
  14. var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
  15. function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
  16. return new (P || (P = Promise))(function (resolve, reject) {
  17. function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
  18. function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
  19. function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
  20. step((generator = generator.apply(thisArg, _arguments || [])).next());
  21. });
  22. };
  23. import { DataTransfers } from '../../../../base/browser/dnd.js';
  24. import { addDisposableListener } from '../../../../base/browser/dom.js';
  25. import { createCancelablePromise } from '../../../../base/common/async.js';
  26. import { createStringDataTransferItem } from '../../../../base/common/dataTransfer.js';
  27. import { Disposable } from '../../../../base/common/lifecycle.js';
  28. import { Mimes } from '../../../../base/common/mime.js';
  29. import { generateUuid } from '../../../../base/common/uuid.js';
  30. import { toVSDataTransfer, UriList } from '../../../browser/dnd.js';
  31. import { IBulkEditService, ResourceEdit } from '../../../browser/services/bulkEditService.js';
  32. import { Range } from '../../../common/core/range.js';
  33. import { ILanguageFeaturesService } from '../../../common/services/languageFeatures.js';
  34. import { EditorStateCancellationTokenSource } from '../../editorState/browser/editorState.js';
  35. import { performSnippetEdit } from '../../snippet/browser/snippetController2.js';
  36. import { SnippetParser } from '../../snippet/browser/snippetParser.js';
  37. import { IClipboardService } from '../../../../platform/clipboard/common/clipboardService.js';
  38. import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
  39. const vscodeClipboardMime = 'application/vnd.code.copyMetadata';
  40. let CopyPasteController = class CopyPasteController extends Disposable {
  41. constructor(editor, _bulkEditService, _clipboardService, _configurationService, _languageFeaturesService) {
  42. super();
  43. this._bulkEditService = _bulkEditService;
  44. this._clipboardService = _clipboardService;
  45. this._configurationService = _configurationService;
  46. this._languageFeaturesService = _languageFeaturesService;
  47. this._editor = editor;
  48. const container = editor.getContainerDomNode();
  49. this._register(addDisposableListener(container, 'copy', e => this.handleCopy(e)));
  50. this._register(addDisposableListener(container, 'cut', e => this.handleCopy(e)));
  51. this._register(addDisposableListener(container, 'paste', e => this.handlePaste(e), true));
  52. }
  53. arePasteActionsEnabled(model) {
  54. return this._configurationService.getValue('editor.experimental.pasteActions.enabled', {
  55. resource: model.uri
  56. });
  57. }
  58. handleCopy(e) {
  59. var _a;
  60. if (!e.clipboardData || !this._editor.hasTextFocus()) {
  61. return;
  62. }
  63. const model = this._editor.getModel();
  64. const selections = this._editor.getSelections();
  65. if (!model || !(selections === null || selections === void 0 ? void 0 : selections.length)) {
  66. return;
  67. }
  68. if (!this.arePasteActionsEnabled(model)) {
  69. return;
  70. }
  71. const ranges = [...selections];
  72. const primarySelection = selections[0];
  73. const wasFromEmptySelection = primarySelection.isEmpty();
  74. if (wasFromEmptySelection) {
  75. if (!this._editor.getOption(33 /* EditorOption.emptySelectionClipboard */)) {
  76. return;
  77. }
  78. ranges[0] = new Range(primarySelection.startLineNumber, 0, primarySelection.startLineNumber, model.getLineLength(primarySelection.startLineNumber));
  79. }
  80. const providers = this._languageFeaturesService.documentPasteEditProvider.ordered(model).filter(x => !!x.prepareDocumentPaste);
  81. if (!providers.length) {
  82. this.setCopyMetadata(e.clipboardData, { wasFromEmptySelection });
  83. return;
  84. }
  85. const dataTransfer = toVSDataTransfer(e.clipboardData);
  86. // Save off a handle pointing to data that VS Code maintains.
  87. const handle = generateUuid();
  88. this.setCopyMetadata(e.clipboardData, {
  89. id: handle,
  90. wasFromEmptySelection,
  91. });
  92. const promise = createCancelablePromise((token) => __awaiter(this, void 0, void 0, function* () {
  93. const results = yield Promise.all(providers.map(provider => {
  94. return provider.prepareDocumentPaste(model, ranges, dataTransfer, token);
  95. }));
  96. for (const result of results) {
  97. result === null || result === void 0 ? void 0 : result.forEach((value, key) => {
  98. dataTransfer.replace(key, value);
  99. });
  100. }
  101. return dataTransfer;
  102. }));
  103. (_a = this._currentClipboardItem) === null || _a === void 0 ? void 0 : _a.dataTransferPromise.cancel();
  104. this._currentClipboardItem = { handle: handle, dataTransferPromise: promise };
  105. }
  106. setCopyMetadata(dataTransfer, metadata) {
  107. dataTransfer.setData(vscodeClipboardMime, JSON.stringify(metadata));
  108. }
  109. handlePaste(e) {
  110. var _a, _b, _c;
  111. return __awaiter(this, void 0, void 0, function* () {
  112. if (!e.clipboardData || !this._editor.hasTextFocus()) {
  113. return;
  114. }
  115. const selections = this._editor.getSelections();
  116. if (!(selections === null || selections === void 0 ? void 0 : selections.length) || !this._editor.hasModel()) {
  117. return;
  118. }
  119. const model = this._editor.getModel();
  120. if (!this.arePasteActionsEnabled(model)) {
  121. return;
  122. }
  123. let metadata;
  124. const rawMetadata = (_a = e.clipboardData) === null || _a === void 0 ? void 0 : _a.getData(vscodeClipboardMime);
  125. if (rawMetadata && typeof rawMetadata === 'string') {
  126. metadata = JSON.parse(rawMetadata);
  127. }
  128. const providers = this._languageFeaturesService.documentPasteEditProvider.ordered(model);
  129. if (!providers.length) {
  130. return;
  131. }
  132. e.preventDefault();
  133. e.stopImmediatePropagation();
  134. const originalDocVersion = model.getVersionId();
  135. const tokenSource = new EditorStateCancellationTokenSource(this._editor, 1 /* CodeEditorStateFlag.Value */ | 2 /* CodeEditorStateFlag.Selection */);
  136. try {
  137. const dataTransfer = toVSDataTransfer(e.clipboardData);
  138. if ((metadata === null || metadata === void 0 ? void 0 : metadata.id) && ((_b = this._currentClipboardItem) === null || _b === void 0 ? void 0 : _b.handle) === metadata.id) {
  139. const toMergeDataTransfer = yield this._currentClipboardItem.dataTransferPromise;
  140. toMergeDataTransfer.forEach((value, key) => {
  141. dataTransfer.replace(key, value);
  142. });
  143. }
  144. if (!dataTransfer.has(Mimes.uriList)) {
  145. const resources = yield this._clipboardService.readResources();
  146. if (resources.length) {
  147. dataTransfer.append(Mimes.uriList, createStringDataTransferItem(UriList.create(resources)));
  148. }
  149. }
  150. dataTransfer.delete(vscodeClipboardMime);
  151. for (const provider of providers) {
  152. if (!provider.pasteMimeTypes.some(type => {
  153. if (type.toLowerCase() === DataTransfers.FILES.toLowerCase()) {
  154. return [...dataTransfer.values()].some(item => item.asFile());
  155. }
  156. return dataTransfer.has(type);
  157. })) {
  158. continue;
  159. }
  160. const edit = yield provider.provideDocumentPasteEdits(model, selections, dataTransfer, tokenSource.token);
  161. if (originalDocVersion !== model.getVersionId()) {
  162. return;
  163. }
  164. if (edit) {
  165. performSnippetEdit(this._editor, typeof edit.insertText === 'string' ? SnippetParser.escape(edit.insertText) : edit.insertText.snippet, selections);
  166. if (edit.additionalEdit) {
  167. yield this._bulkEditService.apply(ResourceEdit.convert(edit.additionalEdit), { editor: this._editor });
  168. }
  169. return;
  170. }
  171. }
  172. // Default handler
  173. const textDataTransfer = (_c = dataTransfer.get(Mimes.text)) !== null && _c !== void 0 ? _c : dataTransfer.get('text');
  174. if (!textDataTransfer) {
  175. return;
  176. }
  177. const text = yield textDataTransfer.asString();
  178. if (originalDocVersion !== model.getVersionId()) {
  179. return;
  180. }
  181. this._editor.trigger('keyboard', "paste" /* Handler.Paste */, {
  182. text: text,
  183. pasteOnNewLine: metadata === null || metadata === void 0 ? void 0 : metadata.wasFromEmptySelection,
  184. multicursorText: null
  185. });
  186. }
  187. finally {
  188. tokenSource.dispose();
  189. }
  190. });
  191. }
  192. };
  193. CopyPasteController.ID = 'editor.contrib.copyPasteActionController';
  194. CopyPasteController = __decorate([
  195. __param(1, IBulkEditService),
  196. __param(2, IClipboardService),
  197. __param(3, IConfigurationService),
  198. __param(4, ILanguageFeaturesService)
  199. ], CopyPasteController);
  200. export { CopyPasteController };