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
}