Minor fixes

This commit is contained in:
Saoud Rizwan
2024-09-19 15:17:24 -04:00
parent 73f082bf98
commit 826ee28fc1
3 changed files with 38 additions and 17 deletions

View File

@@ -39,9 +39,10 @@ export async function parseMentions(text: string, cwd: string, urlScraper: UrlSc
if (mention.startsWith("http")) { if (mention.startsWith("http")) {
return `'${mention}' (see below for site content)` return `'${mention}' (see below for site content)`
} else if (mention.startsWith("/")) { } else if (mention.startsWith("/")) {
return mention.endsWith("/") const mentionPath = mention.slice(1) // Remove the leading '/'
? `'${mention}' (see below for folder content)` return mentionPath.endsWith("/")
: `'${mention}' (see below for file content)` ? `'${mentionPath}' (see below for folder content)`
: `'${mentionPath}' (see below for file content)`
} else if (mention === "problems") { } else if (mention === "problems") {
return `Workspace Problems (see below for diagnostics)` 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>` parsedText += `\n\n<url_content url="${mention}">\n${result}\n</url_content>`
} else if (mention.startsWith("/")) { } else if (mention.startsWith("/")) {
const mentionPath = mention.slice(1) // Remove the leading '/' const mentionPath = mention.slice(1)
try { try {
const content = await getFileOrFolderContent(mentionPath, cwd) const content = await getFileOrFolderContent(mentionPath, cwd)
if (mention.endsWith("/")) { if (mention.endsWith("/")) {
@@ -126,11 +127,13 @@ async function getFileOrFolderContent(mentionPath: string, cwd: string): Promise
return content return content
} else if (stats.isDirectory()) { } else if (stats.isDirectory()) {
const entries = await fs.readdir(absPath, { withFileTypes: true }) const entries = await fs.readdir(absPath, { withFileTypes: true })
let directoryContent = "" let folderContent = ""
const fileContentPromises: Promise<string | undefined>[] = [] const fileContentPromises: Promise<string | undefined>[] = []
entries.forEach((entry) => { entries.forEach((entry, index) => {
const isLast = index === entries.length - 1
const linePrefix = isLast ? "└── " : "├── "
if (entry.isFile()) { if (entry.isFile()) {
directoryContent += `- File: ${entry.name}\n` folderContent += `${linePrefix}${entry.name}\n`
const filePath = path.join(mentionPath, entry.name) const filePath = path.join(mentionPath, entry.name)
const absoluteFilePath = path.resolve(absPath, entry.name) const absoluteFilePath = path.resolve(absPath, entry.name)
// const relativeFilePath = path.relative(cwd, absoluteFilePath); // const relativeFilePath = path.relative(cwd, absoluteFilePath);
@@ -149,14 +152,14 @@ async function getFileOrFolderContent(mentionPath: string, cwd: string): Promise
})() })()
) )
} else if (entry.isDirectory()) { } else if (entry.isDirectory()) {
directoryContent += `- Directory: ${entry.name}/\n` folderContent += `${linePrefix}${entry.name}/\n`
// not recursively getting folder contents // not recursively getting folder contents
} else { } else {
directoryContent += `- Other: ${entry.name}\n` folderContent += `${linePrefix}${entry.name}\n`
} }
}) })
const fileContents = (await Promise.all(fileContentPromises)).filter((content) => content) 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 { } else {
return `(Failed to read contents of ${mentionPath})` return `(Failed to read contents of ${mentionPath})`
} }

View File

@@ -1,17 +1,17 @@
import React, { forwardRef, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react" import React, { forwardRef, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react"
import DynamicTextArea from "react-textarea-autosize" import DynamicTextArea from "react-textarea-autosize"
import { mentionRegex, mentionRegexGlobal } from "../../../src/shared/context-mentions"
import { useExtensionState } from "../context/ExtensionStateContext" import { useExtensionState } from "../context/ExtensionStateContext"
import { import {
ContextMenuOptionType,
getContextMenuOptions, getContextMenuOptions,
insertMention, insertMention,
removeMention, removeMention,
shouldShowContextMenu, shouldShowContextMenu,
ContextMenuOptionType,
} from "../utils/context-mentions" } from "../utils/context-mentions"
import { MAX_IMAGES_PER_MESSAGE } from "./ChatView" import { MAX_IMAGES_PER_MESSAGE } from "./ChatView"
import ContextMenu from "./ContextMenu" import ContextMenu from "./ContextMenu"
import Thumbnails from "./Thumbnails" import Thumbnails from "./Thumbnails"
import { mentionRegex, mentionRegexGlobal } from "../../../src/shared/context-mentions"
interface ChatTextAreaProps { interface ChatTextAreaProps {
inputValue: string inputValue: string
@@ -116,9 +116,14 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
insertValue = "problems" insertValue = "problems"
} }
const newValue = insertMention(textAreaRef.current.value, cursorPosition, insertValue) const { newValue, mentionIndex } = insertMention(
textAreaRef.current.value,
cursorPosition,
insertValue
)
setInputValue(newValue) setInputValue(newValue)
const newCursorPosition = newValue.indexOf(" ", newValue.lastIndexOf("@")) + 1 const newCursorPosition = newValue.indexOf(" ", mentionIndex + insertValue.length) + 1
setCursorPosition(newCursorPosition) setCursorPosition(newCursorPosition)
setIntendedCursorPosition(newCursorPosition) setIntendedCursorPosition(newCursorPosition)
textAreaRef.current.focus() textAreaRef.current.focus()

View File

@@ -1,20 +1,31 @@
import { mentionRegex } from "../../../src/shared/context-mentions" 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 beforeCursor = text.slice(0, position)
const afterCursor = text.slice(position) const afterCursor = text.slice(position)
// Find the position of the last '@' symbol before the cursor // Find the position of the last '@' symbol before the cursor
const lastAtIndex = beforeCursor.lastIndexOf("@") const lastAtIndex = beforeCursor.lastIndexOf("@")
let newValue: string
let mentionIndex: number
if (lastAtIndex !== -1) { if (lastAtIndex !== -1) {
// If there's an '@' symbol, replace everything after it with the new mention // If there's an '@' symbol, replace everything after it with the new mention
const beforeMention = text.slice(0, lastAtIndex) const beforeMention = text.slice(0, lastAtIndex)
return beforeMention + "@" + value + " " + afterCursor.replace(/^[^\s]*/, "") newValue = beforeMention + "@" + value + " " + afterCursor.replace(/^[^\s]*/, "")
mentionIndex = lastAtIndex
} else { } else {
// If there's no '@' symbol, insert the mention at the cursor position // 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 } { 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 // Don't show the menu if it's a problems
if (textAfterAt.toLowerCase().startsWith("problems")) return false 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) // Show the menu if there's just '@' or '@' followed by some text (but not a URL)
return true return true
} }