BUGFIX: Fix tab completion for multi-word quoted autocomplete options (#2612)

This commit is contained in:
Lee Stutzman
2026-04-11 00:36:11 +01:00
committed by GitHub
parent 00a1bc2f6e
commit 8cbd6ff9e1
3 changed files with 37 additions and 6 deletions

View File

@@ -17,14 +17,21 @@ import { parseUnknownError } from "../utils/ErrorHelper";
import { DarknetServer } from "../Server/DarknetServer";
import { CompletedProgramName } from "@enums";
/** Extract the text being autocompleted, handling unclosed double quotes as a single token */
export function extractCurrentText(terminalText: string): string {
const quoteCount = (terminalText.match(/"/g) || []).length;
if (quoteCount % 2 === 1) return terminalText.substring(terminalText.lastIndexOf('"'));
return /[^ ]*$/.exec(terminalText)?.[0] ?? "";
}
/** Suggest all completion possibilities for the last argument in the last command being typed
* @param terminalText The current full text entered in the terminal
* @param baseDir The current working directory.
* @returns Array of possible string replacements for the current text being autocompleted.
*/
export async function getTabCompletionPossibilities(terminalText: string, baseDir = root): Promise<string[]> {
// Get the current command text
const currentText = /[^ ]*$/.exec(terminalText)?.[0] ?? "";
// Get the current command text, treating unclosed quotes as a single token
const currentText = extractCurrentText(terminalText);
// Remove the current text from the commands string
const valueWithoutCurrent = terminalText.substring(0, terminalText.length - currentText.length);
// Parse the commands string, this handles alias replacement as well.

View File

@@ -6,7 +6,7 @@ import { Paper, Popper, TextField, Typography } from "@mui/material";
import { KEY } from "../../utils/KeyboardEventKey";
import { Terminal } from "../../Terminal";
import { Player } from "@player";
import { getTabCompletionPossibilities } from "../getTabCompletionPossibilities";
import { extractCurrentText, getTabCompletionPossibilities } from "../getTabCompletionPossibilities";
import { Settings } from "../../Settings/Settings";
import { longestCommonStart } from "../../utils/StringHelperFunctions";
import { exceptionAlert } from "../../utils/helpers/exceptionAlert";
@@ -266,13 +266,16 @@ export function TerminalInput(): React.ReactElement {
if (possibilities.length === 0) return;
setSearchResults([]);
// Use quote-aware replacement: if mid-quote, replace from the opening quote
const currentText = extractCurrentText(value);
const replacePattern = currentText.startsWith('"') ? /"[^"]*$/ : /[^ ]*$/;
if (possibilities.length === 1) {
saveValue(value.replace(/[^ ]*$/, possibilities[0]) + " ");
saveValue(value.replace(replacePattern, possibilities[0]) + " ");
return;
}
// More than one possibility, check to see if there is a longer common string than currentText.
const longestMatch = longestCommonStart(possibilities);
saveValue(value.replace(/[^ ]*$/, longestMatch));
saveValue(value.replace(replacePattern, longestMatch));
setPossibilities(possibilities);
}