feat: Enhance file search with core plugin and Omnisearch integration

- Introduces a new match_search_files tool for fuzzy/keyword search, integrating with Obsidian's core search plugin and updating Omnisearch integration for improved file search capabilities.
- Adds settings for selecting search backends (core plugin, Omnisearch, ripgrep) for both regex and match searches.
- Updates language files, prompts, and types to support the new functionality.
- Restructures search-related files for better organization.
This commit is contained in:
travertexg
2025-06-09 15:15:16 +00:00
parent 350a49cef9
commit 9984527e85
18 changed files with 326 additions and 36 deletions

View File

@@ -29,8 +29,10 @@ import {
LLMBaseUrlNotSetException,
LLMModelNotSetException,
} from '../../core/llm/exception'
import { regexSearchFilesWithRipgrep } from '../../core/regex/ripgrep-index'
import { regexSearchFilesWithOmnisearch } from '../../core/regex/omnisearch-index'
import { searchFilesWithCorePlugin } from '../../core/search/match/coreplugin-match'
import { searchFilesWithOmnisearch } from '../../core/search/match/omnisearch-match'
import { regexSearchFilesWithRipgrep } from '../../core/search/regex/ripgrep-regex'
import { regexSearchFilesWithCorePlugin } from '../../core/search/regex/coreplugin-regex'
import { useChatHistory } from '../../hooks/use-chat-history'
import { useCustomModes } from '../../hooks/use-custom-mode'
import { t } from '../../lang/helpers'
@@ -608,15 +610,37 @@ const Chat = forwardRef<ChatRef, ChatProps>((props, ref) => {
mentionables: [],
}
}
} else if (toolArgs.type === 'regex_search_files') {
// @ts-expect-error Obsidian API type mismatch
const searchBackend = settings.regexSearchBackend
const baseVaultPath = String(app.vault.adapter.getBasePath())
const absolutePath = path.join(baseVaultPath, toolArgs.filepath)
} else if (toolArgs.type === 'match_search_files') {
const searchBackend = settings.matchSearchBackend
let results: string;
if (searchBackend === 'omnisearch') {
results = await regexSearchFilesWithOmnisearch(absolutePath, toolArgs.regex, app)
results = await searchFilesWithOmnisearch(toolArgs.query, app)
} else {
results = await searchFilesWithCorePlugin(toolArgs.query, app)
}
const formattedContent = `[match_search_files for '${toolArgs.filepath}'] Result:\n${results}\n`;
return {
type: 'match_search_files',
applyMsgId,
applyStatus: ApplyStatus.Applied,
returnMsg: {
role: 'user',
applyStatus: ApplyStatus.Idle,
content: null,
promptContent: formattedContent,
id: uuidv4(),
mentionables: [],
}
}
} else if (toolArgs.type === 'regex_search_files') {
const searchBackend = settings.regexSearchBackend
let results: string;
if (searchBackend === 'coreplugin') {
results = await regexSearchFilesWithCorePlugin(toolArgs.regex, app)
} else {
// @ts-expect-error Obsidian API type mismatch
const baseVaultPath = String(app.vault.adapter.getBasePath())
const absolutePath = path.join(baseVaultPath, toolArgs.filepath)
const ripgrepPath = settings.ripgrepPath
results = await regexSearchFilesWithRipgrep(absolutePath, toolArgs.regex, ripgrepPath)
}

View File

@@ -0,0 +1,52 @@
import { FileSearch } from 'lucide-react'
import React from 'react'
import { useApp } from "../../../contexts/AppContext"
import { t } from '../../../lang/helpers'
import { ApplyStatus, MatchSearchFilesToolArgs } from "../../../types/apply"
import { openMarkdownFile } from "../../../utils/obsidian"
export default function MarkdownMatchSearchFilesBlock({
applyStatus,
onApply,
path,
query,
finish
}: {
applyStatus: ApplyStatus
onApply: (args: MatchSearchFilesToolArgs) => void
path: string,
query: string,
finish: boolean
}) {
const app = useApp()
const handleClick = () => {
openMarkdownFile(app, path)
}
React.useEffect(() => {
if (finish && applyStatus === ApplyStatus.Idle) {
onApply({
type: 'match_search_files',
filepath: path,
query: query,
file_pattern: ".md",
})
}
}, [finish])
return (
<div
className={`infio-chat-code-block ${path ? 'has-filename' : ''}`}
onClick={handleClick}
>
<div className={'infio-chat-code-block-header'}>
<div className={'infio-chat-code-block-header-filename'}>
<FileSearch size={14} className="infio-chat-code-block-header-icon" />
<span>{t('chat.reactMarkdown.matchSearchInPath').replace('{query}', query).replace('{path}', path)}</span>
</div>
</div>
</div>
)
}

View File

@@ -13,6 +13,7 @@ import MarkdownFetchUrlsContentBlock from './Markdown/MarkdownFetchUrlsContentBl
import MarkdownListFilesBlock from './Markdown/MarkdownListFilesBlock'
import MarkdownReadFileBlock from './Markdown/MarkdownReadFileBlock'
import MarkdownReasoningBlock from './Markdown/MarkdownReasoningBlock'
import MarkdownMatchSearchFilesBlock from './Markdown/MarkdownMatchSearchFilesBlock'
import MarkdownRegexSearchFilesBlock from './Markdown/MarkdownRegexSearchFilesBlock'
import MarkdownSearchAndReplace from './Markdown/MarkdownSearchAndReplace'
import MarkdownSearchWebBlock from './Markdown/MarkdownSearchWebBlock'
@@ -117,6 +118,15 @@ function ReactMarkdown({
recursive={block.recursive}
finish={block.finish}
/>
) : block.type === 'match_search_files' ? (
<MarkdownMatchSearchFilesBlock
key={"match-search-files-" + index}
applyStatus={applyStatus}
onApply={onApply}
path={block.path}
query={block.query}
finish={block.finish}
/>
) : block.type === 'regex_search_files' ? (
<MarkdownRegexSearchFilesBlock
key={"regex-search-files-" + index}