![[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. 設定画面で警告アイコンの枠が消え、色が警告色になっていることを確認
```
警告アイコンについては自分で調整。
```