diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/untitled.languagedetection.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/untitled.languagedetection.test.ts index e27689c8b24..4970a5c33e3 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/untitled.languagedetection.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/untitled.languagedetection.test.ts @@ -20,7 +20,7 @@ suite('vscode - untitled automatic language detection', () => { assert.strictEqual(editor.document.languageId, 'plaintext'); - const settingResult = vscode.workspace.getConfiguration().get('workbench.editor.untitled.languageDetection'); + const settingResult = vscode.workspace.getConfiguration().get('workbench.editor.languageDetection'); assert.ok(settingResult); const result = await editor.edit(editBuilder => { diff --git a/extensions/vscode-api-tests/testWorkspace/.vscode/settings.json b/extensions/vscode-api-tests/testWorkspace/.vscode/settings.json index 2ad11d49651..987c35c4484 100644 --- a/extensions/vscode-api-tests/testWorkspace/.vscode/settings.json +++ b/extensions/vscode-api-tests/testWorkspace/.vscode/settings.json @@ -6,5 +6,5 @@ "**/files-exclude/**": true }, "editor.minimap.enabled": false, // see https://github.com/microsoft/vscode/issues/115747 - "workbench.editor.untitled.languageDetection": true + "workbench.editor.languageDetection": true } diff --git a/src/vs/workbench/browser/workbench.contribution.ts b/src/vs/workbench/browser/workbench.contribution.ts index 8e2bb513a69..fcd70823be6 100644 --- a/src/vs/workbench/browser/workbench.contribution.ts +++ b/src/vs/workbench/browser/workbench.contribution.ts @@ -93,10 +93,10 @@ const registry = Registry.as(ConfigurationExtensions.Con 'default': 'text', 'markdownDescription': localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'untitledHint' }, "Controls if the untitled hint should be inline text in the editor or a floating button or hidden.") }, - 'workbench.editor.untitled.languageDetection': { + 'workbench.editor.languageDetection': { type: 'boolean', default: true, - description: localize('workbench.editor.untitled.languageDetection', "Controls whether the language in an untitled text editor is automatically detected unless the language has been explicitly set by the language picker. This can also be scoped by language so you can control which languages you want to trigger language detection on."), + description: localize('workbench.editor.languageDetection', "Controls whether the language in a text editor is automatically detected unless the language has been explicitly set by the language picker. This can also be scoped by language so you can control which languages you want to trigger language detection on."), scope: ConfigurationScope.LANGUAGE_OVERRIDABLE }, 'workbench.editor.tabCloseButton': { diff --git a/src/vs/workbench/common/editor/textEditorModel.ts b/src/vs/workbench/common/editor/textEditorModel.ts index bb3dd709a8f..26a9f18d07d 100644 --- a/src/vs/workbench/common/editor/textEditorModel.ts +++ b/src/vs/workbench/common/editor/textEditorModel.ts @@ -14,6 +14,7 @@ import { MutableDisposable } from 'vs/base/common/lifecycle'; import { PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry'; import { withUndefinedAsNull } from 'vs/base/common/types'; import { ILanguageDetectionService } from 'vs/workbench/services/languageDetection/common/languageDetectionWorkerService'; +import { ThrottledDelayer } from 'vs/base/common/async'; /** * The base text editor model leverages the code editor model. This class is only intended to be subclassed and not instantiated. @@ -25,6 +26,7 @@ export class BaseTextEditorModel extends EditorModel implements ITextEditorModel private createdEditorModel: boolean | undefined; private readonly modelDisposeListener = this._register(new MutableDisposable()); + private readonly _autoDetectLanguageThrottler = this._register(new ThrottledDelayer(600)); constructor( @IModelService protected modelService: IModelService, @@ -100,6 +102,10 @@ export class BaseTextEditorModel extends EditorModel implements ITextEditorModel } protected async autoDetectLanguage() { + this._autoDetectLanguageThrottler.trigger(() => this.autoDetectLanguageImpl()); + } + + private async autoDetectLanguageImpl() { if (this.hasModeSetExplicitly || !this.textEditorModelHandle || !this.languageDetectionService.isEnabledForMode(this.getMode() ?? PLAINTEXT_MODE_ID)) { return; } diff --git a/src/vs/workbench/services/languageDetection/browser/languageDetectionWorkerServiceImpl.ts b/src/vs/workbench/services/languageDetection/browser/languageDetectionWorkerServiceImpl.ts index 31960a01541..1d094d8e929 100644 --- a/src/vs/workbench/services/languageDetection/browser/languageDetectionWorkerServiceImpl.ts +++ b/src/vs/workbench/services/languageDetection/browser/languageDetectionWorkerServiceImpl.ts @@ -21,7 +21,7 @@ import { EditorWorkerClient, EditorWorkerHost } from 'vs/editor/common/services/ const moduleLocation = '../../../../../../node_modules/@vscode/vscode-languagedetection'; const moduleLocationAsar = '../../../../../../node_modules.asar/@vscode/vscode-languagedetection'; export class LanguageDetectionService extends Disposable implements ILanguageDetectionService { - static readonly enablementSettingKey = 'workbench.editor.untitled.languageDetection'; + static readonly enablementSettingKey = 'workbench.editor.languageDetection'; _serviceBrand: undefined; diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts index d380f0277b6..bcbeec8d35c 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts @@ -13,7 +13,7 @@ import { IWorkingCopyBackupService, IResolvedWorkingCopyBackup } from 'vs/workbe import { IFileService, FileOperationError, FileOperationResult, FileChangesEvent, FileChangeType, IFileStatWithMetadata, ETAG_DISABLED, FileSystemProviderCapabilities, NotModifiedSinceFileOperationError } from 'vs/platform/files/common/files'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IModelService } from 'vs/editor/common/services/modelService'; -import { timeout, TaskSequentializer, ThrottledDelayer } from 'vs/base/common/async'; +import { timeout, TaskSequentializer } from 'vs/base/common/async'; import { ITextBufferFactory, ITextModel } from 'vs/editor/common/model'; import { ILogService } from 'vs/platform/log/common/log'; import { basename } from 'vs/base/common/path'; @@ -90,7 +90,6 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil private lastResolvedFileStat: IFileStatWithMetadata | undefined; private readonly saveSequentializer = new TaskSequentializer(); - private readonly _autoDetectLanguageThrottler = this._register(new ThrottledDelayer(600)); private dirty = false; private inConflictMode = false; @@ -531,13 +530,8 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // Model Listeners this.installModelListeners(textModel); - // Try to detect language from content (debounced by some time to reduce pressure). - this._autoDetectLanguageThrottler.trigger(async () => { - const currentMode = this.getMode(); - if (this.resource.scheme === this.pathService.defaultUriScheme && (!currentMode || currentMode === PLAINTEXT_MODE_ID)) { - await this.autoDetectLanguage(); - } - }); + // Detect language + this.autoDetectLanguage(); } private doUpdateTextModel(value: ITextBufferFactory): void { @@ -608,13 +602,15 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // Emit as event this._onDidChangeContent.fire(); - // Try to detect language from content (debounced by some time to reduce pressure). - this._autoDetectLanguageThrottler.trigger(async () => { - const currentMode = this.getMode(); - if (this.resource.scheme === this.pathService.defaultUriScheme && (!currentMode || currentMode === PLAINTEXT_MODE_ID)) { - await this.autoDetectLanguage(); - } - }); + // Detect language from content. Internally, this is throttled to reduce pressure. + this.autoDetectLanguage(); + } + + override async autoDetectLanguage() { + const currentMode = this.getMode(); + if (this.resource.scheme === this.pathService.defaultUriScheme && (!currentMode || currentMode === PLAINTEXT_MODE_ID)) { + super.autoDetectLanguage(); + } } //#endregion diff --git a/src/vs/workbench/services/untitled/common/untitledTextEditorModel.ts b/src/vs/workbench/services/untitled/common/untitledTextEditorModel.ts index 41e13e536d1..e505dcc48e8 100644 --- a/src/vs/workbench/services/untitled/common/untitledTextEditorModel.ts +++ b/src/vs/workbench/services/untitled/common/untitledTextEditorModel.ts @@ -27,7 +27,6 @@ import { getCharContainingOffset } from 'vs/base/common/strings'; import { UTF8 } from 'vs/workbench/services/textfile/common/encoding'; import { bufferToStream, VSBuffer, VSBufferReadableStream } from 'vs/base/common/buffer'; import { ILanguageDetectionService } from 'vs/workbench/services/languageDetection/common/languageDetectionWorkerService'; -import { ThrottledDelayer } from 'vs/base/common/async'; export interface IUntitledTextEditorModel extends ITextEditorModel, IModeSupport, IEncodingSupport, IWorkingCopy { @@ -73,8 +72,11 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IUnt private static readonly FIRST_LINE_NAME_CANDIDATE_MAX_LENGTH = UntitledTextEditorModel.FIRST_LINE_NAME_MAX_LENGTH * 10; // support the special '${activeEditorLanguage}' mode by - // looking up the language mode from the currently - // active text editor if any + // looking up the language mode from the editor that is + // active before the untitled editor opens. This special + // mode is only used for the initial language mode and + // can be changed after the fact (either manually or through + // auto-detection). private static readonly ACTIVE_EDITOR_LANGUAGE_MODE = '${activeEditorLanguage}'; //#region Events @@ -100,8 +102,6 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IUnt readonly capabilities = WorkingCopyCapabilities.Untitled; - private readonly _autoDetectLanguageThrottler = this._register(new ThrottledDelayer(600)); - //#region Name private configuredLabelFormat: 'content' | 'name' = 'content'; @@ -368,8 +368,8 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IUnt // Emit as general content change event this._onDidChangeContent.fire(); - // Try to detect language from content (debounced by some time to reduce pressure). - this._autoDetectLanguageThrottler.trigger(() => this.autoDetectLanguage()); + // Detect language from content. Internally this is throttled to reduce pressure. + this.autoDetectLanguage(); } private updateNameFromFirstLine(textEditorModel: ITextModel): void {