Path: blob/main/src/vs/workbench/contrib/chat/browser/tools/toolHelpers.ts
13406 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { MarkdownString } from '../../../../../base/common/htmlContent.js';6import { escapeRegExpCharacters } from '../../../../../base/common/strings.js';7import { URI } from '../../../../../base/common/uri.js';8import { ITextModel } from '../../../../../editor/common/model.js';9import { IWorkspaceContextService } from '../../../../../platform/workspace/common/workspace.js';10import { IToolResult } from '../../common/tools/languageModelToolsService.js';11import { createToolSimpleTextResult } from '../../common/tools/builtinTools/toolHelpers.js';1213export interface ISymbolToolInput {14symbol: string;15uri?: string;16filePath?: string;17lineContent: string;18}1920/**21* Resolves a URI from tool input. Accepts either a full URI string or a22* workspace-relative file path.23*/24export function resolveToolUri(input: ISymbolToolInput, workspaceContextService: IWorkspaceContextService): URI | undefined {25if (input.uri) {26return URI.parse(input.uri);27}28if (input.filePath) {29const folders = workspaceContextService.getWorkspace().folders;30if (folders.length === 1) {31return folders[0].toResource(input.filePath);32}33// try each folder, return the first34for (const folder of folders) {35return folder.toResource(input.filePath);36}37}38return undefined;39}4041/**42* Finds the line number in the model that matches the given line content.43* Whitespace is normalized so that extra spaces in the input still match.44*45* @returns The 1-based line number, or `undefined` if not found.46*/47export function findLineNumber(model: ITextModel, lineContent: string): number | undefined {48const parts = lineContent.trim().split(/\s+/);49const pattern = parts.map(escapeRegExpCharacters).join('\\s+');50const matches = model.findMatches(pattern, false, true, false, null, false, 1);51if (matches.length === 0) {52return undefined;53}54return matches[0].range.startLineNumber;55}5657/**58* Finds the 1-based column of a symbol within a line of text using word59* boundary matching.60*61* @returns The 1-based column, or `undefined` if not found.62*/63export function findSymbolColumn(lineText: string, symbol: string): number | undefined {64const pattern = new RegExp(`\\b${escapeRegExpCharacters(symbol)}\\b`);65const match = pattern.exec(lineText);66if (match) {67return match.index + 1; // 1-based column68}69return undefined;70}7172/**73* Creates an error tool result with the given message as both the content74* and the tool result message.75*/76export function errorResult(message: string): IToolResult {77const result = createToolSimpleTextResult(message);78result.toolResultMessage = new MarkdownString(message);79return result;80}818283