From d2f44c18761f4f7c87fc928f23156189c70f3cdb Mon Sep 17 00:00:00 2001 From: le Date: Sun, 16 Nov 2025 02:28:27 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20=E7=94=A8=20obsidian://fs=3Fquery=3D?= =?UTF-8?q?{query}=20=E6=90=9C=E7=B4=A2=E6=97=B6=EF=BC=8C=E6=90=9C?= =?UTF-8?q?=E7=B4=A2=E7=BB=93=E6=9E=9C=E4=BC=9A=E8=A2=AB"=E6=90=9C?= =?UTF-8?q?=E7=B4=A2=E5=BB=BA=E8=AE=AE"=E9=81=AE=E6=8C=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/floatSearchIndex.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/floatSearchIndex.ts b/src/floatSearchIndex.ts index 4799436..5e1cb73 100644 --- a/src/floatSearchIndex.ts +++ b/src/floatSearchIndex.ts @@ -223,7 +223,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(); @@ -244,6 +245,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() { @@ -855,7 +863,8 @@ export default class FloatSearchPlugin extends Plugin { current: false, }, true, - false + false, + true ); } else { await initSearchViewWithLeaf( From a57a7bfff2e0c6ace0dae64b832307d14cb0458f Mon Sep 17 00:00:00 2001 From: le Date: Mon, 23 Feb 2026 02:23:11 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E5=B0=86=E6=90=9C=E7=B4=A2=E7=9A=84?= =?UTF-8?q?=E9=AB=98=E4=BA=AE=E6=96=87=E5=AD=97=E6=BB=9A=E5=8A=A8=E5=88=B0?= =?UTF-8?q?=E4=B8=BB=E7=BC=96=E8=BE=91=E5=99=A8=E9=A1=B6=E9=83=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/floatSearchIndex.ts | 84 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 83 insertions(+), 1 deletion(-) diff --git a/src/floatSearchIndex.ts b/src/floatSearchIndex.ts index 5e1cb73..3baa20f 100644 --- a/src/floatSearchIndex.ts +++ b/src/floatSearchIndex.ts @@ -27,6 +27,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" @@ -74,6 +75,40 @@ const DEFAULT_SETTINGS: FloatSearchSettings = { defaultViewType: "modal", }; +/** + * 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", @@ -1600,7 +1635,7 @@ class FloatSearchModal extends Modal { initContent() { const { contentEl } = this; - contentEl.onclick = (e) => { + contentEl.onclick = async (e) => { const resultElement = contentEl.getElementsByClassName( "search-results-children" )[0]; @@ -1623,7 +1658,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;