Files
react-native-devtools-frontend/front_end/quick_open/CommandMenu.js
T
Tim van der Lippe e4d64e7ae0 Remove unrestricted from comments that include other annotations
For all comments that contained both the unrestricted annotation
and any other potential annotation, remove only the unrestricted
annotation.

R=szuend@chromium.org

No-Presubmit: True
Bug: 1011811
Change-Id: I27dd67f657cdb1a9233d768eea81cabe2591f5f7
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2569759
Commit-Queue: Tim van der Lippe <tvanderlippe@chromium.org>
Reviewed-by: Simon Zünd <szuend@chromium.org>
2020-12-02 15:31:52 +00:00

468 lines
12 KiB
JavaScript

// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import * as Common from '../common/common.js';
import * as Diff from '../diff/diff.js';
import * as Host from '../host/host.js';
import * as Root from '../root/root.js';
import * as UI from '../ui/ui.js';
import {FilteredListWidget, Provider} from './FilteredListWidget.js';
import {QuickOpenImpl} from './QuickOpen.js';
/** @type {!CommandMenu} */
let commandMenuInstance;
export class CommandMenu {
/** @private */
constructor() {
/** @type {!Array<!Command>} */
this._commands = [];
this._loadCommands();
}
static instance() {
if (!commandMenuInstance) {
commandMenuInstance = new CommandMenu();
}
return commandMenuInstance;
}
/**
* @param {!CreateCommandOptions} options
* @return {!Command}
*/
static createCommand(options) {
const {category, keys, title, shortcut, executeHandler, availableHandler, userActionCode} = options;
let handler = executeHandler;
if (userActionCode) {
const actionCode = userActionCode;
handler = () => {
Host.userMetrics.actionTaken(actionCode);
executeHandler();
};
}
return new Command(category, title, keys, shortcut, handler, availableHandler);
}
/**
* @param {!Common.Settings.Setting<*>} setting
* @param {string} title
* @param {V} value
* @return {!Command}
* @template V
*/
static createSettingCommand(setting, title, value) {
const category = setting.category() || '';
const tags = setting.tags() || '';
const reloadRequired = !!setting.reloadRequired();
return CommandMenu.createCommand({
category,
keys: tags,
title,
shortcut: '',
executeHandler: () => {
setting.set(value);
if (reloadRequired) {
UI.InspectorView.InspectorView.instance().displayReloadRequiredWarning(
ls`One or more settings have changed which requires a reload to take effect.`);
}
},
availableHandler,
userActionCode: undefined,
});
/**
* @return {boolean}
*/
function availableHandler() {
return setting.get() !== value;
}
}
/**
* @param {!ActionCommandOptions} options
* @return {!Command}
*/
static createActionCommand(options) {
const {action, userActionCode} = options;
const shortcut = UI.ShortcutRegistry.ShortcutRegistry.instance().shortcutTitleForAction(action.id()) || '';
return CommandMenu.createCommand({
category: action.category(),
keys: action.tags() || '',
title: action.title() || '',
shortcut,
executeHandler: action.execute.bind(action),
userActionCode,
availableHandler: undefined,
});
}
/**
* @param {!RevealViewCommandOptions} options
* @return {!Command}
*/
static createRevealViewCommand(options) {
const {title, tags, category, userActionCode, id} = options;
return CommandMenu.createCommand({
category,
keys: tags,
title,
shortcut: '',
executeHandler: UI.ViewManager.ViewManager.instance().showView.bind(
UI.ViewManager.ViewManager.instance(), id, /* userGesture */ true),
userActionCode,
availableHandler: undefined
});
}
_loadCommands() {
// TODO(crbug.com/1134103): replace this implementation for the one on _loadCommandsFromPreRegisteredExtensions once
// all settings, views and type lookups extensions have been migrated.
const locations = new Map();
Root.Runtime.Runtime.instance().extensions(UI.View.ViewLocationResolver).forEach(extension => {
const category = extension.descriptor()['category'];
const name = extension.descriptor()['name'];
if (category && name) {
locations.set(name, category);
}
});
// TODO(crbug.com/1134103): Remove this call when all views are migrated
const viewExtensions = Root.Runtime.Runtime.instance().extensions('view');
for (const extension of viewExtensions) {
const category = locations.get(extension.descriptor()['location']);
if (!category) {
continue;
}
const extensionDescriptor = extension.descriptor();
const keys = extensionDescriptor.tags || '';
// Get localized keys and separate by null character to prevent fuzzy matching from matching across them.
const keyList = keys.split(',');
let tags = '';
keyList.forEach(k => {
tags += (ls(k.trim()) + '\0');
});
/** @type {!RevealViewCommandOptions} */
const options = {
id: extensionDescriptor.id,
title: Common.UIString.UIString('Show %s', extensionDescriptor.title),
tags,
category: ls(category),
userActionCode: undefined
};
this._commands.push(CommandMenu.createRevealViewCommand(options));
}
// Populate allowlisted settings.
// TODO(crbug.com/1134103): Remove this call when all settings are migrated
const settingExtensions = Root.Runtime.Runtime.instance().extensions('setting');
for (const extension of settingExtensions) {
const descriptor = extension.descriptor();
const options = descriptor.options;
if (!options || !descriptor.category) {
continue;
}
for (const pair of options) {
const setting = Common.Settings.Settings.instance().moduleSetting(descriptor.settingName);
this._commands.push(CommandMenu.createSettingCommand(setting, ls(pair['title']), pair['value']));
}
}
this._loadCommandsFromPreRegisteredExtensions(locations);
}
/**
* @param {!Map<string,string>} locations
*/
_loadCommandsFromPreRegisteredExtensions(locations) {
const views = UI.ViewManager.getRegisteredViewExtensions();
for (const view of views) {
const viewLocation = view.location();
const category = viewLocation && locations.get(viewLocation);
if (!category) {
continue;
}
/** @type {!RevealViewCommandOptions} */
const options = {
title: view.title(),
tags: view.tags() || '',
category: ls(category),
userActionCode: undefined,
id: view.viewId()
};
this._commands.push(CommandMenu.createRevealViewCommand(options));
}
const settingsRegistrations = Common.Settings.getRegisteredSettings();
for (const settingRegistration of settingsRegistrations) {
const options = settingRegistration.options;
if (!options || !settingRegistration.category) {
continue;
}
for (const pair of options) {
const setting = Common.Settings.Settings.instance().moduleSetting(settingRegistration.settingName);
this._commands.push(CommandMenu.createSettingCommand(setting, pair.title, pair.value));
}
}
}
/**
* @return {!Array.<!Command>}
*/
commands() {
return this._commands;
}
}
/**
* @typedef {{
* action: !UI.ActionRegistration.Action,
* userActionCode: (!Host.UserMetrics.Action|undefined),
* }}
*/
// @ts-ignore typedef
export let ActionCommandOptions;
/**
* @typedef {{
* id: string,
* title: string,
* tags: string,
* category: string,
* userActionCode: (!Host.UserMetrics.Action|undefined)
* }}
*/
// @ts-ignore typedef
export let RevealViewCommandOptions;
/**
* @typedef {{
* category: string,
* keys: string,
* title: string,
* shortcut: string,
* executeHandler: !function():*,
* availableHandler: ((!function():boolean)|undefined),
* userActionCode: (!Host.UserMetrics.Action|undefined)
* }}
*/
// @ts-ignore typedef
export let CreateCommandOptions;
export class CommandMenuProvider extends Provider {
constructor() {
super();
/** @type {!Array<!Command>} */
this._commands = [];
}
/**
* @override
*/
attach() {
const allCommands = CommandMenu.instance().commands();
// Populate allowlisted actions.
const actions = UI.ActionRegistry.ActionRegistry.instance().availableActions();
for (const action of actions) {
const category = action.category();
if (!category) {
continue;
}
/** @type {!ActionCommandOptions} */
const options = {action, userActionCode: undefined};
this._commands.push(CommandMenu.createActionCommand(options));
}
for (const command of allCommands) {
if (command.available()) {
this._commands.push(command);
}
}
this._commands = this._commands.sort(commandComparator);
/**
* @param {!Command} left
* @param {!Command} right
* @return {number}
*/
function commandComparator(left, right) {
const cats = left.category().compareTo(right.category());
return cats ? cats : left.title().compareTo(right.title());
}
}
/**
* @override
*/
detach() {
this._commands = [];
}
/**
* @override
* @return {number}
*/
itemCount() {
return this._commands.length;
}
/**
* @override
* @param {number} itemIndex
* @return {string}
*/
itemKeyAt(itemIndex) {
return this._commands[itemIndex].key();
}
/**
* @override
* @param {number} itemIndex
* @param {string} query
* @return {number}
*/
itemScoreAt(itemIndex, query) {
const command = this._commands[itemIndex];
let score = Diff.Diff.DiffWrapper.characterScore(query.toLowerCase(), command.title().toLowerCase());
// Score panel/drawer reveals above regular actions.
if (command.category().startsWith('Panel')) {
score += 2;
} else if (command.category().startsWith('Drawer')) {
score += 1;
}
return score;
}
/**
* @override
* @param {number} itemIndex
* @param {string} query
* @param {!Element} titleElement
* @param {!Element} subtitleElement
*/
renderItem(itemIndex, query, titleElement, subtitleElement) {
const command = this._commands[itemIndex];
titleElement.removeChildren();
const tagElement = /** @type {!HTMLElement} */ (titleElement.createChild('span', 'tag'));
const index = String.hashCode(command.category()) % MaterialPaletteColors.length;
tagElement.style.backgroundColor = MaterialPaletteColors[index];
tagElement.textContent = command.category();
UI.UIUtils.createTextChild(titleElement, command.title());
FilteredListWidget.highlightRanges(titleElement, query, true);
subtitleElement.textContent = command.shortcut();
}
/**
* @override
* @param {?number} itemIndex
* @param {string} promptValue
*/
selectItem(itemIndex, promptValue) {
if (itemIndex === null) {
return;
}
this._commands[itemIndex].execute();
Host.userMetrics.actionTaken(Host.UserMetrics.Action.SelectCommandFromCommandMenu);
}
/**
* @override
* @return {string}
*/
notFoundText() {
return ls`No commands found`;
}
}
export const MaterialPaletteColors = [
'#F44336', '#E91E63', '#9C27B0', '#673AB7', '#3F51B5', '#03A9F4', '#00BCD4', '#009688', '#4CAF50', '#8BC34A',
'#CDDC39', '#FFC107', '#FF9800', '#FF5722', '#795548', '#9E9E9E', '#607D8B'
];
export class Command {
/**
* @param {string} category
* @param {string} title
* @param {string} key
* @param {string} shortcut
* @param {function():*} executeHandler
* @param {function()=} availableHandler
*/
constructor(category, title, key, shortcut, executeHandler, availableHandler) {
this._category = category;
this._title = title;
this._key = category + '\0' + title + '\0' + key;
this._shortcut = shortcut;
this._executeHandler = executeHandler;
this._availableHandler = availableHandler;
}
/**
* @return {string}
*/
category() {
return this._category;
}
/**
* @return {string}
*/
title() {
return this._title;
}
/**
* @return {string}
*/
key() {
return this._key;
}
/**
* @return {string}
*/
shortcut() {
return this._shortcut;
}
/**
* @return {boolean}
*/
available() {
return this._availableHandler ? this._availableHandler() : true;
}
execute() {
this._executeHandler();
}
}
/**
* @implements {UI.ActionRegistration.ActionDelegate}
*/
export class ShowActionDelegate {
/**
* @override
* @param {!UI.Context.Context} context
* @param {string} actionId
* @return {boolean}
*/
handleAction(context, actionId) {
Host.InspectorFrontendHost.InspectorFrontendHostInstance.bringToFront();
QuickOpenImpl.show('>');
return true;
}
}