UNPKG

chrome-devtools-frontend

Version:
174 lines (157 loc) 6.07 kB
// Copyright 2016 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import '../../ui/kit/kit.js'; import * as i18n from '../../core/i18n/i18n.js'; import * as QuickOpen from '../../ui/legacy/components/quick_open/quick_open.js'; import * as UI from '../../ui/legacy/legacy.js'; import {html, type TemplateResult} from '../../ui/lit/lit.js'; import {SourcesView} from './SourcesView.js'; import type {UISourceCodeFrame} from './UISourceCodeFrame.js'; const UIStrings = { /** * @description Text in the go to line quick open menu of the Sources panel. */ noFileSelected: 'No file selected', /** * @description Text to show no results have been found. */ noResultsFound: 'No results found', /** * @description Text in the go to line quick open menu of the Sources panel. */ typeANumberToGoToThatLine: 'Type a number to go to that line', /** * @description Text in the go to line quick open menu of the Sources panel. * @example {0000} PH1 * @example {ffff} PH2 */ currentPositionXsTypeAnOffset: 'Type an offset between 0x{PH1} and 0x{PH2} to navigate to', /** * @description Text in the go to line quick open menu of the Sources panel that describes the current line number, file line number range, and use of the go to line menu. * @example {100} PH1 */ currentLineSTypeALineNumber: 'Type a line number between 1 and {PH1} to navigate to', /** * @description Text in the go to line quick open menu of the Sources panel. * @example {abc} PH1 */ goToOffsetXs: 'Go to offset 0x{PH1}', /** * @description Text in the go to line quick open menu of the Sources panel. * @example {2} PH1 * @example {2} PH2 */ goToLineSAndColumnS: 'Go to line {PH1} and column {PH2}', /** * @description Text in the go to line quick open menu of the Sources panel. * @example {2} PH1 */ goToLineS: 'Go to line {PH1}', } as const; const str_ = i18n.i18n.registerUIStrings('panels/sources/GoToLineQuickOpen.ts', UIStrings); const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_); export class GoToLineQuickOpen extends QuickOpen.FilteredListWidget.Provider { #goToLineStrings: string[] = []; override selectItem(_itemIndex: number|null, promptValue: string): void { const sourceFrame = this.currentSourceFrame(); if (!sourceFrame) { return; } const position = this.parsePosition(promptValue); if (!position) { return; } sourceFrame.revealPosition({lineNumber: position.line - 1, columnNumber: position.column - 1}); } override itemCount(): number { return this.#goToLineStrings.length; } override renderItem(itemIndex: number, _query: string): TemplateResult { // clang-format off return html` <devtools-icon name="colon"></devtools-icon> <div> <div>${this.#goToLineStrings[itemIndex]}</div> </div>`; // clang-format on } override rewriteQuery(_query: string): string { // For Go to Line Quick Open, we don't need to filter any item, set query to empty string, so the filter regex matching will be skipped return ''; } override queryChanged(query: string): void { this.#goToLineStrings = []; const position = this.parsePosition(query); const sourceFrame = this.currentSourceFrame(); if (!position) { if (!sourceFrame) { this.#goToLineStrings.push(i18nString(UIStrings.typeANumberToGoToThatLine)); return; } const editorState = sourceFrame.textEditor.state; const disassembly = sourceFrame.wasmDisassembly; if (disassembly) { const lastBytecodeOffset = disassembly.lineNumberToBytecodeOffset(disassembly.lineNumbers - 1); const bytecodeOffsetDigits = lastBytecodeOffset.toString(16).length; this.#goToLineStrings.push(i18nString(UIStrings.currentPositionXsTypeAnOffset, { PH1: '0'.padStart(bytecodeOffsetDigits, '0'), PH2: lastBytecodeOffset.toString(16), })); return; } const linesCount = sourceFrame.editorLocationToUILocation(editorState.doc.lines - 1).lineNumber + 1; this.#goToLineStrings.push(i18nString(UIStrings.currentLineSTypeALineNumber, {PH1: linesCount})); return; } if (sourceFrame?.wasmDisassembly) { this.#goToLineStrings.push(i18nString(UIStrings.goToOffsetXs, {PH1: (position.column - 1).toString(16)})); return; } if (position.column && position.column > 1) { this.#goToLineStrings.push(i18nString(UIStrings.goToLineSAndColumnS, {PH1: position.line, PH2: position.column})); return; } if (sourceFrame && position.line > sourceFrame.textEditor.state.doc.lines) { return; } this.#goToLineStrings.push(i18nString(UIStrings.goToLineS, {PH1: position.line})); } override notFoundText(_query: string): string { if (!this.currentSourceFrame()) { return i18nString(UIStrings.noFileSelected); } return i18nString(UIStrings.noResultsFound); } private parsePosition(query: string): { line: number, column: number, }|null { const sourceFrame = this.currentSourceFrame(); if (sourceFrame?.wasmDisassembly) { const parts = query.match(/0x([0-9a-fA-F]+)/); if (!parts?.[0] || parts[0].length !== query.length) { return null; } const column = parseInt(parts[0], 16) + 1; return {line: 0, column}; } const parts = query.match(/([0-9]+)(\:[0-9]*)?/); if (!parts?.[0] || parts[0].length !== query.length) { return null; } const line = parseInt(parts[1], 10); let column = 0; if (parts[2]) { column = parseInt(parts[2].substring(1), 10); } return {line: Math.max(line | 0, 1), column: Math.max(column | 0, 1)}; } private currentSourceFrame(): UISourceCodeFrame|null { const sourcesView = UI.Context.Context.instance().flavor(SourcesView); if (!sourcesView) { return null; } return sourcesView.currentSourceFrame(); } }