Skip to content

Commit

Permalink
feat: move dom element highlight codeLens to status bar
Browse files Browse the repository at this point in the history
close #1535
  • Loading branch information
johnsoncodehk committed Aug 26, 2022
1 parent e1f7aec commit f9a14dd
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 95 deletions.
184 changes: 97 additions & 87 deletions extensions/vscode-vue-language-features/src/features/preview.ts
Expand Up @@ -20,21 +20,23 @@ const enum PreviewType {
export async function register(context: vscode.ExtensionContext) {

const panels = new Set<vscode.WebviewPanel>();
const panelUrl = new Map<vscode.WebviewPanel, string>();
let _activePreview: vscode.WebviewPanel | undefined;
let externalBrowserPanel: vscode.WebviewPanel | undefined;
let avoidUpdateOnDidChangeActiveTextEditor = false;
let updateComponentPreview: Function | undefined;

const statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right);
statusBar.command = 'volar.inputWebviewUrl';
statusBar.command = 'volar.previewMenu';
statusBar.backgroundColor = new vscode.ThemeColor('statusBarItem.warningBackground');
context.subscriptions.push(statusBar);

let connection: ReturnType<typeof preview.createPreviewConnection> | undefined;
let highlightDomElements = true;
const onDidChangeCodeLensesEmmiter = new vscode.EventEmitter<void>();

if (vscode.window.terminals.some(terminal => terminal.name.startsWith('volar-preview:'))) {
const previewTerminal = vscode.window.terminals.find(terminal => terminal.name.startsWith('volar-preview:'));
if (previewTerminal) {
connection = preview.createPreviewConnection({
onGotoCode: handleGoToCode,
getFileHref: (fileName, range) => {
Expand All @@ -44,6 +46,8 @@ export async function register(context: vscode.ExtensionContext) {
},
});
onDidChangeCodeLensesEmmiter.fire();
statusBar.text = 'Preview Port: ' + previewTerminal.name.split(':')[1];
statusBar.show();
}
vscode.window.onDidOpenTerminal(e => {
if (e.name.startsWith('volar-preview:')) {
Expand All @@ -56,13 +60,16 @@ export async function register(context: vscode.ExtensionContext) {
},
});
onDidChangeCodeLensesEmmiter.fire();
statusBar.text = 'Preview Port: ' + e.name.split(':')[1];
statusBar.show();
}
});
vscode.window.onDidCloseTerminal(e => {
if (e.name.startsWith('volar-preview:')) {
connection?.stop();
connection = undefined;
onDidChangeCodeLensesEmmiter.fire();
statusBar.hide();
}
});

Expand Down Expand Up @@ -171,6 +178,61 @@ export async function register(context: vscode.ExtensionContext) {
new VueComponentPreview(),
);

context.subscriptions.push(vscode.commands.registerCommand('volar.previewMenu', async () => {

const baseOptions: Record<string, vscode.QuickPickItem> = {};
const urlOptions: Record<string, vscode.QuickPickItem> = {};
const highlight: Record<string, vscode.QuickPickItem> = {};

baseOptions['kill'] = { label: 'Kill Preview Server' };
baseOptions['browser'] = { label: 'Open in Browser' };

for (const panel of panels) {
urlOptions['url::' + panelUrl.get(panel)] = { label: 'Input WebView URL', detail: panelUrl.get(panel) };
}

highlight['highlight-on'] = { label: (highlightDomElements ? '• ' : '') + 'Highlight DOM Elements' };
highlight['highlight-off'] = { label: (!highlightDomElements ? '• ' : '') + `Don't Highlight DOM Elements` };

const key = await userPick([baseOptions, urlOptions, highlight]);

if (key?.startsWith('url::')) {
const url = key.split('::')[1];
const input = await vscode.window.showInputBox({ value: url });
for (const panel of panels) {
if (panelUrl.get(panel) === url) {
if (input !== undefined && input !== statusBar.text) {
panel.webview.html = getWebviewContent(input);
}
}
}
}
if (key === 'kill') {
for (const terminal of vscode.window.terminals) {
if (terminal.name.startsWith('volar-preview:')) {
terminal.dispose();
}
for (const panel of panels) {
panel.dispose();
}
}
}
if (key === 'browser') {
vscode.env.openExternal(vscode.Uri.parse('http://localhost:' + statusBar.text.split(':')[1].trim()));
}
if (key === 'highlight-on') {
highlightDomElements = true;
if (vscode.window.activeTextEditor) {
updateSelectionHighlights(vscode.window.activeTextEditor);
}
}
if (key === 'highlight-off') {
highlightDomElements = false;
if (vscode.window.activeTextEditor) {
updateSelectionHighlights(vscode.window.activeTextEditor);
}
}
}));
context.subscriptions.push(vscode.commands.registerCommand('volar.action.vite', async () => {

const editor = vscode.window.activeTextEditor;
Expand Down Expand Up @@ -228,15 +290,8 @@ export async function register(context: vscode.ExtensionContext) {
}
}));
context.subscriptions.push(vscode.commands.registerCommand('volar.action.openInBrowser', () => {
vscode.env.openExternal(vscode.Uri.parse(statusBar.text));
}));
context.subscriptions.push(vscode.commands.registerCommand('volar.inputWebviewUrl', async () => {
const panel = [...panels].find(panel => panel.active);
if (panel) {
const input = await vscode.window.showInputBox({ value: statusBar.text });
if (input !== undefined && input !== statusBar.text) {
panel.webview.html = getWebviewContent(input);
}
for (const panel of panels) {
vscode.env.openExternal(vscode.Uri.parse(panelUrl.get(panel)!));
}
}));
context.subscriptions.push(vscode.window.onDidChangeTextEditorSelection(e => {
Expand All @@ -257,44 +312,6 @@ export async function register(context: vscode.ExtensionContext) {
context.subscriptions.push(vscode.window.onDidChangeActiveTextEditor(updatePreviewIconStatus));

updatePreviewIconStatus();
useHighlightDomElements();

function useHighlightDomElements() {

class HighlightDomElementsStatusCodeLens implements vscode.CodeLensProvider {
provideCodeLenses(document: vscode.TextDocument, token: vscode.CancellationToken): vscode.ProviderResult<vscode.CodeLens[]> {
if (connection) {
return [{
isResolved: true,
range: new vscode.Range(
document.positionAt(0),
document.positionAt(0),
),
command: {
title: 'highlight dom elements ' + (highlightDomElements ? '☑' : '☐'),
command: 'volar.toggleHighlightDomElementsStatus',
},
}];
}
};
onDidChangeCodeLenses = onDidChangeCodeLensesEmmiter.event;
}

const codeLens = new HighlightDomElementsStatusCodeLens();

vscode.languages.registerCodeLensProvider(
{ scheme: 'file', language: 'vue' },
codeLens,
);

vscode.commands.registerCommand('volar.toggleHighlightDomElementsStatus', () => {
highlightDomElements = !highlightDomElements;
if (vscode.window.activeTextEditor) {
updateSelectionHighlights(vscode.window.activeTextEditor);
}
onDidChangeCodeLensesEmmiter.fire();
});
}

function getSfc(document: vscode.TextDocument) {
let cache = sfcs.get(document);
Expand Down Expand Up @@ -404,13 +421,6 @@ export async function register(context: vscode.ExtensionContext) {
panel.webview.html = getWebviewContent(`http://localhost:${port}`, { fileName, mode });
}));
panel.webview.html = getWebviewContent(`http://localhost:${port}`, { fileName, mode });

panel.onDidChangeViewState(() => {
if (panel.active)
statusBar.show();
else
statusBar.hide();
});
}

return port;
Expand All @@ -432,38 +442,38 @@ export async function register(context: vscode.ExtensionContext) {
function setPreviewActiveContext(value: boolean) {
vscode.commands.executeCommand('setContext', 'volarPreviewFocus', value);
}
}

async function webviewEventHandler(message: any) {
switch (message.command) {
case 'openUrl': {
const url = message.data;
vscode.env.openExternal(vscode.Uri.parse(url));
break;
}
case 'closeExternalBrowserPanel': {
externalBrowserPanel?.dispose();
break;
}
case 'urlChanged': {
const url = message.data;
statusBar.text = url;
break;
}
case 'log': {
const text = message.data;
vscode.window.showInformationMessage(text);
break;
}
case 'warn': {
const text = message.data;
vscode.window.showWarningMessage(text);
break;
}
case 'error': {
const text = message.data;
vscode.window.showErrorMessage(text);
break;
async function webviewEventHandler(message: any) {
switch (message.command) {
case 'openUrl': {
const url = message.data;
vscode.env.openExternal(vscode.Uri.parse(url));
break;
}
case 'closeExternalBrowserPanel': {
externalBrowserPanel?.dispose();
break;
}
case 'urlChanged': {
const url = message.data;
panelUrl.set(panel, url);
break;
}
case 'log': {
const text = message.data;
vscode.window.showInformationMessage(text);
break;
}
case 'warn': {
const text = message.data;
vscode.window.showWarningMessage(text);
break;
}
case 'error': {
const text = message.data;
vscode.window.showErrorMessage(text);
break;
}
}
}
}
Expand Down
Expand Up @@ -94,19 +94,33 @@ function useDocDescriptor() {
}
}

export function userPick(options: Record<string, vscode.QuickPickItem>, placeholder?: string) {
export function userPick(groups: Record<string, vscode.QuickPickItem> | Record<string, vscode.QuickPickItem>[], placeholder?: string) {
return new Promise<string | undefined>(resolve => {
const quickPick = vscode.window.createQuickPick();
quickPick.items = Object.values(options);
const items: vscode.QuickPickItem[] = [];
for (const group of Array.isArray(groups) ? groups : [groups]) {
const groupItems = Object.values(group);
if (groupItems.length) {
if (items.length) {
items.push({ label: '', kind: vscode.QuickPickItemKind.Separator });
}
for (const item of groupItems) {
items.push(item);
}
}
}
quickPick.items = items;
quickPick.placeholder = placeholder;
quickPick.onDidChangeSelection(selection => {
if (selection[0]) {
for (let key in options) {
const option = options[key];
if (selection[0] === option) {
resolve(key);
quickPick.hide();
break;
for (const options of Array.isArray(groups) ? groups : [groups]) {
for (let key in options) {
const option = options[key];
if (selection[0] === option) {
resolve(key);
quickPick.hide();
break;
}
}
}
}
Expand Down

0 comments on commit f9a14dd

Please sign in to comment.