Skip to content

Commit 92329e4

Browse files
committed
add "start with snippet" to empty editor text, change things to use formatted text renderer (fixes microsoft#155293)
1 parent 7fd96db commit 92329e4

File tree

3 files changed

+53
-59
lines changed

3 files changed

+53
-59
lines changed

src/vs/base/browser/formattedTextRenderer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { IMouseEvent } from 'vs/base/browser/mouseEvent';
88
import { DisposableStore } from 'vs/base/common/lifecycle';
99

1010
export interface IContentActionHandler {
11-
callback: (content: string, event?: IMouseEvent) => void;
11+
callback: (content: string, event: IMouseEvent) => void;
1212
readonly disposables: DisposableStore;
1313
}
1414

src/vs/workbench/contrib/codeEditor/browser/untitledTextEditorHint.ts

Lines changed: 49 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import * as dom from 'vs/base/browser/dom';
7-
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
7+
import { DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle';
88
import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser';
99
import { localize } from 'vs/nls';
1010
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
@@ -17,9 +17,10 @@ import { Schemas } from 'vs/base/common/network';
1717
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
1818
import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions';
1919
import { registerEditorContribution } from 'vs/editor/browser/editorExtensions';
20-
import { EventType as GestureEventType, Gesture } from 'vs/base/browser/touch';
2120
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
2221
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
22+
import { IContentActionHandler, renderFormattedText } from 'vs/base/browser/formattedTextRenderer';
23+
import { SelectSnippetForEmptyFile } from 'vs/workbench/contrib/snippets/browser/commands/emptyFileSnippets';
2324

2425
const $ = dom.$;
2526

@@ -70,7 +71,7 @@ class UntitledTextEditorHintContentWidget implements IContentWidget {
7071
private static readonly ID = 'editor.widget.untitledHint';
7172

7273
private domNode: HTMLElement | undefined;
73-
private toDispose: IDisposable[];
74+
private toDispose: DisposableStore;
7475

7576
constructor(
7677
private readonly editor: ICodeEditor,
@@ -79,9 +80,9 @@ class UntitledTextEditorHintContentWidget implements IContentWidget {
7980
private readonly configurationService: IConfigurationService,
8081
private readonly keybindingService: IKeybindingService,
8182
) {
82-
this.toDispose = [];
83-
this.toDispose.push(editor.onDidChangeModelContent(() => this.onDidChangeModelContent()));
84-
this.toDispose.push(this.editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => {
83+
this.toDispose = new DisposableStore();
84+
this.toDispose.add(editor.onDidChangeModelContent(() => this.onDidChangeModelContent()));
85+
this.toDispose.add(this.editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => {
8586
if (this.domNode && e.hasChanged(EditorOption.fontInfo)) {
8687
this.editor.applyFontInfo(this.domNode);
8788
}
@@ -107,59 +108,56 @@ class UntitledTextEditorHintContentWidget implements IContentWidget {
107108
this.domNode = $('.untitled-hint');
108109
this.domNode.style.width = 'max-content';
109110

110-
const language = $('a.language-mode');
111-
language.style.cursor = 'pointer';
112-
language.innerText = localize('selectAlanguage2', "Select a language");
113-
const languageKeyBinding = this.keybindingService.lookupKeybinding(ChangeLanguageAction.ID);
114-
const languageKeybindingLabel = languageKeyBinding?.getLabel();
115-
if (languageKeybindingLabel) {
116-
language.title = localize('keyboardBindingTooltip', "{0}", languageKeybindingLabel);
117-
}
118-
this.domNode.appendChild(language);
119-
120-
const or = $('span');
121-
or.innerText = localize('or', " or ",);
122-
this.domNode.appendChild(or);
123-
124-
const editorType = $('a.editor-type');
125-
editorType.style.cursor = 'pointer';
126-
editorType.innerText = localize('openADifferentEditor', "open a different editor");
127-
const selectEditorTypeKeyBinding = this.keybindingService.lookupKeybinding('welcome.showNewFileEntries');
128-
const selectEditorTypeKeybindingLabel = selectEditorTypeKeyBinding?.getLabel();
129-
if (selectEditorTypeKeybindingLabel) {
130-
editorType.title = localize('keyboardBindingTooltip', "{0}", selectEditorTypeKeybindingLabel);
131-
}
132-
this.domNode.appendChild(editorType);
133-
134-
const toGetStarted = $('span');
135-
toGetStarted.innerText = localize('toGetStarted', " to get started.");
136-
this.domNode.appendChild(toGetStarted);
137-
138-
this.domNode.appendChild($('br'));
139-
140-
const startTyping = $('span');
141-
startTyping.innerText = localize('startTyping', "Start typing to dismiss or ");
142-
this.domNode.appendChild(startTyping);
111+
const hintMsg = localize({ key: 'message', comment: ['Presereve double-square brackets and their order'] }, '[[Select a language]], [[start with a snippet]], or [[open a different editor]] to get started.\nStart typing to dismiss or [[don\'t show]] this again.');
112+
const hintHandler: IContentActionHandler = {
113+
disposables: this.toDispose,
114+
callback: (index, event) => {
115+
switch (index) {
116+
case '0':
117+
languageOnClickOrTap(event.browserEvent);
118+
break;
119+
case '1':
120+
snippetOnClickOrTab(event.browserEvent);
121+
break;
122+
case '2':
123+
chooseEditorOnClickOrTap(event.browserEvent);
124+
break;
125+
case '3':
126+
dontShowOnClickOrTap();
127+
break;
128+
}
129+
}
130+
};
143131

144-
const dontShow = $('a');
145-
dontShow.style.cursor = 'pointer';
146-
dontShow.innerText = localize('dontshow', "don't show");
147-
this.domNode.appendChild(dontShow);
132+
const hintElement = renderFormattedText(hintMsg, {
133+
actionHandler: hintHandler,
134+
renderCodeSegments: false,
135+
});
136+
this.domNode.append(hintElement);
137+
138+
// ugly way to associate keybindings...
139+
const keybindingsLookup = [ChangeLanguageAction.ID, SelectSnippetForEmptyFile.Id, 'welcome.showNewFileEntries'];
140+
for (const anchor of hintElement.querySelectorAll('A')) {
141+
(<HTMLAnchorElement>anchor).style.cursor = 'pointer';
142+
const id = keybindingsLookup.shift();
143+
const title = id && this.keybindingService.lookupKeybinding(id)?.getLabel();
144+
(<HTMLAnchorElement>anchor).title = title ?? '';
145+
}
148146

149-
const thisAgain = $('span');
150-
thisAgain.innerText = localize('thisAgain', " this again.");
151-
this.domNode.appendChild(thisAgain);
152-
this.toDispose.push(Gesture.addTarget(this.domNode));
147+
// the actual command handlers...
153148
const languageOnClickOrTap = async (e: MouseEvent) => {
154149
e.stopPropagation();
155150
// Need to focus editor before so current editor becomes active and the command is properly executed
156151
this.editor.focus();
157152
await this.commandService.executeCommand(ChangeLanguageAction.ID, { from: 'hint' });
158153
this.editor.focus();
159154
};
160-
this.toDispose.push(dom.addDisposableListener(language, 'click', languageOnClickOrTap));
161-
this.toDispose.push(dom.addDisposableListener(language, GestureEventType.Tap, languageOnClickOrTap));
162-
this.toDispose.push(Gesture.addTarget(language));
155+
156+
const snippetOnClickOrTab = async (e: MouseEvent) => {
157+
e.stopPropagation();
158+
this.editor.focus();
159+
this.commandService.executeCommand(SelectSnippetForEmptyFile.Id, { from: 'hint' });
160+
};
163161

164162
const chooseEditorOnClickOrTap = async (e: MouseEvent) => {
165163
e.stopPropagation();
@@ -172,20 +170,14 @@ class UntitledTextEditorHintContentWidget implements IContentWidget {
172170
this.editorGroupsService.activeGroup.closeEditor(activeEditorInput, { preserveFocus: true });
173171
}
174172
};
175-
this.toDispose.push(dom.addDisposableListener(editorType, 'click', chooseEditorOnClickOrTap));
176-
this.toDispose.push(dom.addDisposableListener(editorType, GestureEventType.Tap, chooseEditorOnClickOrTap));
177-
this.toDispose.push(Gesture.addTarget(editorType));
178173

179174
const dontShowOnClickOrTap = () => {
180175
this.configurationService.updateValue(untitledTextEditorHintSetting, 'hidden');
181176
this.dispose();
182177
this.editor.focus();
183178
};
184-
this.toDispose.push(dom.addDisposableListener(dontShow, 'click', dontShowOnClickOrTap));
185-
this.toDispose.push(dom.addDisposableListener(dontShow, GestureEventType.Tap, dontShowOnClickOrTap));
186-
this.toDispose.push(Gesture.addTarget(dontShow));
187179

188-
this.toDispose.push(dom.addDisposableListener(this.domNode, 'click', () => {
180+
this.toDispose.add(dom.addDisposableListener(this.domNode, 'click', () => {
189181
this.editor.focus();
190182
}));
191183

src/vs/workbench/contrib/snippets/browser/commands/emptyFileSnippets.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
1818

1919
export class SelectSnippetForEmptyFile extends SnippetsAction {
2020

21+
static readonly Id = 'workbench.action.populateFromSnippet';
22+
2123
constructor() {
2224
super({
23-
id: 'workbench.action.populateFromSnippet',
25+
id: SelectSnippetForEmptyFile.Id,
2426
title: {
2527
value: localize('label', 'Populate from Snippet'),
2628
original: 'Populate from Snippet'

0 commit comments

Comments
 (0)