mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-06-28 12:17:02 -07:00
fix: strip line/column suffixes from Windows path links
This PR implements a workaround for issue #26902 where terminal link handlers on Windows (specifically in the Antigravity editor and standard VS Code) fail to correctly parse and open absolute file paths that include `:line:column` suffixes. On Windows, colons are invalid characters in file paths (except for the drive letter), causing `FileSystemError` when these links are clicked. ### Changes: - Added `stripLineColumnSuffixes` utility in `packages/core/src/utils/textUtils.ts`. - Applied this utility across various output formatting paths to ensure safe link generation on Windows: - `packages/cli/src/ui/utils/textOutput.ts` (Non-interactive mode) - `packages/cli/src/ui/utils/markdownParsingUtils.ts` (Agent output in interactive mode) - `packages/core/src/utils/debugLogger.ts` (Core debug logging) - `packages/cli/src/ui/utils/ConsolePatcher.ts` (Interactive mode console redirection) - Added comprehensive unit tests in `packages/core/src/utils/textUtils.test.ts`. These changes are only active when running on Windows (`process.platform === 'win32'`). Fixes #26902 cc @google-gemini/gemini-cli-maintainers
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
/* eslint-disable no-console */
|
||||
|
||||
import util from 'node:util';
|
||||
import { stripLineColumnSuffixes } from '@google/gemini-cli-core';
|
||||
import type { ConsoleMessageItem } from '../types.js';
|
||||
|
||||
interface ConsolePatcherParams {
|
||||
@@ -45,7 +46,10 @@ export class ConsolePatcher {
|
||||
console.info = this.originalConsoleInfo;
|
||||
};
|
||||
|
||||
private formatArgs = (args: unknown[]): string => util.format(...args);
|
||||
private formatArgs = (args: unknown[]): string => {
|
||||
const formatted = util.format(...args);
|
||||
return stripLineColumnSuffixes(formatted);
|
||||
};
|
||||
|
||||
private patchConsoleMethod =
|
||||
(type: 'log' | 'warn' | 'error' | 'debug' | 'info') =>
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
INK_NAME_TO_HEX_MAP,
|
||||
} from '../themes/color-utils.js';
|
||||
import { theme } from '../semantic-colors.js';
|
||||
import { debugLogger } from '@google/gemini-cli-core';
|
||||
import { debugLogger, stripLineColumnSuffixes } from '@google/gemini-cli-core';
|
||||
import { convertLatexToUnicode } from './latexToUnicode.js';
|
||||
|
||||
// Constants for Markdown parsing
|
||||
@@ -108,6 +108,12 @@ export const parseMarkdownToANSI = (
|
||||
defaultColor?: string,
|
||||
): string => {
|
||||
const baseColor = defaultColor ?? theme.text.primary;
|
||||
// Strip line and column number suffixes from Windows paths BEFORE any other
|
||||
// processing. This ensures that we don't break markdown parsing or URL
|
||||
// detection, and that the final output is safe for Windows terminal links.
|
||||
// See issue #26902.
|
||||
const sanitizedRawText = stripLineColumnSuffixes(rawText);
|
||||
|
||||
// Convert LaTeX-style math/commands to Unicode BEFORE tokenizing markdown,
|
||||
// so constructs like `$\{P_0, \dots, P_n\}$` are handled as a whole even
|
||||
// when they contain underscores (which the tokenizer would otherwise treat
|
||||
@@ -115,7 +121,7 @@ export const parseMarkdownToANSI = (
|
||||
// conversion so their contents are preserved verbatim. Unknown `\foo`
|
||||
// sequences are left alone, so Windows paths and regex escapes survive.
|
||||
// See issue #25656.
|
||||
const text = convertLatexPreservingSpans(rawText);
|
||||
const text = convertLatexPreservingSpans(sanitizedRawText);
|
||||
// Early return for plain text without markdown or URLs
|
||||
if (!/[*_~`<[https?:]/.test(text)) {
|
||||
return ansiColorize(text, baseColor);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
*/
|
||||
|
||||
import stripAnsi from 'strip-ansi';
|
||||
import { stripLineColumnSuffixes } from '@google/gemini-cli-core';
|
||||
|
||||
export class TextOutput {
|
||||
private atStartOfLine = true;
|
||||
@@ -27,8 +28,9 @@ export class TextOutput {
|
||||
if (str.length === 0) {
|
||||
return;
|
||||
}
|
||||
this.outputStream.write(str);
|
||||
const strippedStr = stripAnsi(str);
|
||||
const processedStr = stripLineColumnSuffixes(str);
|
||||
this.outputStream.write(processedStr);
|
||||
const strippedStr = stripAnsi(processedStr);
|
||||
if (strippedStr.length > 0) {
|
||||
this.atStartOfLine = strippedStr.endsWith('\n');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user