From 826ee28fc1fa1d60f3d112b89e9d5af154ec2fe4 Mon Sep 17 00:00:00 2001 From: Saoud Rizwan <7799382+saoudrizwan@users.noreply.github.com> Date: Thu, 19 Sep 2024 15:17:24 -0400 Subject: [PATCH] Minor fixes --- src/utils/context-mentions.ts | 23 ++++++++++++---------- webview-ui/src/components/ChatTextArea.tsx | 13 ++++++++---- webview-ui/src/utils/context-mentions.ts | 19 +++++++++++++++--- 3 files changed, 38 insertions(+), 17 deletions(-) diff --git a/src/utils/context-mentions.ts b/src/utils/context-mentions.ts index a8f9af7..bc59a73 100644 --- a/src/utils/context-mentions.ts +++ b/src/utils/context-mentions.ts @@ -39,9 +39,10 @@ export async function parseMentions(text: string, cwd: string, urlScraper: UrlSc if (mention.startsWith("http")) { return `'${mention}' (see below for site content)` } else if (mention.startsWith("/")) { - return mention.endsWith("/") - ? `'${mention}' (see below for folder content)` - : `'${mention}' (see below for file content)` + 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)` } @@ -75,7 +76,7 @@ export async function parseMentions(text: string, cwd: string, urlScraper: UrlSc } parsedText += `\n\n\n${result}\n` } else if (mention.startsWith("/")) { - const mentionPath = mention.slice(1) // Remove the leading '/' + const mentionPath = mention.slice(1) try { const content = await getFileOrFolderContent(mentionPath, cwd) if (mention.endsWith("/")) { @@ -126,11 +127,13 @@ async function getFileOrFolderContent(mentionPath: string, cwd: string): Promise return content } else if (stats.isDirectory()) { const entries = await fs.readdir(absPath, { withFileTypes: true }) - let directoryContent = "" + let folderContent = "" const fileContentPromises: Promise[] = [] - entries.forEach((entry) => { + entries.forEach((entry, index) => { + const isLast = index === entries.length - 1 + const linePrefix = isLast ? "└── " : "├── " if (entry.isFile()) { - directoryContent += `- File: ${entry.name}\n` + 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); @@ -149,14 +152,14 @@ async function getFileOrFolderContent(mentionPath: string, cwd: string): Promise })() ) } else if (entry.isDirectory()) { - directoryContent += `- Directory: ${entry.name}/\n` + folderContent += `${linePrefix}${entry.name}/\n` // not recursively getting folder contents } else { - directoryContent += `- Other: ${entry.name}\n` + folderContent += `${linePrefix}${entry.name}\n` } }) const fileContents = (await Promise.all(fileContentPromises)).filter((content) => content) - return `${directoryContent}\n${fileContents.join("\n")}`.trim() + return `${folderContent}\n${fileContents.join("\n\n")}`.trim() } else { return `(Failed to read contents of ${mentionPath})` } diff --git a/webview-ui/src/components/ChatTextArea.tsx b/webview-ui/src/components/ChatTextArea.tsx index cca75a1..b2c8311 100644 --- a/webview-ui/src/components/ChatTextArea.tsx +++ b/webview-ui/src/components/ChatTextArea.tsx @@ -1,17 +1,17 @@ import React, { forwardRef, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react" import DynamicTextArea from "react-textarea-autosize" +import { mentionRegex, mentionRegexGlobal } from "../../../src/shared/context-mentions" import { useExtensionState } from "../context/ExtensionStateContext" import { + ContextMenuOptionType, getContextMenuOptions, insertMention, removeMention, shouldShowContextMenu, - ContextMenuOptionType, } from "../utils/context-mentions" import { MAX_IMAGES_PER_MESSAGE } from "./ChatView" import ContextMenu from "./ContextMenu" import Thumbnails from "./Thumbnails" -import { mentionRegex, mentionRegexGlobal } from "../../../src/shared/context-mentions" interface ChatTextAreaProps { inputValue: string @@ -116,9 +116,14 @@ const ChatTextArea = forwardRef( insertValue = "problems" } - const newValue = insertMention(textAreaRef.current.value, cursorPosition, insertValue) + const { newValue, mentionIndex } = insertMention( + textAreaRef.current.value, + cursorPosition, + insertValue + ) + setInputValue(newValue) - const newCursorPosition = newValue.indexOf(" ", newValue.lastIndexOf("@")) + 1 + const newCursorPosition = newValue.indexOf(" ", mentionIndex + insertValue.length) + 1 setCursorPosition(newCursorPosition) setIntendedCursorPosition(newCursorPosition) textAreaRef.current.focus() diff --git a/webview-ui/src/utils/context-mentions.ts b/webview-ui/src/utils/context-mentions.ts index 8286527..a5fb420 100644 --- a/webview-ui/src/utils/context-mentions.ts +++ b/webview-ui/src/utils/context-mentions.ts @@ -1,20 +1,31 @@ import { mentionRegex } from "../../../src/shared/context-mentions" -export function insertMention(text: string, position: number, value: string): string { +export function insertMention( + text: string, + position: number, + value: string +): { newValue: string; mentionIndex: number } { const beforeCursor = text.slice(0, position) const afterCursor = text.slice(position) // Find the position of the last '@' symbol before the cursor const lastAtIndex = beforeCursor.lastIndexOf("@") + let newValue: string + let mentionIndex: number + if (lastAtIndex !== -1) { // If there's an '@' symbol, replace everything after it with the new mention const beforeMention = text.slice(0, lastAtIndex) - return beforeMention + "@" + value + " " + afterCursor.replace(/^[^\s]*/, "") + newValue = beforeMention + "@" + value + " " + afterCursor.replace(/^[^\s]*/, "") + mentionIndex = lastAtIndex } else { // If there's no '@' symbol, insert the mention at the cursor position - return beforeCursor + "@" + value + " " + afterCursor + newValue = beforeCursor + "@" + value + " " + afterCursor + mentionIndex = position } + + return { newValue, mentionIndex } } export function removeMention(text: string, position: number): { newText: string; newPosition: number } { @@ -111,6 +122,8 @@ export function shouldShowContextMenu(text: string, position: number): boolean { // Don't show the menu if it's a problems if (textAfterAt.toLowerCase().startsWith("problems")) return false + // NOTE: it's okay that menu shows when there's trailing punctuation since user could be inputting a path with marks + // Show the menu if there's just '@' or '@' followed by some text (but not a URL) return true }