diff --git a/src/lib/context.ts b/src/lib/context.ts index 6184153..d570721 100644 --- a/src/lib/context.ts +++ b/src/lib/context.ts @@ -2,7 +2,7 @@ import * as vscode from 'vscode'; import { AllQPItemVariants, DisposablesMap } from '../types'; import { getConfig } from '../utils/getConfig'; import { ChildProcessWithoutNullStreams } from 'child_process'; -import { highlightLineDecorationType } from '../utils/highlightLineDecorationType'; +import { initHighlightLineInstance } from '../utils/highlightLineDecorationType'; // simple context for each invoke of periscope search let qp = vscode.window.createQuickPick(); // @see https://code.visualstudio.com/api/references/vscode-api#QuickPick @@ -11,7 +11,7 @@ let query = ''; let spawnRegistry: ChildProcessWithoutNullStreams[] = []; let config = getConfig(); let rgMenuActionsSelected: string[] = []; -let highlightDecoration = highlightLineDecorationType(); +let highlightDecoration = initHighlightLineInstance(); let disposables: DisposablesMap = { general: [], rgMenuActions: [], @@ -38,7 +38,7 @@ function resetContext() { context.spawnRegistry = []; context.config = getConfig(); context.rgMenuActionsSelected = []; - context.highlightDecoration = highlightLineDecorationType(); + context.highlightDecoration = initHighlightLineInstance(); context.disposables = { general: [], rgMenuActions: [], diff --git a/src/lib/globalActions.ts b/src/lib/globalActions.ts index 2561699..e75fb41 100644 --- a/src/lib/globalActions.ts +++ b/src/lib/globalActions.ts @@ -7,10 +7,23 @@ import { context as cx } from './context'; import { QPItemQuery } from '../types'; import { closePreviewEditor, setCursorPosition } from './editorActions'; -export function accept(item?: QPItemQuery) { +type ConfirmPayload = ConfirmPayloadDefault | ConfirmHorizontalSplitPayload; + +type ConfirmPayloadDefault = { context: 'unknown' }; + +type ConfirmHorizontalSplitPayload = { + item: QPItemQuery + context: 'openInHorizontalSplit' +}; + +export function confirm(payload: ConfirmPayload = {context: 'unknown'}) { checkKillProcess(); - const currentItem = item ? item : cx.qp.selectedItems[0] as QPItemQuery; + let currentItem = cx.qp.selectedItems[0] as QPItemQuery; + if (payload.context === 'openInHorizontalSplit') { + currentItem = payload.item; + } + if (!currentItem?.data) { return; } @@ -19,7 +32,7 @@ export function accept(item?: QPItemQuery) { vscode.workspace.openTextDocument(path.resolve(filePath)).then(document => { const options: vscode.TextDocumentShowOptions = {}; - if(item) { // horizontal split + if(payload.context === 'openInHorizontalSplit') { options.viewColumn = vscode.ViewColumn.Beside; closePreviewEditor(); } diff --git a/src/lib/quickpickActions.ts b/src/lib/quickpickActions.ts index 0741cdf..20fe32d 100644 --- a/src/lib/quickpickActions.ts +++ b/src/lib/quickpickActions.ts @@ -1,12 +1,12 @@ import * as vscode from 'vscode'; import { AllQPItemVariants, QPItemQuery, QPItemRgMenuAction } from "../types"; import { openNativeVscodeSearch, peekItem } from "./editorActions"; -import { checkKillProcess, extraRgFlagsFromQuery, search } from "./ripgrep"; +import { checkKillProcess, checkAndExtractRgFlagsFromQuery, rgSearch } from "./ripgrep"; import { context as cx } from './context'; import { getSelectedText } from "../utils/getSelectedText"; import { log } from '../utils/log'; import { previousActiveEditor } from './editorContext'; -import { accept, finished } from './globalActions'; +import { confirm, finished } from './globalActions'; // update quickpick event listeners for the query export function setupQuickPickForQuery() { @@ -36,43 +36,41 @@ export function reset() { function onDidChangeValue(value: string) { checkKillProcess(); - if (value) { - cx.query = value; - - // Jump to rg menu actions - if ( - cx.config.gotoRgMenuActionsPrefix && - value.startsWith(cx.config.gotoRgMenuActionsPrefix) - ) { - setupRgMenuActions(); - return; - } + if (!value) { + cx.qp.items = []; + return; + } - // Jump to native vscode search option - if ( - cx.config.enableGotoNativeSearch && - cx.config.gotoNativeSearchSuffix && - value.endsWith(cx.config.gotoNativeSearchSuffix) - ) { - openNativeVscodeSearch(cx.query, cx.qp); - return; - } + cx.query = value; - if(cx.config.rgQueryParams.length > 0) { - const { newQuery, extraRgFlags } = extraRgFlagsFromQuery(value); - cx.query = newQuery; // update query for later use + // jump to rg custom menu if the prefix is found in the query + if ( + cx.config.gotoRgMenuActionsPrefix && + value.startsWith(cx.config.gotoRgMenuActionsPrefix) + ) { + setupRgMenuActions(); + return; + } - if(cx.config.rgQueryParamsShowTitle) { // update title with preview - cx.qp.title = extraRgFlags.length > 0 ? `rg '${cx.query}' ${extraRgFlags.join(' ')}` : undefined; - } + // jump to native vscode search if the suffix is found in the query + if ( + cx.config.enableGotoNativeSearch && + cx.config.gotoNativeSearchSuffix && + value.endsWith(cx.config.gotoNativeSearchSuffix) + ) { + openNativeVscodeSearch(cx.query, cx.qp); + return; + } - search(newQuery, extraRgFlags); - } else { - search(value); - } - } else { - cx.qp.items = []; + // update the query if rgQueryParams are available and found + const { updatedQuery, extraRgFlags } = checkAndExtractRgFlagsFromQuery(value); + + // update the quickpick title with a preview of the rgQueryParam command if utilised + if(cx.config.rgQueryParamsShowTitle) { + cx.qp.title = extraRgFlags.length > 0 ? `rg '${cx.query}' ${extraRgFlags.join(' ')}` : undefined; } + + rgSearch(updatedQuery, extraRgFlags); } // when item is 'FOCUSSED' @@ -82,14 +80,19 @@ function onDidChangeActive(items: readonly AllQPItemVariants[]) { // when item is 'SELECTED' function onDidAccept() { - accept(); + confirm(); } // when item button is 'TRIGGERED' +// this is the rightmost button on the quickpick item function onDidTriggerItemButton(e: vscode.QuickPickItemButtonEvent) { log('item button triggered'); if (e.item._type === 'QuickPickItemQuery') { - accept(e.item); + // as there is only horizontal split as an option we can assume this + confirm({ + context: 'openInHorizontalSplit', + item: e.item + }); } } diff --git a/src/lib/ripgrep.ts b/src/lib/ripgrep.ts index 8601671..4da435f 100644 --- a/src/lib/ripgrep.ts +++ b/src/lib/ripgrep.ts @@ -1,16 +1,24 @@ +import { rgPath } from '@vscode/ripgrep'; import { spawn } from 'child_process'; import * as vscode from 'vscode'; import { getConfig } from "../utils/getConfig"; -import { ripgrepPath } from "../utils/ripgrep"; import { context as cx } from './context'; import { tryJsonParse } from '../utils/jsonUtils'; import { QPItemQuery, RgLine } from '../types'; import { log, notifyError } from '../utils/log'; import { createResultItem } from '../utils/quickpickUtils'; import { handleNoResultsFound } from './editorActions'; -import { parse } from 'path'; -export function rgCommand(value: string, extraFlags?: string[]) { +// grab the bundled ripgrep binary from vscode +function ripgrepPath(optionsPath?: string) { + if(optionsPath?.trim()) { + return optionsPath.trim(); + } + + return rgPath; +} + +function getRgCommand(value: string, extraFlags?: string[]) { let config = getConfig(); let workspaceFolders = vscode.workspace.workspaceFolders; @@ -46,9 +54,9 @@ export function rgCommand(value: string, extraFlags?: string[]) { return `"${rgPath}" "${value}" ${rgFlags.join(' ')}`; } -export function search(value: string, rgExtraFlags?: string[]) { +export function rgSearch(value: string, rgExtraFlags?: string[]) { cx.qp.busy = true; - const rgCmd = rgCommand(value, rgExtraFlags); + const rgCmd = getRgCommand(value, rgExtraFlags); log('rgCmd:', rgCmd); checkKillProcess(); let searchResults: any[] = []; @@ -63,20 +71,7 @@ export function search(value: string, rgExtraFlags?: string[]) { const parsedLine = tryJsonParse(line); if (parsedLine?.type === 'match') { - // eslint-disable-next-line @typescript-eslint/naming-convention - const { path, lines, line_number } = parsedLine.data; - const filePath = path.text; - const linePos = line_number; - const colPos = parsedLine.data.submatches[0].start + 1; - const textResult = lines.text.trim(); - - const resultItem = { - filePath, - linePos, - colPos, - textResult - }; - searchResults.push(resultItem); + searchResults.push(normaliseRgResult(parsedLine)); } } }); @@ -134,6 +129,22 @@ export function search(value: string, rgExtraFlags?: string[]) { }); } +function normaliseRgResult(parsedLine: RgLine) { + // eslint-disable-next-line @typescript-eslint/naming-convention + const { path, lines, line_number } = parsedLine.data; + const filePath = path.text; + const linePos = line_number; + const colPos = parsedLine.data.submatches[0].start + 1; + const textResult = lines.text.trim(); + + return { + filePath, + linePos, + colPos, + textResult + }; +} + export function checkKillProcess() { const {spawnRegistry} = cx; spawnRegistry.forEach(spawnProcess => { @@ -149,10 +160,7 @@ export function checkKillProcess() { } // extract rg flags from the query, can match multiple regex's -export function extraRgFlagsFromQuery(query: string): { - newQuery: string; - extraRgFlags: string[]; -} { +export function checkAndExtractRgFlagsFromQuery(query: string): { updatedQuery: string, extraRgFlags: string[]} { const extraRgFlags: string[] = []; const queries = [query]; @@ -171,6 +179,6 @@ export function extraRgFlagsFromQuery(query: string): { } // prefer the first query match or the original one - const newQuery = queries.length > 1 ? queries[1] : queries[0]; - return { newQuery, extraRgFlags }; + const updatedQuery = queries.length > 1 ? queries[1] : queries[0]; + return { updatedQuery, extraRgFlags }; } diff --git a/src/utils/highlightLineDecorationType.ts b/src/utils/highlightLineDecorationType.ts index 77b371e..08c2821 100644 --- a/src/utils/highlightLineDecorationType.ts +++ b/src/utils/highlightLineDecorationType.ts @@ -2,9 +2,9 @@ import * as vscode from 'vscode'; import { getConfig } from './getConfig'; /** - * Util to create a decoration type (for highlighting) for when 'peeking' at a file + * Util to create a highlight decoration on matches when 'peeking' at a file */ -export function highlightLineDecorationType() { +export function initHighlightLineInstance() { const { peekBorderColor: borderColor, peekBorderWidth: borderWidth,