|
@@ -8,6 +8,20 @@ import { arePathsEqual } from "../../utils/path"
|
|
|
import { getBinPath } from "../../services/ripgrep"
|
|
import { getBinPath } from "../../services/ripgrep"
|
|
|
import { DIRS_TO_IGNORE } from "./constants"
|
|
import { DIRS_TO_IGNORE } from "./constants"
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * Context object for directory scanning operations
|
|
|
|
|
+ */
|
|
|
|
|
+interface ScanContext {
|
|
|
|
|
+ /** Whether this is the explicitly targeted directory */
|
|
|
|
|
+ isTargetDir: boolean
|
|
|
|
|
+ /** Whether we're inside an explicitly targeted hidden directory */
|
|
|
|
|
+ insideExplicitHiddenTarget: boolean
|
|
|
|
|
+ /** The base path for the scan operation */
|
|
|
|
|
+ basePath: string
|
|
|
|
|
+ /** The ignore instance for gitignore handling */
|
|
|
|
|
+ ignoreInstance: ReturnType<typeof ignore>
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* List files in a directory, with optional recursive traversal
|
|
* List files in a directory, with optional recursive traversal
|
|
|
*
|
|
*
|
|
@@ -70,7 +84,13 @@ async function getFirstLevelDirectories(dirPath: string, ignoreInstance: ReturnT
|
|
|
for (const entry of entries) {
|
|
for (const entry of entries) {
|
|
|
if (entry.isDirectory() && !entry.isSymbolicLink()) {
|
|
if (entry.isDirectory() && !entry.isSymbolicLink()) {
|
|
|
const fullDirPath = path.join(absolutePath, entry.name)
|
|
const fullDirPath = path.join(absolutePath, entry.name)
|
|
|
- if (shouldIncludeDirectory(entry.name, fullDirPath, dirPath, ignoreInstance)) {
|
|
|
|
|
|
|
+ const context: ScanContext = {
|
|
|
|
|
+ isTargetDir: false,
|
|
|
|
|
+ insideExplicitHiddenTarget: false,
|
|
|
|
|
+ basePath: dirPath,
|
|
|
|
|
+ ignoreInstance,
|
|
|
|
|
+ }
|
|
|
|
|
+ if (shouldIncludeDirectory(entry.name, fullDirPath, context)) {
|
|
|
const formattedPath = fullDirPath.endsWith("/") ? fullDirPath : `${fullDirPath}/`
|
|
const formattedPath = fullDirPath.endsWith("/") ? fullDirPath : `${fullDirPath}/`
|
|
|
directories.push(formattedPath)
|
|
directories.push(formattedPath)
|
|
|
}
|
|
}
|
|
@@ -179,9 +199,14 @@ async function listFilesWithRipgrep(
|
|
|
recursive: boolean,
|
|
recursive: boolean,
|
|
|
limit: number,
|
|
limit: number,
|
|
|
): Promise<string[]> {
|
|
): Promise<string[]> {
|
|
|
|
|
+ const rgArgs = buildRipgrepArgs(dirPath, recursive)
|
|
|
|
|
+
|
|
|
|
|
+ const relativePaths = await execRipgrep(rgPath, rgArgs, limit)
|
|
|
|
|
+
|
|
|
|
|
+ // Convert relative paths from ripgrep to absolute paths
|
|
|
|
|
+ // Resolve dirPath once here for the mapping operation
|
|
|
const absolutePath = path.resolve(dirPath)
|
|
const absolutePath = path.resolve(dirPath)
|
|
|
- const rgArgs = buildRipgrepArgs(absolutePath, recursive)
|
|
|
|
|
- return execRipgrep(rgPath, rgArgs, limit)
|
|
|
|
|
|
|
+ return relativePaths.map((relativePath) => path.resolve(absolutePath, relativePath))
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -192,7 +217,7 @@ function buildRipgrepArgs(dirPath: string, recursive: boolean): string[] {
|
|
|
const args = ["--files", "--hidden", "--follow"]
|
|
const args = ["--files", "--hidden", "--follow"]
|
|
|
|
|
|
|
|
if (recursive) {
|
|
if (recursive) {
|
|
|
- return [...args, ...buildRecursiveArgs(), dirPath]
|
|
|
|
|
|
|
+ return [...args, ...buildRecursiveArgs(dirPath), dirPath]
|
|
|
} else {
|
|
} else {
|
|
|
return [...args, ...buildNonRecursiveArgs(), dirPath]
|
|
return [...args, ...buildNonRecursiveArgs(), dirPath]
|
|
|
}
|
|
}
|
|
@@ -201,14 +226,62 @@ function buildRipgrepArgs(dirPath: string, recursive: boolean): string[] {
|
|
|
/**
|
|
/**
|
|
|
* Build ripgrep arguments for recursive directory traversal
|
|
* Build ripgrep arguments for recursive directory traversal
|
|
|
*/
|
|
*/
|
|
|
-function buildRecursiveArgs(): string[] {
|
|
|
|
|
|
|
+function buildRecursiveArgs(dirPath: string): string[] {
|
|
|
const args: string[] = []
|
|
const args: string[] = []
|
|
|
|
|
|
|
|
// In recursive mode, respect .gitignore by default
|
|
// In recursive mode, respect .gitignore by default
|
|
|
// (ripgrep does this automatically)
|
|
// (ripgrep does this automatically)
|
|
|
|
|
|
|
|
|
|
+ // Check if we're explicitly targeting a hidden directory
|
|
|
|
|
+ // Normalize the path first to handle edge cases
|
|
|
|
|
+ const normalizedPath = path.normalize(dirPath)
|
|
|
|
|
+ // Split by separator and filter out empty parts
|
|
|
|
|
+ // This handles cases like trailing slashes, multiple separators, etc.
|
|
|
|
|
+ const pathParts = normalizedPath.split(path.sep).filter((part) => part.length > 0)
|
|
|
|
|
+ const isTargetingHiddenDir = pathParts.some((part) => part.startsWith("."))
|
|
|
|
|
+
|
|
|
|
|
+ // Get the target directory name to check if it's in the ignore list
|
|
|
|
|
+ const targetDirName = path.basename(dirPath)
|
|
|
|
|
+ const isTargetInIgnoreList = DIRS_TO_IGNORE.includes(targetDirName)
|
|
|
|
|
+
|
|
|
|
|
+ // If targeting a hidden directory or a directory in the ignore list,
|
|
|
|
|
+ // use special handling to ensure all files are shown
|
|
|
|
|
+ if (isTargetingHiddenDir || isTargetInIgnoreList) {
|
|
|
|
|
+ args.push("--no-ignore-vcs")
|
|
|
|
|
+ args.push("--no-ignore")
|
|
|
|
|
+
|
|
|
|
|
+ // When targeting an ignored directory, we need to be careful with glob patterns
|
|
|
|
|
+ // Add a pattern to explicitly include files at the root level
|
|
|
|
|
+ args.push("-g", "*")
|
|
|
|
|
+ args.push("-g", "**/*")
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
// Apply directory exclusions for recursive searches
|
|
// Apply directory exclusions for recursive searches
|
|
|
for (const dir of DIRS_TO_IGNORE) {
|
|
for (const dir of DIRS_TO_IGNORE) {
|
|
|
|
|
+ // Special handling for hidden directories pattern
|
|
|
|
|
+ if (dir === ".*") {
|
|
|
|
|
+ // If we're explicitly targeting a hidden directory, don't exclude hidden files/dirs
|
|
|
|
|
+ // This allows the target hidden directory and all its contents to be listed
|
|
|
|
|
+ if (!isTargetingHiddenDir) {
|
|
|
|
|
+ // Not targeting hidden dir: exclude all hidden directories
|
|
|
|
|
+ args.push("-g", `!**/.*/**`)
|
|
|
|
|
+ }
|
|
|
|
|
+ // If targeting hidden dir: don't add any exclusion for hidden directories
|
|
|
|
|
+ continue
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // When explicitly targeting a directory that's in the ignore list (e.g., "temp"),
|
|
|
|
|
+ // we need special handling:
|
|
|
|
|
+ // - Don't add any exclusion pattern for the target directory itself
|
|
|
|
|
+ // - Only exclude nested subdirectories with the same name
|
|
|
|
|
+ // This ensures all files in the target directory are listed, while still
|
|
|
|
|
+ // preventing recursion into nested directories with the same ignored name
|
|
|
|
|
+ if (dir === targetDirName && isTargetInIgnoreList) {
|
|
|
|
|
+ // Skip adding any exclusion pattern - we want to see everything in the target directory
|
|
|
|
|
+ continue
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // For all other cases, exclude the directory pattern globally
|
|
|
args.push("-g", `!**/${dir}/**`)
|
|
args.push("-g", `!**/${dir}/**`)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -231,8 +304,11 @@ function buildNonRecursiveArgs(): string[] {
|
|
|
// Apply directory exclusions for non-recursive searches
|
|
// Apply directory exclusions for non-recursive searches
|
|
|
for (const dir of DIRS_TO_IGNORE) {
|
|
for (const dir of DIRS_TO_IGNORE) {
|
|
|
if (dir === ".*") {
|
|
if (dir === ".*") {
|
|
|
- // For hidden files/dirs in non-recursive mode
|
|
|
|
|
- args.push("-g", "!.*")
|
|
|
|
|
|
|
+ // For hidden directories in non-recursive mode, we want to show the directories
|
|
|
|
|
+ // themselves but not their contents. Since we're using --maxdepth 1, this
|
|
|
|
|
+ // naturally happens - we just need to avoid excluding the directories entirely.
|
|
|
|
|
+ // We'll let the directory scanning logic handle the visibility.
|
|
|
|
|
+ continue
|
|
|
} else {
|
|
} else {
|
|
|
// Direct children only
|
|
// Direct children only
|
|
|
args.push("-g", `!${dir}`)
|
|
args.push("-g", `!${dir}`)
|
|
@@ -261,7 +337,7 @@ async function createIgnoreInstance(dirPath: string): Promise<ReturnType<typeof
|
|
|
ignoreInstance.add(content)
|
|
ignoreInstance.add(content)
|
|
|
} catch (err) {
|
|
} catch (err) {
|
|
|
// Continue if we can't read a .gitignore file
|
|
// Continue if we can't read a .gitignore file
|
|
|
- console.warn(`Error reading .gitignore at ${gitignoreFile}: ${err}`)
|
|
|
|
|
|
|
+ console.warn(`Could not read .gitignore at ${gitignoreFile}: ${err}`)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -312,7 +388,20 @@ async function listFilteredDirectories(
|
|
|
const absolutePath = path.resolve(dirPath)
|
|
const absolutePath = path.resolve(dirPath)
|
|
|
const directories: string[] = []
|
|
const directories: string[] = []
|
|
|
|
|
|
|
|
- async function scanDirectory(currentPath: string): Promise<void> {
|
|
|
|
|
|
|
+ // For environment details generation, we don't want to treat the root as a "target"
|
|
|
|
|
+ // if we're doing a general recursive scan, as this would include hidden directories
|
|
|
|
|
+ // Only treat as target if we're explicitly scanning a single hidden directory
|
|
|
|
|
+ const isExplicitHiddenTarget = path.basename(absolutePath).startsWith(".")
|
|
|
|
|
+
|
|
|
|
|
+ // Create initial context for the scan
|
|
|
|
|
+ const initialContext: ScanContext = {
|
|
|
|
|
+ isTargetDir: isExplicitHiddenTarget,
|
|
|
|
|
+ insideExplicitHiddenTarget: isExplicitHiddenTarget,
|
|
|
|
|
+ basePath: dirPath,
|
|
|
|
|
+ ignoreInstance,
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async function scanDirectory(currentPath: string, context: ScanContext): Promise<void> {
|
|
|
try {
|
|
try {
|
|
|
// List all entries in the current directory
|
|
// List all entries in the current directory
|
|
|
const entries = await fs.promises.readdir(currentPath, { withFileTypes: true })
|
|
const entries = await fs.promises.readdir(currentPath, { withFileTypes: true })
|
|
@@ -323,61 +412,155 @@ async function listFilteredDirectories(
|
|
|
const dirName = entry.name
|
|
const dirName = entry.name
|
|
|
const fullDirPath = path.join(currentPath, dirName)
|
|
const fullDirPath = path.join(currentPath, dirName)
|
|
|
|
|
|
|
|
|
|
+ // Create context for subdirectory checks
|
|
|
|
|
+ // Subdirectories found during scanning are never target directories themselves
|
|
|
|
|
+ const subdirContext: ScanContext = {
|
|
|
|
|
+ ...context,
|
|
|
|
|
+ isTargetDir: false,
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
// Check if this directory should be included
|
|
// Check if this directory should be included
|
|
|
- if (shouldIncludeDirectory(dirName, fullDirPath, dirPath, ignoreInstance)) {
|
|
|
|
|
|
|
+ if (shouldIncludeDirectory(dirName, fullDirPath, subdirContext)) {
|
|
|
// Add the directory to our results (with trailing slash)
|
|
// Add the directory to our results (with trailing slash)
|
|
|
|
|
+ // fullDirPath is already absolute since it's built with path.join from absolutePath
|
|
|
const formattedPath = fullDirPath.endsWith("/") ? fullDirPath : `${fullDirPath}/`
|
|
const formattedPath = fullDirPath.endsWith("/") ? fullDirPath : `${fullDirPath}/`
|
|
|
directories.push(formattedPath)
|
|
directories.push(formattedPath)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // If recursive mode and not a ignored directory, scan subdirectories
|
|
|
|
|
+ // Don't recurse into hidden directories unless they are the explicit target
|
|
|
|
|
+ // or we're already inside an explicitly targeted hidden directory
|
|
|
|
|
+ const isHiddenDir = dirName.startsWith(".")
|
|
|
|
|
+
|
|
|
|
|
+ // Use the same logic as shouldIncludeDirectory for recursion decisions
|
|
|
|
|
+ // When inside an explicitly targeted hidden directory, only block critical directories
|
|
|
|
|
+ let shouldRecurseIntoDir = true
|
|
|
|
|
+ if (context.insideExplicitHiddenTarget) {
|
|
|
|
|
+ // Only apply the most critical ignore patterns when inside explicit hidden target
|
|
|
|
|
+ shouldRecurseIntoDir = !CRITICAL_IGNORE_PATTERNS.has(dirName)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ shouldRecurseIntoDir = !isDirectoryExplicitlyIgnored(dirName)
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // If recursive mode and not a ignored directory, scan subdirectories
|
|
|
|
|
- if (recursive && !isDirectoryExplicitlyIgnored(dirName)) {
|
|
|
|
|
- await scanDirectory(fullDirPath)
|
|
|
|
|
|
|
+ const shouldRecurse =
|
|
|
|
|
+ recursive &&
|
|
|
|
|
+ shouldRecurseIntoDir &&
|
|
|
|
|
+ !(
|
|
|
|
|
+ isHiddenDir &&
|
|
|
|
|
+ DIRS_TO_IGNORE.includes(".*") &&
|
|
|
|
|
+ !context.isTargetDir &&
|
|
|
|
|
+ !context.insideExplicitHiddenTarget
|
|
|
|
|
+ )
|
|
|
|
|
+ if (shouldRecurse) {
|
|
|
|
|
+ // If we're entering a hidden directory that's the target, or we're already inside one,
|
|
|
|
|
+ // mark that we're inside an explicitly targeted hidden directory
|
|
|
|
|
+ const newInsideExplicitHiddenTarget =
|
|
|
|
|
+ context.insideExplicitHiddenTarget || (isHiddenDir && context.isTargetDir)
|
|
|
|
|
+ const newContext: ScanContext = {
|
|
|
|
|
+ ...context,
|
|
|
|
|
+ isTargetDir: false,
|
|
|
|
|
+ insideExplicitHiddenTarget: newInsideExplicitHiddenTarget,
|
|
|
}
|
|
}
|
|
|
|
|
+ await scanDirectory(fullDirPath, newContext)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
} catch (err) {
|
|
} catch (err) {
|
|
|
- // Silently continue if we can't read a directory
|
|
|
|
|
|
|
+ // Continue if we can't read a directory
|
|
|
console.warn(`Could not read directory ${currentPath}: ${err}`)
|
|
console.warn(`Could not read directory ${currentPath}: ${err}`)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Start scanning from the root directory
|
|
// Start scanning from the root directory
|
|
|
- await scanDirectory(absolutePath)
|
|
|
|
|
|
|
+ await scanDirectory(absolutePath, initialContext)
|
|
|
|
|
|
|
|
return directories
|
|
return directories
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * Determine if a directory should be included in results based on filters
|
|
|
|
|
|
|
+ * Critical directories that should always be ignored, even inside explicitly targeted hidden directories
|
|
|
|
|
+ */
|
|
|
|
|
+const CRITICAL_IGNORE_PATTERNS = new Set(["node_modules", ".git", "__pycache__", "venv", "env"])
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * Check if a directory matches any of the given patterns
|
|
|
|
|
+ */
|
|
|
|
|
+function matchesIgnorePattern(dirName: string, patterns: string[]): boolean {
|
|
|
|
|
+ for (const pattern of patterns) {
|
|
|
|
|
+ if (pattern === dirName || (pattern.includes("/") && pattern.split("/")[0] === dirName)) {
|
|
|
|
|
+ return true
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return false
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * Check if a directory is ignored by gitignore
|
|
|
*/
|
|
*/
|
|
|
-function shouldIncludeDirectory(
|
|
|
|
|
- dirName: string,
|
|
|
|
|
|
|
+function isIgnoredByGitignore(
|
|
|
fullDirPath: string,
|
|
fullDirPath: string,
|
|
|
basePath: string,
|
|
basePath: string,
|
|
|
ignoreInstance: ReturnType<typeof ignore>,
|
|
ignoreInstance: ReturnType<typeof ignore>,
|
|
|
): boolean {
|
|
): boolean {
|
|
|
- // Skip hidden directories if configured to ignore them
|
|
|
|
|
- if (dirName.startsWith(".") && DIRS_TO_IGNORE.includes(".*")) {
|
|
|
|
|
|
|
+ const relativePath = path.relative(basePath, fullDirPath)
|
|
|
|
|
+ const normalizedPath = relativePath.replace(/\\/g, "/")
|
|
|
|
|
+ return ignoreInstance.ignores(normalizedPath) || ignoreInstance.ignores(normalizedPath + "/")
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * Check if a target directory should be included
|
|
|
|
|
+ */
|
|
|
|
|
+function shouldIncludeTargetDirectory(dirName: string): boolean {
|
|
|
|
|
+ // Only apply non-hidden-directory ignore rules to target directories
|
|
|
|
|
+ const nonHiddenIgnorePatterns = DIRS_TO_IGNORE.filter((pattern) => pattern !== ".*")
|
|
|
|
|
+ return !matchesIgnorePattern(dirName, nonHiddenIgnorePatterns)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * Check if a directory inside an explicitly targeted hidden directory should be included
|
|
|
|
|
+ */
|
|
|
|
|
+function shouldIncludeInsideHiddenTarget(dirName: string, fullDirPath: string, context: ScanContext): boolean {
|
|
|
|
|
+ // Only apply the most critical ignore patterns when inside explicit hidden target
|
|
|
|
|
+ if (CRITICAL_IGNORE_PATTERNS.has(dirName)) {
|
|
|
return false
|
|
return false
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Check against explicit ignore patterns
|
|
|
|
|
- if (isDirectoryExplicitlyIgnored(dirName)) {
|
|
|
|
|
|
|
+ // Check against gitignore patterns
|
|
|
|
|
+ return !isIgnoredByGitignore(fullDirPath, context.basePath, context.ignoreInstance)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * Check if a regular directory should be included
|
|
|
|
|
+ */
|
|
|
|
|
+function shouldIncludeRegularDirectory(dirName: string, fullDirPath: string, context: ScanContext): boolean {
|
|
|
|
|
+ // Check against explicit ignore patterns (excluding the ".*" pattern)
|
|
|
|
|
+ const nonHiddenIgnorePatterns = DIRS_TO_IGNORE.filter((pattern) => pattern !== ".*")
|
|
|
|
|
+ if (matchesIgnorePattern(dirName, nonHiddenIgnorePatterns)) {
|
|
|
return false
|
|
return false
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Check against gitignore patterns using the ignore library
|
|
|
|
|
- // Calculate relative path from the base directory
|
|
|
|
|
- const relativePath = path.relative(basePath, fullDirPath)
|
|
|
|
|
- const normalizedPath = relativePath.replace(/\\/g, "/")
|
|
|
|
|
|
|
+ // Check against gitignore patterns
|
|
|
|
|
+ return !isIgnoredByGitignore(fullDirPath, context.basePath, context.ignoreInstance)
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- // Check if the directory is ignored by .gitignore
|
|
|
|
|
- if (ignoreInstance.ignores(normalizedPath) || ignoreInstance.ignores(normalizedPath + "/")) {
|
|
|
|
|
- return false
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * Determine if a directory should be included in results based on filters
|
|
|
|
|
+ */
|
|
|
|
|
+function shouldIncludeDirectory(dirName: string, fullDirPath: string, context: ScanContext): boolean {
|
|
|
|
|
+ // If this is the explicitly targeted directory, allow it even if it's hidden
|
|
|
|
|
+ // This preserves the ability to explicitly target hidden directories like .roo-memory
|
|
|
|
|
+ if (context.isTargetDir) {
|
|
|
|
|
+ return shouldIncludeTargetDirectory(dirName)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // If we're inside an explicitly targeted hidden directory, allow subdirectories
|
|
|
|
|
+ // even if they would normally be filtered out by the ".*" pattern or other ignore rules
|
|
|
|
|
+ if (context.insideExplicitHiddenTarget) {
|
|
|
|
|
+ return shouldIncludeInsideHiddenTarget(dirName, fullDirPath, context)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- return true
|
|
|
|
|
|
|
+ // Regular directory inclusion logic
|
|
|
|
|
+ return shouldIncludeRegularDirectory(dirName, fullDirPath, context)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -390,6 +573,11 @@ function isDirectoryExplicitlyIgnored(dirName: string): boolean {
|
|
|
return true
|
|
return true
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // Skip the ".*" pattern - it's handled specially to allow top-level visibility
|
|
|
|
|
+ if (pattern === ".*") {
|
|
|
|
|
+ continue
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
// Path patterns that contain /
|
|
// Path patterns that contain /
|
|
|
if (pattern.includes("/")) {
|
|
if (pattern.includes("/")) {
|
|
|
const pathParts = pattern.split("/")
|
|
const pathParts = pattern.split("/")
|
|
@@ -432,6 +620,9 @@ function formatAndCombineResults(files: string[], directories: string[], limit:
|
|
|
*/
|
|
*/
|
|
|
async function execRipgrep(rgPath: string, args: string[], limit: number): Promise<string[]> {
|
|
async function execRipgrep(rgPath: string, args: string[], limit: number): Promise<string[]> {
|
|
|
return new Promise((resolve, reject) => {
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
+ // Extract the directory path from args (it's the last argument)
|
|
|
|
|
+ const searchDir = args[args.length - 1]
|
|
|
|
|
+
|
|
|
const rgProcess = childProcess.spawn(rgPath, args)
|
|
const rgProcess = childProcess.spawn(rgPath, args)
|
|
|
let output = ""
|
|
let output = ""
|
|
|
let results: string[] = []
|
|
let results: string[] = []
|
|
@@ -497,6 +688,7 @@ async function execRipgrep(rgPath: string, args: string[], limit: number): Promi
|
|
|
// Process each complete line
|
|
// Process each complete line
|
|
|
for (const line of lines) {
|
|
for (const line of lines) {
|
|
|
if (line.trim() && results.length < limit) {
|
|
if (line.trim() && results.length < limit) {
|
|
|
|
|
+ // Keep the relative path as returned by ripgrep
|
|
|
results.push(line)
|
|
results.push(line)
|
|
|
} else if (results.length >= limit) {
|
|
} else if (results.length >= limit) {
|
|
|
break
|
|
break
|