UNPKG

monaco-editor

Version:
330 lines (327 loc) • 16 kB
import '../../../../../base/common/observableInternal/index.js'; import { splitLines } from '../../../../../base/common/strings.js'; import { vUnion, vObj, vOptionalProp, vWithJsonSchemaRef, vUndefined, vBoolean, vString } from '../../../../../base/common/validation.js'; import { localize2, localize } from '../../../../../nls.js'; import { CONTEXT_ACCESSIBILITY_MODE_ENABLED } from '../../../../../platform/accessibility/common/accessibility.js'; import { MenuId, Action2 } from '../../../../../platform/actions/common/actions.js'; import { IClipboardService } from '../../../../../platform/clipboard/common/clipboardService.js'; import { IConfigurationService } from '../../../../../platform/configuration/common/configuration.js'; import { ContextKeyExpr } from '../../../../../platform/contextkey/common/contextkey.js'; import { KeybindingsRegistry } from '../../../../../platform/keybinding/common/keybindingsRegistry.js'; import { INotificationService, Severity } from '../../../../../platform/notification/common/notification.js'; import { EditorAction } from '../../../../browser/editorExtensions.js'; import { EditorContextKeys } from '../../../../common/editorContextKeys.js'; import { ILanguageFeaturesService } from '../../../../common/services/languageFeatures.js'; import { Context } from '../../../suggest/browser/suggest.js'; import { showNextInlineSuggestionActionId, showPreviousInlineSuggestionActionId, inlineSuggestCommitId, hideInlineCompletionId, toggleShowCollapsedId, jumpToNextInlineEditId } from './commandIds.js'; import { InlineCompletionContextKeys } from './inlineCompletionContextKeys.js'; import { InlineCompletionsController } from './inlineCompletionsController.js'; import { transaction, asyncTransaction } from '../../../../../base/common/observableInternal/transaction.js'; /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ class ShowNextInlineSuggestionAction extends EditorAction { static { this.ID = showNextInlineSuggestionActionId; } constructor() { super({ id: ShowNextInlineSuggestionAction.ID, label: localize2(1183, "Show Next Inline Suggestion"), precondition: ContextKeyExpr.and(EditorContextKeys.writable, InlineCompletionContextKeys.inlineSuggestionVisible), kbOpts: { weight: 100, primary: 512 /* KeyMod.Alt */ | 94 /* KeyCode.BracketRight */, }, }); } async run(accessor, editor) { const controller = InlineCompletionsController.get(editor); controller?.model.get()?.next(); } } class ShowPreviousInlineSuggestionAction extends EditorAction { static { this.ID = showPreviousInlineSuggestionActionId; } constructor() { super({ id: ShowPreviousInlineSuggestionAction.ID, label: localize2(1184, "Show Previous Inline Suggestion"), precondition: ContextKeyExpr.and(EditorContextKeys.writable, InlineCompletionContextKeys.inlineSuggestionVisible), kbOpts: { weight: 100, primary: 512 /* KeyMod.Alt */ | 92 /* KeyCode.BracketLeft */, }, }); } async run(accessor, editor) { const controller = InlineCompletionsController.get(editor); controller?.model.get()?.previous(); } } const providerIdSchemaUri = 'vscode://schemas/inlineCompletionProviderIdArgs'; function inlineCompletionProviderGetMatcher(provider) { const result = []; if (provider.providerId) { result.push(provider.providerId.toStringWithoutVersion()); result.push(provider.providerId.extensionId + ':*'); } return result; } const argsValidator = vUnion(vObj({ showNoResultNotification: vOptionalProp(vBoolean()), providerId: vOptionalProp(vWithJsonSchemaRef(providerIdSchemaUri, vString())), explicit: vOptionalProp(vBoolean()), }), vUndefined()); class TriggerInlineSuggestionAction extends EditorAction { constructor() { super({ id: 'editor.action.inlineSuggest.trigger', label: localize2(1185, "Trigger Inline Suggestion"), precondition: EditorContextKeys.writable, metadata: { description: localize(1172, "Triggers an inline suggestion in the editor."), args: [{ name: 'args', description: localize(1173, "Options for triggering inline suggestions."), isOptional: true, schema: argsValidator.getJSONSchema(), }] } }); } async run(accessor, editor, args) { const notificationService = accessor.get(INotificationService); const languageFeaturesService = accessor.get(ILanguageFeaturesService); const controller = InlineCompletionsController.get(editor); const validatedArgs = argsValidator.validateOrThrow(args); const provider = validatedArgs?.providerId ? languageFeaturesService.inlineCompletionsProvider.all(editor.getModel()) .find(p => inlineCompletionProviderGetMatcher(p).some(m => m === validatedArgs.providerId)) : undefined; await asyncTransaction(async (tx) => { /** @description triggerExplicitly from command */ await controller?.model.get()?.trigger(tx, { provider: provider, explicit: validatedArgs?.explicit ?? true, }); controller?.playAccessibilitySignal(tx); }); if (validatedArgs?.showNoResultNotification) { if (!controller?.model.get()?.state.get()) { notificationService.notify({ severity: Severity.Info, message: localize(1174, "No inline suggestion is available.") }); } } } } class AcceptNextWordOfInlineCompletion extends EditorAction { constructor() { super({ id: 'editor.action.inlineSuggest.acceptNextWord', label: localize2(1186, "Accept Next Word Of Inline Suggestion"), precondition: ContextKeyExpr.and(EditorContextKeys.writable, InlineCompletionContextKeys.inlineSuggestionVisible), kbOpts: { weight: 100 /* KeybindingWeight.EditorContrib */ + 1, primary: 2048 /* KeyMod.CtrlCmd */ | 17 /* KeyCode.RightArrow */, kbExpr: ContextKeyExpr.and(EditorContextKeys.writable, InlineCompletionContextKeys.inlineSuggestionVisible, InlineCompletionContextKeys.cursorBeforeGhostText, CONTEXT_ACCESSIBILITY_MODE_ENABLED.negate()), }, menuOpts: [{ menuId: MenuId.InlineSuggestionToolbar, title: localize(1175, 'Accept Word'), group: 'primary', order: 2, }], }); } async run(accessor, editor) { const controller = InlineCompletionsController.get(editor); await controller?.model.get()?.acceptNextWord(); } } class AcceptNextLineOfInlineCompletion extends EditorAction { constructor() { super({ id: 'editor.action.inlineSuggest.acceptNextLine', label: localize2(1187, "Accept Next Line Of Inline Suggestion"), precondition: ContextKeyExpr.and(EditorContextKeys.writable, InlineCompletionContextKeys.inlineSuggestionVisible), kbOpts: { weight: 100 /* KeybindingWeight.EditorContrib */ + 1, }, menuOpts: [{ menuId: MenuId.InlineSuggestionToolbar, title: localize(1176, 'Accept Line'), group: 'secondary', order: 2, }], }); } async run(accessor, editor) { const controller = InlineCompletionsController.get(editor); await controller?.model.get()?.acceptNextLine(); } } class AcceptInlineCompletion extends EditorAction { constructor() { super({ id: inlineSuggestCommitId, label: localize2(1188, "Accept Inline Suggestion"), precondition: ContextKeyExpr.or(InlineCompletionContextKeys.inlineSuggestionVisible, InlineCompletionContextKeys.inlineEditVisible), menuOpts: [{ menuId: MenuId.InlineSuggestionToolbar, title: localize(1177, "Accept"), group: 'primary', order: 2, }, { menuId: MenuId.InlineEditsActions, title: localize(1178, "Accept"), group: 'primary', order: 2, }], kbOpts: [ { primary: 2 /* KeyCode.Tab */, weight: 200, kbExpr: ContextKeyExpr.or(ContextKeyExpr.and(InlineCompletionContextKeys.inlineSuggestionVisible, EditorContextKeys.tabMovesFocus.toNegated(), Context.Visible.toNegated(), EditorContextKeys.hoverFocused.toNegated(), InlineCompletionContextKeys.hasSelection.toNegated(), InlineCompletionContextKeys.inlineSuggestionHasIndentationLessThanTabSize), ContextKeyExpr.and(InlineCompletionContextKeys.inlineEditVisible, EditorContextKeys.tabMovesFocus.toNegated(), Context.Visible.toNegated(), EditorContextKeys.hoverFocused.toNegated(), InlineCompletionContextKeys.tabShouldAcceptInlineEdit)), } ], }); } async run(accessor, editor) { const controller = InlineCompletionsController.getInFocusedEditorOrParent(accessor); if (controller) { controller.model.get()?.accept(controller.editor); controller.editor.focus(); } } } KeybindingsRegistry.registerKeybindingRule({ id: inlineSuggestCommitId, weight: 202, // greater than jump primary: 2 /* KeyCode.Tab */, when: ContextKeyExpr.and(InlineCompletionContextKeys.inInlineEditsPreviewEditor) }); class JumpToNextInlineEdit extends EditorAction { constructor() { super({ id: jumpToNextInlineEditId, label: localize2(1189, "Jump to next inline edit"), precondition: InlineCompletionContextKeys.inlineEditVisible, menuOpts: [{ menuId: MenuId.InlineEditsActions, title: localize(1179, "Jump"), group: 'primary', order: 1, when: InlineCompletionContextKeys.cursorAtInlineEdit.toNegated(), }], kbOpts: { primary: 2 /* KeyCode.Tab */, weight: 201, kbExpr: ContextKeyExpr.and(InlineCompletionContextKeys.inlineEditVisible, EditorContextKeys.tabMovesFocus.toNegated(), Context.Visible.toNegated(), EditorContextKeys.hoverFocused.toNegated(), InlineCompletionContextKeys.tabShouldJumpToInlineEdit), } }); } async run(accessor, editor) { const controller = InlineCompletionsController.get(editor); if (controller) { controller.jump(); } } } class HideInlineCompletion extends EditorAction { static { this.ID = hideInlineCompletionId; } constructor() { super({ id: HideInlineCompletion.ID, label: localize2(1190, "Hide Inline Suggestion"), precondition: ContextKeyExpr.or(InlineCompletionContextKeys.inlineSuggestionVisible, InlineCompletionContextKeys.inlineEditVisible), kbOpts: { weight: 100 /* KeybindingWeight.EditorContrib */ + 90, // same as hiding the suggest widget primary: 9 /* KeyCode.Escape */, }, menuOpts: [{ menuId: MenuId.InlineEditsActions, title: localize(1180, "Reject"), group: 'primary', order: 3, }] }); } async run(accessor, editor) { const controller = InlineCompletionsController.getInFocusedEditorOrParent(accessor); transaction(tx => { controller?.model.get()?.stop('explicitCancel', tx); }); controller?.editor.focus(); } } class ToggleInlineCompletionShowCollapsed extends EditorAction { static { this.ID = toggleShowCollapsedId; } constructor() { super({ id: ToggleInlineCompletionShowCollapsed.ID, label: localize2(1191, "Toggle Inline Suggestions Show Collapsed"), precondition: ContextKeyExpr.true(), }); } async run(accessor, editor) { const configurationService = accessor.get(IConfigurationService); const showCollapsed = configurationService.getValue('editor.inlineSuggest.edits.showCollapsed'); configurationService.updateValue('editor.inlineSuggest.edits.showCollapsed', !showCollapsed); } } KeybindingsRegistry.registerKeybindingRule({ id: HideInlineCompletion.ID, weight: -1, // very weak primary: 9 /* KeyCode.Escape */, secondary: [1024 /* KeyMod.Shift */ | 9 /* KeyCode.Escape */], when: ContextKeyExpr.and(InlineCompletionContextKeys.inInlineEditsPreviewEditor) }); class ToggleAlwaysShowInlineSuggestionToolbar extends Action2 { static { this.ID = 'editor.action.inlineSuggest.toggleAlwaysShowToolbar'; } constructor() { super({ id: ToggleAlwaysShowInlineSuggestionToolbar.ID, title: localize(1181, "Always Show Toolbar"), f1: false, precondition: undefined, menu: [{ id: MenuId.InlineSuggestionToolbar, group: 'secondary', order: 10, }], toggled: ContextKeyExpr.equals('config.editor.inlineSuggest.showToolbar', 'always') }); } async run(accessor) { const configService = accessor.get(IConfigurationService); const currentValue = configService.getValue('editor.inlineSuggest.showToolbar'); const newValue = currentValue === 'always' ? 'onHover' : 'always'; configService.updateValue('editor.inlineSuggest.showToolbar', newValue); } } class DevExtractReproSample extends EditorAction { constructor() { super({ id: 'editor.action.inlineSuggest.dev.extractRepro', label: localize(1182, "Developer: Extract Inline Suggest State"), alias: 'Developer: Inline Suggest Extract Repro', precondition: ContextKeyExpr.or(InlineCompletionContextKeys.inlineEditVisible, InlineCompletionContextKeys.inlineSuggestionVisible), }); } async run(accessor, editor) { const clipboardService = accessor.get(IClipboardService); const controller = InlineCompletionsController.get(editor); const m = controller?.model.get(); if (!m) { return; } const repro = m.extractReproSample(); const inlineCompletionLines = splitLines(JSON.stringify({ inlineCompletion: repro.inlineCompletion }, null, 4)); const json = inlineCompletionLines.map(l => '// ' + l).join('\n'); const reproStr = `${repro.documentValue}\n\n// <json>\n${json}\n// </json>\n`; await clipboardService.writeText(reproStr); return { reproCase: reproStr }; } } export { AcceptInlineCompletion, AcceptNextLineOfInlineCompletion, AcceptNextWordOfInlineCompletion, DevExtractReproSample, HideInlineCompletion, JumpToNextInlineEdit, ShowNextInlineSuggestionAction, ShowPreviousInlineSuggestionAction, ToggleAlwaysShowInlineSuggestionToolbar, ToggleInlineCompletionShowCollapsed, TriggerInlineSuggestionAction, inlineCompletionProviderGetMatcher, providerIdSchemaUri };