untitiled hint

#114307
This commit is contained in:
isidor
2021-02-17 20:10:18 +01:00
parent 00b583d38d
commit 5a4f5c95fe
2 changed files with 154 additions and 0 deletions

View File

@@ -57,6 +57,7 @@ import { IPathService } from 'vs/workbench/services/path/common/pathService';
import { FileAccess } from 'vs/base/common/network';
import { Codicon } from 'vs/base/common/codicons';
import { registerIcon } from 'vs/platform/theme/common/iconRegistry';
import { UntitledHintContribution } from 'vs/workbench/browser/parts/editor/untitledHint';
// Register String Editor
Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor(
@@ -276,6 +277,9 @@ Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).regi
// Register Editor Auto Save
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(EditorAutoSave, LifecyclePhase.Ready);
// Register Untitled Hint
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(UntitledHintContribution, LifecyclePhase.Ready);
// Register Status Actions
const registry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
registry.registerWorkbenchAction(SyncActionDescriptor.from(ChangeModeAction, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_M) }), 'Change Language Mode');

View File

@@ -0,0 +1,150 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as dom from 'vs/base/browser/dom';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition, isCodeEditor } from 'vs/editor/browser/editorBrowser';
import { localize } from 'vs/nls';
import { DEFAULT_FONT_FAMILY } from 'vs/workbench/browser/style';
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { inputPlaceholderForeground } from 'vs/platform/theme/common/colorRegistry';
import { ChangeModeAction } from 'vs/workbench/browser/parts/editor/editorStatus';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
const $ = dom.$;
const UNTITLED_HINT_VISIBILITY_STORAGE_KEY = 'untitledHint.visible';
export class UntitledHintContribution implements IWorkbenchContribution {
private toDispose: IDisposable[];
private untitledHintContentWidget: UntitledHintContentWidget | undefined;
constructor(
@IEditorService private readonly editorService: IEditorService,
@ICommandService private readonly commandService: ICommandService,
@IStorageService private readonly storageService: IStorageService,
) {
this.toDispose = [];
this.toDispose.push(this.editorService.onDidActiveEditorChange(() => this.onActiveEditorChange()));
this.onActiveEditorChange();
}
private onActiveEditorChange(): void {
const activeEditor = this.editorService.activeEditor;
this.untitledHintContentWidget?.dispose();
const activeCodeEditor = this.editorService.activeTextEditorControl;
const untitledHintVisible = this.storageService.getBoolean(UNTITLED_HINT_VISIBILITY_STORAGE_KEY, StorageScope.GLOBAL, true);
if (untitledHintVisible && activeEditor && activeEditor.isUntitled() && isCodeEditor(activeCodeEditor)) {
this.untitledHintContentWidget = new UntitledHintContentWidget(activeCodeEditor, this.commandService, this.storageService);
}
}
dispose(): void {
dispose(this.toDispose);
this.untitledHintContentWidget?.dispose();
}
}
class UntitledHintContentWidget implements IContentWidget {
private static readonly ID = 'editor.widget.untitledHint';
private domNode: HTMLElement | undefined;
private toDispose: IDisposable[];
constructor(
private readonly editor: ICodeEditor,
private readonly commandService: ICommandService,
private readonly storageService: IStorageService,
) {
this.toDispose = [];
this.toDispose.push(editor.onDidChangeModelContent(() => this.onDidChangeModelContent()));
this.toDispose.push(editor.onDidChangeModelLanguage(() => this.onDidChangeModelContent()));
this.onDidChangeModelContent();
}
private onDidChangeModelContent(): void {
if (this.editor.getValue() === '' && this.editor.getModel()?.getModeId() === PLAINTEXT_MODE_ID) {
this.editor.addContentWidget(this);
} else {
this.editor.removeContentWidget(this);
}
}
getId(): string {
return UntitledHintContentWidget.ID;
}
// Select a language to get started. Start typing to dismiss, or don't show this again.
getDomNode(): HTMLElement {
if (!this.domNode) {
this.domNode = $('.untitled-hint');
this.domNode.style.width = 'max-content';
const select = $('span');
select.innerText = localize('select', "Select a ");
this.domNode.appendChild(select);
const language = $('span.language-mode.detected-link-active');
language.innerText = localize('language', "language");
this.domNode.appendChild(language);
const toGetStarted = $('span');
toGetStarted.innerText = localize('toGetStarted', " to get started. Start typing to dismiss, or ");
this.domNode.appendChild(toGetStarted);
const dontShow = $('span.detected-link-active');
dontShow.innerText = localize('dontshow', "don't show");
this.domNode.appendChild(dontShow);
const thisAgain = $('span');
thisAgain.innerText = localize('thisAgain', " this again.");
this.domNode.appendChild(thisAgain);
this.toDispose.push(dom.addDisposableListener(language, 'click', async e => {
e.stopPropagation();
await this.commandService.executeCommand(ChangeModeAction.ID);
this.editor.focus();
}));
this.toDispose.push(dom.addDisposableListener(dontShow, 'click', () => {
this.storageService.store(UNTITLED_HINT_VISIBILITY_STORAGE_KEY, false, StorageScope.GLOBAL, StorageTarget.USER);
this.dispose();
this.editor.focus();
}));
this.toDispose.push(dom.addDisposableListener(this.domNode, 'click', () => {
this.editor.focus();
}));
this.domNode.style.fontFamily = DEFAULT_FONT_FAMILY;
this.domNode.style.fontStyle = 'italic';
this.domNode.style.paddingLeft = '4px';
}
return this.domNode;
}
getPosition(): IContentWidgetPosition | null {
return {
position: { lineNumber: 1, column: 1 },
preference: [ContentWidgetPositionPreference.EXACT]
};
}
dispose(): void {
this.editor.removeContentWidget(this);
dispose(this.toDispose);
}
}
registerThemingParticipant((theme, collector) => {
const inputPlaceholderForegroundColor = theme.getColor(inputPlaceholderForeground);
if (inputPlaceholderForegroundColor) {
collector.addRule(`.monaco-editor .contentWidgets .untitled-hint { color: ${inputPlaceholderForegroundColor}; }`);
}
});