Refactor mentions

This commit is contained in:
Saoud Rizwan
2024-09-24 12:32:47 -04:00
parent ae1c06b711
commit a82ff941b9
3 changed files with 2 additions and 2 deletions

179
src/core/mentions/index.ts Normal file
View File

@@ -0,0 +1,179 @@
import * as vscode from "vscode"
import * as path from "path"
import { openFile } from "../../integrations/misc/open-file"
import { UrlContentFetcher } from "../../services/browser/UrlContentFetcher"
import { mentionRegexGlobal } from "../../shared/context-mentions"
import fs from "fs/promises"
import { extractTextFromFile } from "../../integrations/misc/extract-text"
import { isBinaryFile } from "isbinaryfile"
import { diagnosticsToProblemsString } from "../../integrations/diagnostics"
export function openMention(mention?: string): void {
if (!mention) {
return
}
if (mention.startsWith("/")) {
const relPath = mention.slice(1)
const cwd = vscode.workspace.workspaceFolders?.map((folder) => folder.uri.fsPath).at(0)
if (!cwd) {
return
}
const absPath = path.resolve(cwd, relPath)
if (mention.endsWith("/")) {
vscode.commands.executeCommand("revealInExplorer", vscode.Uri.file(absPath))
// vscode.commands.executeCommand("vscode.openFolder", , { forceNewWindow: false }) opens in new window
} else {
openFile(absPath)
}
} else if (mention === "problems") {
vscode.commands.executeCommand("workbench.actions.view.problems")
} else if (mention.startsWith("http")) {
vscode.env.openExternal(vscode.Uri.parse(mention))
}
}
export async function parseMentions(text: string, cwd: string, urlContentFetcher: UrlContentFetcher): Promise<string> {
const mentions: Set<string> = new Set()
let parsedText = text.replace(mentionRegexGlobal, (match, mention) => {
mentions.add(mention)
if (mention.startsWith("http")) {
return `'${mention}' (see below for site content)`
} else if (mention.startsWith("/")) {
const mentionPath = mention.slice(1) // Remove the leading '/'
return mentionPath.endsWith("/")
? `'${mentionPath}' (see below for folder content)`
: `'${mentionPath}' (see below for file content)`
} else if (mention === "problems") {
return `Workspace Problems (see below for diagnostics)`
}
return match
})
const urlMention = Array.from(mentions).find((mention) => mention.startsWith("http"))
let launchBrowserError: Error | undefined
if (urlMention) {
try {
await urlContentFetcher.launchBrowser()
} catch (error) {
launchBrowserError = error
vscode.window.showErrorMessage(`Error fetching content for ${urlMention}: ${error.message}`)
}
}
for (const mention of mentions) {
if (mention.startsWith("http")) {
let result: string
if (launchBrowserError) {
result = `Error fetching content: ${launchBrowserError.message}`
} else {
try {
const markdown = await urlContentFetcher.urlToMarkdown(mention)
result = markdown
} catch (error) {
vscode.window.showErrorMessage(`Error fetching content for ${mention}: ${error.message}`)
result = `Error fetching content: ${error.message}`
}
}
parsedText += `\n\n<url_content url="${mention}">\n${result}\n</url_content>`
} else if (mention.startsWith("/")) {
const mentionPath = mention.slice(1)
try {
const content = await getFileOrFolderContent(mentionPath, cwd)
if (mention.endsWith("/")) {
parsedText += `\n\n<folder_content path="${mentionPath}">\n${content}\n</folder_content>`
} else {
parsedText += `\n\n<file_content path="${mentionPath}">\n${content}\n</file_content>`
}
} catch (error) {
if (mention.endsWith("/")) {
parsedText += `\n\n<folder_content path="${mentionPath}">\nError fetching content: ${error.message}\n</folder_content>`
} else {
parsedText += `\n\n<file_content path="${mentionPath}">\nError fetching content: ${error.message}\n</file_content>`
}
}
} else if (mention === "problems") {
try {
const problems = getWorkspaceProblems(cwd)
parsedText += `\n\n<workspace_diagnostics>\n${problems}\n</workspace_diagnostics>`
} catch (error) {
parsedText += `\n\n<workspace_diagnostics>\nError fetching diagnostics: ${error.message}\n</workspace_diagnostics>`
}
}
}
if (urlMention) {
try {
await urlContentFetcher.closeBrowser()
} catch (error) {
console.error(`Error closing browser: ${error.message}`)
}
}
return parsedText
}
async function getFileOrFolderContent(mentionPath: string, cwd: string): Promise<string> {
const absPath = path.resolve(cwd, mentionPath)
try {
const stats = await fs.stat(absPath)
if (stats.isFile()) {
const isBinary = await isBinaryFile(absPath).catch(() => false)
if (isBinary) {
return "(Binary file, unable to display content)"
}
const content = await extractTextFromFile(absPath)
return content
} else if (stats.isDirectory()) {
const entries = await fs.readdir(absPath, { withFileTypes: true })
let folderContent = ""
const fileContentPromises: Promise<string | undefined>[] = []
entries.forEach((entry, index) => {
const isLast = index === entries.length - 1
const linePrefix = isLast ? "└── " : "├── "
if (entry.isFile()) {
folderContent += `${linePrefix}${entry.name}\n`
const filePath = path.join(mentionPath, entry.name)
const absoluteFilePath = path.resolve(absPath, entry.name)
// const relativeFilePath = path.relative(cwd, absoluteFilePath);
fileContentPromises.push(
(async () => {
try {
const isBinary = await isBinaryFile(absoluteFilePath).catch(() => false)
if (isBinary) {
return undefined
}
const content = await extractTextFromFile(absoluteFilePath)
return `<file_content path="${filePath.toPosix()}">\n${content}\n</file_content>`
} catch (error) {
return undefined
}
})()
)
} else if (entry.isDirectory()) {
folderContent += `${linePrefix}${entry.name}/\n`
// not recursively getting folder contents
} else {
folderContent += `${linePrefix}${entry.name}\n`
}
})
const fileContents = (await Promise.all(fileContentPromises)).filter((content) => content)
return `${folderContent}\n${fileContents.join("\n\n")}`.trim()
} else {
return `(Failed to read contents of ${mentionPath})`
}
} catch (error) {
throw new Error(`Failed to access path "${mentionPath}": ${error.message}`)
}
}
function getWorkspaceProblems(cwd: string): string {
const diagnostics = vscode.languages.getDiagnostics()
const result = diagnosticsToProblemsString(diagnostics, cwd)
if (!result) {
return "No errors or warnings detected."
}
return result
}