112 lines
2.9 KiB
TypeScript
112 lines
2.9 KiB
TypeScript
import { App } from "obsidian";
|
|
import {
|
|
MAX_RESULTS,
|
|
truncateLine,
|
|
findLineDetails,
|
|
SearchResult,
|
|
formatResults,
|
|
} from '../search-common';
|
|
|
|
type SearchMatchApi = {
|
|
match: string;
|
|
offset: number;
|
|
};
|
|
|
|
type ResultNoteApi = {
|
|
score: number;
|
|
vault: string;
|
|
path: string;
|
|
basename: string;
|
|
foundWords: string[];
|
|
matches: SearchMatchApi[];
|
|
excerpt: string;
|
|
};
|
|
|
|
type OmnisearchApi = {
|
|
search: (query: string) => Promise<ResultNoteApi[]>;
|
|
// ... other API methods
|
|
};
|
|
|
|
declare global {
|
|
interface Window {
|
|
omnisearch: OmnisearchApi;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Checks if the Omnisearch plugin's API is available.
|
|
* @returns {boolean} True if the API is ready, false otherwise.
|
|
*/
|
|
function isOmnisearchAvailable(): boolean {
|
|
return window.omnisearch && typeof window.omnisearch.search === "function";
|
|
}
|
|
|
|
/**
|
|
* Searches using Omnisearch and builds context for each match.
|
|
* @param query The search query for Omnisearch. Note: Omnisearch does not support full regex.
|
|
* @param app The Obsidian App instance.
|
|
* @returns A formatted string of search results.
|
|
*/
|
|
export async function matchSearchUsingOmnisearch(
|
|
query: string,
|
|
app: App,
|
|
): Promise<string> {
|
|
try {
|
|
if (!isOmnisearchAvailable()) {
|
|
throw new Error(
|
|
"Omnisearch plugin not found or not active. Please install and enable it to use this search feature."
|
|
);
|
|
}
|
|
|
|
// Omnisearch is not a regex engine.
|
|
// The `query` will be treated as a keyword/fuzzy search by the plugin.
|
|
const apiResults = await window.omnisearch.search(query);
|
|
if (!apiResults || apiResults.length === 0) {
|
|
console.error("No results found.");
|
|
return "No results found."
|
|
}
|
|
|
|
const results: SearchResult[] = [];
|
|
|
|
for (const result of apiResults) {
|
|
if (results.length >= MAX_RESULTS) {
|
|
break; // Stop processing new files if we have enough results
|
|
}
|
|
if (!result.matches || result.matches.length === 0) continue;
|
|
|
|
const fileContent = await app.vault.adapter.read(result.path);
|
|
const lines = fileContent.split("\n");
|
|
|
|
for (const match of result.matches) {
|
|
if (results.length >= MAX_RESULTS) {
|
|
break; // Stop processing matches if we have enough results
|
|
}
|
|
|
|
const { lineNumber, columnNumber, lineContent } = findLineDetails(
|
|
lines,
|
|
match.offset
|
|
);
|
|
|
|
if (lineNumber === -1) continue;
|
|
|
|
const searchResult: SearchResult = {
|
|
file: result.path,
|
|
line: lineNumber + 1, // ripgrep is 1-based, so we adjust
|
|
column: columnNumber + 1,
|
|
match: truncateLine(lineContent.trimEnd()),
|
|
beforeContext: lineNumber > 0 ? [truncateLine(lines[lineNumber - 1].trimEnd())] : [],
|
|
afterContext:
|
|
lineNumber < lines.length - 1
|
|
? [truncateLine(lines[lineNumber + 1].trimEnd())]
|
|
: [],
|
|
};
|
|
results.push(searchResult);
|
|
}
|
|
}
|
|
|
|
return formatResults(results, ".\\");
|
|
} catch (error) {
|
|
console.error("Error during Omnisearch processing:", error);
|
|
return "An error occurred during the search.";
|
|
}
|
|
} |