This commit is contained in:
YangLe 2026-03-28 19:05:47 +00:00 committed by GitHub
commit 1d48ab93ec
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -33,6 +33,7 @@ import {
import { EmbeddedView, isEmebeddedLeaf, spawnLeafView } from "./leafView";
import { around } from "monkey-around";
import { debounce } from "obsidian";
import { EditorView } from "@codemirror/view";
type sortOrder =
| "alphabetical"
@ -92,6 +93,40 @@ const DEFAULT_SETTINGS: FloatSearchSettings = {
cmdkQuickCreateTitleFormat: "YYYYMMDDHHmmss",
};
/**
* Scroll matched text to the top of the main editor
* @param app - Obsidian app instance
* @param matchOffset - Character offset of the match
*/
function scrollMatchToTop(app: App, matchOffset: number): void {
setTimeout(() => {
const leaf = app.workspace.getMostRecentLeaf();
if (!leaf) return;
const view = leaf.view;
if (!view) return;
const editor = (view as any).editor;
if (!editor) return;
const cm = (editor as any).cm as EditorView;
if (!cm) {
// Fallback to Obsidian built-in API (scrolls to center)
const pos = editor.offsetToPos(matchOffset);
editor.scrollIntoView({ from: pos, to: pos });
return;
}
// Use CodeMirror 6 API to scroll to top
cm.dispatch({
effects: EditorView.scrollIntoView(matchOffset, {
y: "start",
yMargin: 30,
}),
});
}, 150);
}
const allViews: viewType[] = [
{
type: "modal",
@ -285,7 +320,8 @@ export default class FloatSearchPlugin extends Plugin {
initModal(
state: searchState,
stateSave: boolean = false,
clearQuery: boolean = false
clearQuery: boolean = false,
fromURI: boolean = false
) {
if (this.modal) {
this.modal.close();
@ -306,6 +342,13 @@ export default class FloatSearchPlugin extends Plugin {
{ ...state, query: clearQuery ? "" : state.query }
);
this.modal.open();
// 如果是通过URI协议打开且有查询内容删除"建议容器"
if (fromURI && state.query) {
setTimeout(() => {
document.querySelector('.suggestion-container')?.remove();
}, 10);
}
}
patchWorkspace() {
@ -917,7 +960,8 @@ export default class FloatSearchPlugin extends Plugin {
current: false,
},
true,
false
false,
true
);
} else {
await initSearchViewWithLeaf(
@ -1798,7 +1842,7 @@ class FloatSearchModal extends Modal {
initContent() {
const { contentEl } = this;
contentEl.onclick = (e) => {
contentEl.onclick = async (e) => {
const resultElement = contentEl.getElementsByClassName(
"search-results-children"
)[0];
@ -1821,7 +1865,54 @@ class FloatSearchModal extends Modal {
break;
}
if (targetElement.classList.contains("tree-item")) {
// Get file info before closing
const fileInnerEl = targetElement?.getElementsByClassName(
"tree-item-inner"
)[0] as HTMLElement;
const innerText = fileInnerEl.innerText;
const file = this.plugin.app.metadataCache.getFirstLinkpathDest(
innerText,
""
);
// Get match info
const currentView = this.searchLeaf.view as SearchView;
const item = currentView.dom.resultDomLookup.get(file);
// Try to get match offset - find the specific clicked match
let matchOffset: number | undefined = undefined;
// Get the clicked element and find the match element
const clickedEl = e.target as HTMLElement;
// Try to get the actual match element (not file element)
const matchEl = clickedEl.closest(".search-result-file-match");
if (matchEl && item?.vChildren?.children) {
// Get index among siblings - filter to only match elements
const parent = matchEl.parentElement;
if (parent) {
// Filter to only .search-result-file-match elements
const siblings = Array.from(parent.children).filter(
(el) => el.classList.contains("search-result-file-match")
);
const clickedIdx = siblings.indexOf(matchEl);
if (clickedIdx >= 0 && clickedIdx < item.vChildren.children.length) {
const child = item.vChildren.children[clickedIdx];
const childMatch = child?.matches?.[0];
if (Array.isArray(childMatch)) {
matchOffset = childMatch[0];
} else if (typeof childMatch === "number") {
matchOffset = childMatch;
}
}
}
}
this.close();
// Scroll to top if we have a match offset
if (matchOffset !== undefined) {
scrollMatchToTop(this.plugin.app, matchOffset);
}
break;
}
targetElement = targetElement.parentElement;