123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353 |
- /*---------------------------------------------------------------------------------------------
- * Copyright (c) Microsoft Corporation. All rights reserved.
- * Licensed under the MIT License. See License.txt in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
- 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;
- return c > 3 && r && Object.defineProperty(target, key, r), r;
- };
- var __param = (this && this.__param) || function (paramIndex, decorator) {
- return function (target, key) { decorator(target, key, paramIndex); }
- };
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
- return new (P || (P = Promise))(function (resolve, reject) {
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
- step((generator = generator.apply(thisArg, _arguments || [])).next());
- });
- };
- import { alert } from '../../../base/browser/ui/aria/aria.js';
- import { IdleValue, raceCancellation } from '../../../base/common/async.js';
- import { CancellationToken, CancellationTokenSource } from '../../../base/common/cancellation.js';
- import { onUnexpectedError } from '../../../base/common/errors.js';
- import { DisposableStore } from '../../../base/common/lifecycle.js';
- import { assertType } from '../../../base/common/types.js';
- import { URI } from '../../../base/common/uri.js';
- import { EditorStateCancellationTokenSource } from '../../browser/core/editorState.js';
- import { EditorAction, EditorCommand, registerEditorAction, registerEditorCommand, registerEditorContribution, registerModelAndPositionCommand } from '../../browser/editorExtensions.js';
- import { IBulkEditService, ResourceEdit } from '../../browser/services/bulkEditService.js';
- import { ICodeEditorService } from '../../browser/services/codeEditorService.js';
- import { Position } from '../../common/core/position.js';
- import { Range } from '../../common/core/range.js';
- import { EditorContextKeys } from '../../common/editorContextKeys.js';
- import { RenameProviderRegistry } from '../../common/modes.js';
- import { ITextResourceConfigurationService } from '../../common/services/textResourceConfigurationService.js';
- import { MessageController } from '../message/messageController.js';
- import * as nls from '../../../nls.js';
- import { Extensions } from '../../../platform/configuration/common/configurationRegistry.js';
- import { ContextKeyExpr } from '../../../platform/contextkey/common/contextkey.js';
- import { IInstantiationService } from '../../../platform/instantiation/common/instantiation.js';
- import { ILogService } from '../../../platform/log/common/log.js';
- import { INotificationService } from '../../../platform/notification/common/notification.js';
- import { IEditorProgressService } from '../../../platform/progress/common/progress.js';
- import { Registry } from '../../../platform/registry/common/platform.js';
- import { CONTEXT_RENAME_INPUT_VISIBLE, RenameInputField } from './renameInputField.js';
- class RenameSkeleton {
- constructor(model, position) {
- this.model = model;
- this.position = position;
- this._providerRenameIdx = 0;
- this._providers = RenameProviderRegistry.ordered(model);
- }
- hasProvider() {
- return this._providers.length > 0;
- }
- resolveRenameLocation(token) {
- return __awaiter(this, void 0, void 0, function* () {
- const rejects = [];
- for (this._providerRenameIdx = 0; this._providerRenameIdx < this._providers.length; this._providerRenameIdx++) {
- const provider = this._providers[this._providerRenameIdx];
- if (!provider.resolveRenameLocation) {
- break;
- }
- let res = yield provider.resolveRenameLocation(this.model, this.position, token);
- if (!res) {
- continue;
- }
- if (res.rejectReason) {
- rejects.push(res.rejectReason);
- continue;
- }
- return res;
- }
- const word = this.model.getWordAtPosition(this.position);
- if (!word) {
- return {
- range: Range.fromPositions(this.position),
- text: '',
- rejectReason: rejects.length > 0 ? rejects.join('\n') : undefined
- };
- }
- return {
- range: new Range(this.position.lineNumber, word.startColumn, this.position.lineNumber, word.endColumn),
- text: word.word,
- rejectReason: rejects.length > 0 ? rejects.join('\n') : undefined
- };
- });
- }
- provideRenameEdits(newName, token) {
- return __awaiter(this, void 0, void 0, function* () {
- return this._provideRenameEdits(newName, this._providerRenameIdx, [], token);
- });
- }
- _provideRenameEdits(newName, i, rejects, token) {
- return __awaiter(this, void 0, void 0, function* () {
- const provider = this._providers[i];
- if (!provider) {
- return {
- edits: [],
- rejectReason: rejects.join('\n')
- };
- }
- const result = yield provider.provideRenameEdits(this.model, this.position, newName, token);
- if (!result) {
- return this._provideRenameEdits(newName, i + 1, rejects.concat(nls.localize('no result', "No result.")), token);
- }
- else if (result.rejectReason) {
- return this._provideRenameEdits(newName, i + 1, rejects.concat(result.rejectReason), token);
- }
- return result;
- });
- }
- }
- export function rename(model, position, newName) {
- return __awaiter(this, void 0, void 0, function* () {
- const skeleton = new RenameSkeleton(model, position);
- const loc = yield skeleton.resolveRenameLocation(CancellationToken.None);
- if (loc === null || loc === void 0 ? void 0 : loc.rejectReason) {
- return { edits: [], rejectReason: loc.rejectReason };
- }
- return skeleton.provideRenameEdits(newName, CancellationToken.None);
- });
- }
- // --- register actions and commands
- let RenameController = class RenameController {
- constructor(editor, _instaService, _notificationService, _bulkEditService, _progressService, _logService, _configService) {
- this.editor = editor;
- this._instaService = _instaService;
- this._notificationService = _notificationService;
- this._bulkEditService = _bulkEditService;
- this._progressService = _progressService;
- this._logService = _logService;
- this._configService = _configService;
- this._dispoableStore = new DisposableStore();
- this._cts = new CancellationTokenSource();
- this._renameInputField = this._dispoableStore.add(new IdleValue(() => this._dispoableStore.add(this._instaService.createInstance(RenameInputField, this.editor, ['acceptRenameInput', 'acceptRenameInputWithPreview']))));
- }
- static get(editor) {
- return editor.getContribution(RenameController.ID);
- }
- dispose() {
- this._dispoableStore.dispose();
- this._cts.dispose(true);
- }
- run() {
- return __awaiter(this, void 0, void 0, function* () {
- this._cts.dispose(true);
- if (!this.editor.hasModel()) {
- return undefined;
- }
- const position = this.editor.getPosition();
- const skeleton = new RenameSkeleton(this.editor.getModel(), position);
- if (!skeleton.hasProvider()) {
- return undefined;
- }
- this._cts = new EditorStateCancellationTokenSource(this.editor, 4 /* Position */ | 1 /* Value */);
- // resolve rename location
- let loc;
- try {
- const resolveLocationOperation = skeleton.resolveRenameLocation(this._cts.token);
- this._progressService.showWhile(resolveLocationOperation, 250);
- loc = yield resolveLocationOperation;
- }
- catch (e) {
- MessageController.get(this.editor).showMessage(e || nls.localize('resolveRenameLocationFailed', "An unknown error occurred while resolving rename location"), position);
- return undefined;
- }
- if (!loc) {
- return undefined;
- }
- if (loc.rejectReason) {
- MessageController.get(this.editor).showMessage(loc.rejectReason, position);
- return undefined;
- }
- if (this._cts.token.isCancellationRequested) {
- return undefined;
- }
- this._cts.dispose();
- this._cts = new EditorStateCancellationTokenSource(this.editor, 4 /* Position */ | 1 /* Value */, loc.range);
- // do rename at location
- let selection = this.editor.getSelection();
- let selectionStart = 0;
- let selectionEnd = loc.text.length;
- if (!Range.isEmpty(selection) && !Range.spansMultipleLines(selection) && Range.containsRange(loc.range, selection)) {
- selectionStart = Math.max(0, selection.startColumn - loc.range.startColumn);
- selectionEnd = Math.min(loc.range.endColumn, selection.endColumn) - loc.range.startColumn;
- }
- const supportPreview = this._bulkEditService.hasPreviewHandler() && this._configService.getValue(this.editor.getModel().uri, 'editor.rename.enablePreview');
- const inputFieldResult = yield this._renameInputField.value.getInput(loc.range, loc.text, selectionStart, selectionEnd, supportPreview, this._cts.token);
- // no result, only hint to focus the editor or not
- if (typeof inputFieldResult === 'boolean') {
- if (inputFieldResult) {
- this.editor.focus();
- }
- return undefined;
- }
- this.editor.focus();
- const renameOperation = raceCancellation(skeleton.provideRenameEdits(inputFieldResult.newName, this._cts.token), this._cts.token).then((renameResult) => __awaiter(this, void 0, void 0, function* () {
- if (!renameResult || !this.editor.hasModel()) {
- return;
- }
- if (renameResult.rejectReason) {
- this._notificationService.info(renameResult.rejectReason);
- return;
- }
- // collapse selection to active end
- this.editor.setSelection(Range.fromPositions(this.editor.getSelection().getPosition()));
- this._bulkEditService.apply(ResourceEdit.convert(renameResult), {
- editor: this.editor,
- showPreview: inputFieldResult.wantsPreview,
- label: nls.localize('label', "Renaming '{0}'", loc === null || loc === void 0 ? void 0 : loc.text),
- quotableLabel: nls.localize('quotableLabel', "Renaming {0}", loc === null || loc === void 0 ? void 0 : loc.text),
- }).then(result => {
- if (result.ariaSummary) {
- alert(nls.localize('aria', "Successfully renamed '{0}' to '{1}'. Summary: {2}", loc.text, inputFieldResult.newName, result.ariaSummary));
- }
- }).catch(err => {
- this._notificationService.error(nls.localize('rename.failedApply', "Rename failed to apply edits"));
- this._logService.error(err);
- });
- }), err => {
- this._notificationService.error(nls.localize('rename.failed', "Rename failed to compute edits"));
- this._logService.error(err);
- });
- this._progressService.showWhile(renameOperation, 250);
- return renameOperation;
- });
- }
- acceptRenameInput(wantsPreview) {
- this._renameInputField.value.acceptInput(wantsPreview);
- }
- cancelRenameInput() {
- this._renameInputField.value.cancelInput(true);
- }
- };
- RenameController.ID = 'editor.contrib.renameController';
- RenameController = __decorate([
- __param(1, IInstantiationService),
- __param(2, INotificationService),
- __param(3, IBulkEditService),
- __param(4, IEditorProgressService),
- __param(5, ILogService),
- __param(6, ITextResourceConfigurationService)
- ], RenameController);
- // ---- action implementation
- export class RenameAction extends EditorAction {
- constructor() {
- super({
- id: 'editor.action.rename',
- label: nls.localize('rename.label', "Rename Symbol"),
- alias: 'Rename Symbol',
- precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasRenameProvider),
- kbOpts: {
- kbExpr: EditorContextKeys.editorTextFocus,
- primary: 60 /* F2 */,
- weight: 100 /* EditorContrib */
- },
- contextMenuOpts: {
- group: '1_modification',
- order: 1.1
- }
- });
- }
- runCommand(accessor, args) {
- const editorService = accessor.get(ICodeEditorService);
- const [uri, pos] = Array.isArray(args) && args || [undefined, undefined];
- if (URI.isUri(uri) && Position.isIPosition(pos)) {
- return editorService.openCodeEditor({ resource: uri }, editorService.getActiveCodeEditor()).then(editor => {
- if (!editor) {
- return;
- }
- editor.setPosition(pos);
- editor.invokeWithinContext(accessor => {
- this.reportTelemetry(accessor, editor);
- return this.run(accessor, editor);
- });
- }, onUnexpectedError);
- }
- return super.runCommand(accessor, args);
- }
- run(accessor, editor) {
- const controller = RenameController.get(editor);
- if (controller) {
- return controller.run();
- }
- return Promise.resolve();
- }
- }
- registerEditorContribution(RenameController.ID, RenameController);
- registerEditorAction(RenameAction);
- const RenameCommand = EditorCommand.bindToContribution(RenameController.get);
- registerEditorCommand(new RenameCommand({
- id: 'acceptRenameInput',
- precondition: CONTEXT_RENAME_INPUT_VISIBLE,
- handler: x => x.acceptRenameInput(false),
- kbOpts: {
- weight: 100 /* EditorContrib */ + 99,
- kbExpr: EditorContextKeys.focus,
- primary: 3 /* Enter */
- }
- }));
- registerEditorCommand(new RenameCommand({
- id: 'acceptRenameInputWithPreview',
- precondition: ContextKeyExpr.and(CONTEXT_RENAME_INPUT_VISIBLE, ContextKeyExpr.has('config.editor.rename.enablePreview')),
- handler: x => x.acceptRenameInput(true),
- kbOpts: {
- weight: 100 /* EditorContrib */ + 99,
- kbExpr: EditorContextKeys.focus,
- primary: 1024 /* Shift */ + 3 /* Enter */
- }
- }));
- registerEditorCommand(new RenameCommand({
- id: 'cancelRenameInput',
- precondition: CONTEXT_RENAME_INPUT_VISIBLE,
- handler: x => x.cancelRenameInput(),
- kbOpts: {
- weight: 100 /* EditorContrib */ + 99,
- kbExpr: EditorContextKeys.focus,
- primary: 9 /* Escape */,
- secondary: [1024 /* Shift */ | 9 /* Escape */]
- }
- }));
- // ---- api bridge command
- registerModelAndPositionCommand('_executeDocumentRenameProvider', function (model, position, ...args) {
- const [newName] = args;
- assertType(typeof newName === 'string');
- return rename(model, position, newName);
- });
- registerModelAndPositionCommand('_executePrepareRename', function (model, position) {
- return __awaiter(this, void 0, void 0, function* () {
- const skeleton = new RenameSkeleton(model, position);
- const loc = yield skeleton.resolveRenameLocation(CancellationToken.None);
- if (loc === null || loc === void 0 ? void 0 : loc.rejectReason) {
- throw new Error(loc.rejectReason);
- }
- return loc;
- });
- });
- //todo@jrieken use editor options world
- Registry.as(Extensions.Configuration).registerConfiguration({
- id: 'editor',
- properties: {
- 'editor.rename.enablePreview': {
- scope: 5 /* LANGUAGE_OVERRIDABLE */,
- description: nls.localize('enablePreview', "Enable/disable the ability to preview changes before renaming"),
- default: true,
- type: 'boolean'
- }
- }
- });
|