Browse Source

Minor fixes

Saoud Rizwan 1 year ago
parent
commit
826ee28fc1

+ 13 - 10
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<url_content url="${mention}">\n${result}\n</url_content>`
 		} 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<string | undefined>[] = []
-			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})`
 		}

+ 9 - 4
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<HTMLTextAreaElement, ChatTextAreaProps>(
 						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()

+ 16 - 3
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
 }