![[chappy-log.webp|cover-picture]] ## 経緯 <div class="link-card-v2"> <div class="link-card-v2-site"> <img class="link-card-v2-site-icon" src="https://github.githubassets.com/favicons/favicon.svg" /> <span class="link-card-v2-site-name">GitHub</span> </div> <div class="link-card-v2-title"> [FR] add setting search · Issue #299 · tadashi-aikawa/obsidian-another-quick-switcher </div> <div class="link-card-v2-content"> Hello, Feature request in screenshot below: </div> <img class="link-card-v2-image" src="https://opengraph.githubassets.com/3cd2ee116c35935f105aacc1ee22a7f0c4709e02e0211e503ccf419658c46024/tadashi-aikawa/obsidian-another-quick-switcher/issues/299" /> <a href="https://github.com/tadashi-aikawa/obsidian-another-quick-switcher/issues/299"></a> </div> ## ログ > [!right-bubble] ![[minerva-face-right.webp]] > 設定画面の右上に全体を検索できる検索ボックスを追加したい。 > > 今はGroupごとに検索しているけどそれの全体版。設定項目とその親にあたる項目(見出しやネスト)も表示する。 > [!left-bubble] ![[chappy.webp]] > 了解です。まず実装方針を共有します。承諾いただいてからコードを変更します。 > > プラン > > - src/settings.ts に設定ヘッダー(左タイトル/右検索入力)を追加し、検索クエリをクラスプロパティで保持して再描画時も維持する > - 設定画面全体を対象にしたフィルタ処理を src/composables/settings/useGlobalSettingFilter.ts に実装し、設定項目の「名前+説明」を検索対象にして、ヒットした項目とその親(見出し・ネスト元) > を表示する > - 空になった「コマンド/ホットキー」などのコンテナは自動で非表示にする > - 右上検索ボックスの見た目を styles.css に追加 > > 確認したい点 > > - グローバル検索時、折りたたみ中の「Search commands」「Hotkeys in dialog」も一時的に展開して検索対象にしますか?(検索が空になったら元の折りたたみ状態に戻す想定) > > この方針で進めてよければ承諾お願いします。 > [!right-bubble] ![[minerva-face-right.webp]] > > - グローバル検索時、折りたたみ中の「Search commands」「Hotkeys in dialog」も一時的に展開して検索対象にしますか?(検索が空になったら元の折りたたみ状態に戻す想定) > > ヒットした場合のみ展開するのであればお願いします。 > > 既存で addFilterableSetting を呼び出している場所はそのまま変更しないで大丈夫ですか? (addFilterableSettingの実装変更だけで対応できるか?) > [!left-bubble] ![[chappy.webp]] > 了解しました。 > 結論からいうと、addFilterableSetting の実装変更だけでは 全体検索は足りません。理由は以下です。 > > - 全設定の多くが addFilterableSetting を使っておらず(new Setting 直書き)、そこは検索対象に入らない > - 見出しや親要素(h3 やネスト親)を表示制御するには、DOM階層を辿る必要があるため、addFilterableSetting 単体ではカバーできない > > ただし 既存の addFilterableSetting の呼び出しは変更しなくてOK です。 > グローバル検索は別ロジックで DOM 全体を走査して対応します。 > そのため「呼び出し側はそのまま」の要望は満たせます。 > > 更新プラン(承諾前提) > > - src/settings.ts に右上検索ボックスを追加し、クエリをクラスプロパティとして保持(再描画でも入力保持) > - グローバル検索ロジックを新規ユーティリティ(例: src/composables/settings/useGlobalSettingFilter.ts)で実装 > - .setting-item と見出し要素を対象 > - 検索対象は「項目名 + 説明 + 親見出し」 > - ヒットした設定項目とその親(見出し/ネスト親)を表示 > - ヒット無しのコンテナは非表示 > - 「Search commands」「Hotkeys in dialog」は、検索クエリがある時は内部を描画し、 > **ヒットがある場合のみ表示(=展開)**する挙動にする > - 検索が空になったら元の折りたたみ状態に戻る > > この方針で実装してよければ承諾お願いします。 > [!right-bubble] ![[minerva-face-right.webp]] > OK > [!left-bubble] ![[chappy.webp]] > 右上の全体検索ボックスを追加し、全設定を対象にフィルタしつつ「見出し/ネスト親」を表示するようにしました。検索中は「Search commands」「Hotkeys in dialog」を一時的に展開し、ヒットした場合のみ表示されます。 > > - src/settings.ts 右上検索UIを追加、クエリ保持と再描画時のフォーカス維持、検索中のみ強制展開の分岐を追加 > - src/composables/settings/useGlobalSettingFilter.ts 全体検索のフィルタ処理(項目名/説明/入力値を検索対象にし、親見出し・ネスト親を可視化、空コンテナは非表示) > - styles.css ヘッダーと検索入力のレイアウト、モバイル時の縦並び調整 > > テストは実行していません。 > > 次のステップ案 > > 1. Obsidian の設定画面で全体検索の挙動と表示(親/見出しの表示)を確認 > 2. 必要なら bun run build でビルド確認 > [!right-bubble] ![[minerva-face-right.webp]] > if (normalize(getSettingSearchText(item)).includes(normalizedQuery)) { > > の部分について normalizedQuery をwhitespaceで分割してすべてにマッチするケースをフィルタリングしたい。 > > すでにstrings.tsなどにそのような関数があったらそれを利用できるかも? > [!left-bubble] ![[chappy.webp]] > あります。src/utils/strings.ts に smartWhitespaceSplit があり、空白区切り+ダブルクォート対応の分割ができます。これを使って 全トークン一致 にできます。 > > プラン > > - src/composables/settings/useGlobalSettingFilter.ts で smartWhitespaceSplit を使い、クエリをトークン化 > - 検索条件を「各トークンが検索対象文字列に含まれる」(every) に変更 > - 既存の呼び出し側は変更しない > > この方針で進めてよければ承諾お願いします。 > [!right-bubble] ![[minerva-face-right.webp]] > OKです。それなら今回実装したnormalizeはそもそも不要かも? > [!left-bubble] ![[chappy.webp]] > 結論として、現在の normalize ヘルパーは不要にできます。 > ただし 小文字化・trim 自体は必要なので、そこは直接書く形に変更します。 > > 対応案 > > - smartWhitespaceSplit でクエリをトークン化 > - queryTokens と searchText をそれぞれ toLowerCase() で揃えて every 判定 > - その結果、normalize ヘルパーは削除可能 > > この方針で修正してよければ承諾お願いします。 > [!right-bubble] ![[minerva-face-right.webp]] > ``` > describe.each<{ text: string; expected: string[] }>` > text | expected > ${"aa"} | ${["aa"]} > ${"aa "} | ${["aa"]} > ${"aa bb"} | ${["aa", "bb"]} > ${" aa bb"} | ${["aa", "bb"]} > ${"aa bb "} | ${["aa", "bb"]} > ${" aa bb "} | ${["aa", "bb"]} > ${"aa bb cc"} | ${["aa", "bb", "cc"]} > ${" aa bb cc"} | ${["aa", "bb", "cc"]} > ${" aa bb cc "} | ${["aa", "bb", "cc"]} > ${'"aa bb" cc'} | ${["aa bb", "cc"]} > ${'aa "bb cc"'} | ${["aa", "bb cc"]} > ${'"aa bb cc"'} | ${["aa bb cc"]} > ${'"aa bb" "bb cc"'} | ${["aa bb", "bb cc"]} > ${'"aa bb" dd "bb cc"'} | ${["aa bb", "dd", "bb cc"]} > ${'c"aa bb"d'} | ${["caa bbd"]} > ${'search \\"quote'} | ${["search", '"quote']} > ${'search \\" test'} | ${["search", '"', "test"]} > ${'\\"hello world\\"'} | ${['"hello', 'world"']} > ${'pre \\"mid\\" post'} | ${["pre", '"mid"', "post"]} > ${'aa \\"bb cc\\" dd'} | ${["aa", '"bb', 'cc"', "dd"]} > ${'\\"'} | ${['"']} > ${'\\"\\"'} | ${['""']} > ${'test \\"'} | ${["test", '"']} > `("smartWhitespaceSplit", ({ text, expected }) => { > test(`smartWhitespaceSplit(${text}) = ${expected}`, () => { > expect(smartWhitespaceSplit(text)).toStrictEqual(expected); > }); > }); > ``` > > のテストコード見るとtrimも不要では? > [!left-bubble] ![[chappy.webp]] > 結論:trim は不要にできます。 > smartWhitespaceSplit は先頭/末尾の空白を空要素として捨てるので、トリム不要でトークン化できます。 > その代わり 「検索が有効か」の判定は trim ではなく tokens.length を使うのが筋です。 > > 変更方針 > > - smartWhitespaceSplit の結果 tokens が空なら「検索なし」 > - マッチ判定は tokens.every((t) => searchTextLower.includes(tLower)) > - normalize ヘルパーは削除してOK(小文字化は各所で行う) > > この方向で修正してよければ承諾お願いします。 > [!right-bubble] ![[minerva-face-right.webp]] > ok > [!left-bubble] ![[chappy.webp]] > trim をやめて smartWhitespaceSplit に切り替え、トークン全一致に更新しました。 > これで入力先頭/末尾スペースは自然に無視されます。 > > 変更点 > > - src/composables/settings/useGlobalSettingFilter.ts で smartWhitespaceSplit を利用し、tokens.length で検索有効判定 > - normalize ヘルパーは削除、toLowerCase() のみに統一 > > 次のステップ案 > > 1. 設定画面で "aa bb" などの複数語検索が AND 条件で効くことを確認 > [!right-bubble] ![[minerva-face-right.webp]] > 親がヒットした場合は子をすべて表示させることはできますか? > > - 見出し『Appearance』がヒットしたら、配下の9設定をすべて表示 > - 『Header dialog』がヒットしたら、配下のホットキー設定をすべて表示 > > のように。 > [!left-bubble] ![[chappy.webp]] > はい、可能です。実装変更になるのでプランを提示します。 > > プラン > > - src/composables/settings/useGlobalSettingFilter.ts のフィルタロジックを拡張 > - 見出し(h3)がヒットした場合、その見出しから次の h3 までの setting-item をすべて表示 > - Hotkeys の各ダイアログ見出し(.setting-item-heading)がヒットした場合、その見出し以降の同じコンテナ内の setting-item をすべて表示 > > この方針で進めてよければ承諾お願いします。 > [!right-bubble] ![[minerva-face-right.webp]] > Search commands配下も同様にお願いします。認識あっていれば進めてください。 > [!left-bubble] ![[chappy.webp]] > 対応しました。 > 見出し(h3)やダイアログ/コマンド見出し(.setting-item-heading)がヒットした場合、その配下の設定項目をすべて表示するように拡張しています。 > > 変更点 > > - src/composables/settings/useGlobalSettingFilter.ts で「親ヒット時に子を全表示」ロジックを追加 > - h3 見出しヒット → 次の h3 までの全 setting-item を表示 > - Search commands / Hotkeys の見出しヒット → そのコンテナ内の全 setting-item を表示 > > 次のステップ案 > > 1. 設定画面で「Appearance」「Header dialog」「Search commands」などの見出し検索が配下全表示になることを確認 > [!right-bubble] ![[minerva-face-right.webp]] > Hotkeys in dialog と Search commands の項目はヒットすると中身が展開されますが、中身がヒットしていなければ展開しない(直前の展開状態そのまま)にしてください。 > [!left-bubble] ![[chappy.webp]] > 了解です。実装変更になるので、先に方針を共有します。 > > プラン > > - src/composables/settings/useGlobalSettingFilter.ts の「見出しヒット時に子を全表示」ロジックを調整 > - Hotkeys in dialog と Search commands の h3 見出し は “自動で全展開しない” > - .setting-item-heading(各コマンド/各ダイアログ見出し)がヒットしても 中身を全表示しない > - 結果として > - 中身にヒットが無ければ 展開しない(直前の展開状態を維持) > - 中身にヒットがあれば、そのヒット分だけ表示(自動で全展開はしない) > > この方針で進めてよければ承諾お願いします。 > [!right-bubble] ![[minerva-face-right.webp]] > ok > [!left-bubble] ![[chappy.webp]] > 「Hotkeys in dialog」「Search commands」の h3 見出しヒット時は配下を自動展開しない ように変更しました。 > (内容がヒットしない限り、展開は変えず、フィルタだけ適用されます) > > 変更点 > > - src/composables/settings/useGlobalSettingFilter.ts > - 上記2つの見出しだけは「見出しヒット時の全展開」をスキップする判定を追加 > > 次のステップ案 > > 1. Hotkeys in dialog / Search commands で検索しても中身が出ないこと > 2. 中身の項目がヒットした場合は従来通り表示されることを確認 ``` 変更点を戻す ``` > [!right-bubble] ![[minerva-face-right.webp]] > `another-quick-switcher__settings__warning` クラスのwarning要素について、usePopover を使って設定名の横にwarningアイコン表示のポップアップにして。 > [!left-bubble] ![[chappy.webp]] > 了解です。実装変更なので、先にプラン共有します。 > > プラン > > - src/settings.ts の warning 表示(another-quick-switcher__settings__warning)を削除し、該当する設定名の横に usePopover の警告アイコンを追加 > - 「Normalize accents/diacritics」設定名の横に警告ポップオーバー > - 「🔍 Grep」見出し(または該当設定名)横に警告ポップオーバー > - styles.css に警告アイコン用の色・余白のスタイルを追加(既存のポップオーバーアイコンに警告用クラスを追加) > > この方針で進めてよければ承諾お願いします。 > [!right-bubble] ![[minerva-face-right.webp]] > ok > [!left-bubble] ![[chappy.webp]] > 警告表示を usePopover のアイコンに置き換えました。 > 「Normalize accents/diacritics」は有効時のみアイコン表示、「Ripgrep command」は常時アイコン表示です。 > > 変更点 > > - src/settings.ts > - createWarningName を追加し、設定名の横に警告アイコン+ポップオーバーを生成 > - 既存の `.another-quick-switcher__settings__warning` の div を削除して置き換え > - styles.css > - `.another-quick-switcher__settings__warning-icon` を追加(色/余白) > > 次のステップ案 > > 1. 設定画面で「Normalize accents/diacritics」と「Ripgrep command」の警告アイコン表示を確認 > [!right-bubble] ![[minerva-face-right.webp]] > 1. 設定画面で「Normalize accents/diacritics」と「Ripgrep command」の警告アイコン表示を確認 > > これお願いしたいです。既存のiマークのアイコンはどうやってましたっけ? > [!left-bubble] ![[chappy.webp]] > 今の環境では Obsidian のGUIを開いて確認できないため、表示確認はお願いできますか。 > 確認ポイントは「⚠️アイコンが設定名の右に出る」「ホバー/クリックでポップアップが出る」の2点です。 > > 既存の i マークは usePopover で作っていて、ここです: > > - src/settings.ts の Hotkeys セクション(addHotKeysInDialogSettings) > - ボタン生成:createEl("button", { cls: "another-quick-switcher__settings__popup__icon", text: "i", ... }) > > 必要なら、そのまま i と同じクラスを使って警告アイコンも揃えることもできます。 > [!right-bubble] ![[minerva-face-right.webp]] > 確認ポイントは「⚠️アイコンが設定名の右に出る」「ホバー/クリックでポップアップが出る」の2点です。 > > これでOKです。またポップアップ内の文字色はwarning用の文字色にしてください。style.cssに良い定義があれば流用して。 > [!left-bubble] ![[chappy.webp]] > 了解です。実装変更になるので先にプラン提示します。 > > プラン > > - src/settings.ts の警告ポップアップ内容に `another-quick-switcher__settings__warning` クラスを付与して色を流用 > - styles.css に「ポップアップ内では text-align を左寄せに上書き」のルールを追加(色は既存の warning 定義を使う) > > この方針で進めてよければ承諾お願いします。 > [!right-bubble] ![[minerva-face-right.webp]] > ok > [!left-bubble] ![[chappy.webp]] > ポップアップ内の文字色を警告色に統一しつつ、左右寄せは左に揃えるようにしました。 > > 変更点 > > - src/settings.ts > - 警告ポップアップの内容に `another-quick-switcher__settings__warning` を付与 > - styles.css > - ポップアップ内の warning だけ text-align: left に上書き > > 次のステップ案 > > 1. 設定画面で警告ポップアップの文字色が darkorange になっていることを確認 > [!right-bubble] ![[minerva-face-right.webp]] > 文字色はあっていますが、アイコンがiのままですね。warning用のものになっていない。 > [!left-bubble] ![[chappy.webp]] > アイコンが i に見える問題は、警告アイコンの文字をより明確な ⚠ に変更すれば解消できます。 > (! だと丸枠の中で i に見えやすいので) > > プラン > > - src/settings.ts の警告アイコン文字を ⚠ に変更 > - 必要なら styles.css の `.another-quick-switcher__settings__warning-icon` に font-weight などを追加して視認性アップ > > この内容で進めてよければ承諾お願いします。 > [!right-bubble] ![[minerva-face-right.webp]] > お願いします。 > [!left-bubble] ![[chappy.webp]] > 警告アイコンを ⚠ に変更しました。これで i に見える問題は解消されるはずです。 > > 次のステップ案 > > 1. 設定画面で警告アイコンが ⚠ に見えることを確認 > [!right-bubble] ![[minerva-face-right.webp]] > [Image #1] アイコンの色はwarningの色にしてほしい。周囲の丸枠は外すか色をwarningに揃える。 > [!left-bubble] ![[chappy.webp]] > 了解です。実装変更になるので先にプランを共有します。 > > プラン > > - styles.css により強いセレクタ(`.another-quick-switcher__settings__popup__icon.another-quick-switcher__settings__warning-icon`)を追加して、色と枠を警告色に固定 > - 枠は「外す」か「警告色に合わせる」のどちらにするか、指定に合わせて調整 > > 枠は「外す」で進めてよいですか?それとも「警告色に合わせる」が良いですか? > [!right-bubble] ![[minerva-face-right.webp]] > 枠は外してください。 > [!left-bubble] ![[chappy.webp]] > 警告アイコンの枠を外し、色を警告色に固定しました。 > セレクタを強めにして、他の .popup__icon の色指定より優先されるようにしています。 > > 次のステップ案 > > 1. 設定画面で警告アイコンの枠が消え、色が警告色になっていることを確認 ``` 警告アイコンについては自分で調整。 ```