Skip to content

Commit 45dec12

Browse files
committed
feat(search): index every setting, not just over half of them
Search covered 131 of the 230 settings the app models. The whole scrollbar family, the per-window title bar options, drag_threshold, progress_bar and both options added in kitty 0.48 could not be found by searching for them, which is the one route someone takes when they do not know which category a setting lives under. All 230 are indexed now. Descriptions come from kitty's own options/definition.py rather than being written from memory, so what search says an option does is what kitty documents it as doing. Four entries named options that do not exist — select_by_word_chars, tab_min_tabs, macos_title_bar_color, macos_quit_when_last_window_closes — each off by a word from the real key. enable_audio_bell was indexed twice, once under Performance, so selecting that result opened a form that does not contain it. A spec now holds the invariant in both directions: every modelled option is searchable, no entry names an option that does not exist, none is filed under a section that does not hold it, and none is duplicated.
1 parent b45cb69 commit 45dec12

3 files changed

Lines changed: 771 additions & 12 deletions

File tree

‎README.md‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,9 @@ Monokai Pro, One Dark and the Confitty palette. 18 presets combine a theme with
6262
functional settings for cases like performance, accessibility, presentation,
6363
remote sessions and streaming.
6464

65-
132 options are indexed for keyboard-navigable fuzzy search.
65+
Every one of the 230 settings is indexed for keyboard-navigable fuzzy search, by
66+
name, description or synonym. A test fails the build if an option is added
67+
without a search entry.
6668

6769
<div align="center">
6870
<img src="./docs/assets/confitty-config-divider.svg" alt="" width="100%">

‎src/search/config-index.spec.ts‎

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { describe, expect, it } from "vitest";
2+
import { DEFAULT_KITTY_CONFIG } from "../models/kitty-defaults";
3+
import type { KittyConfigAST } from "../models/kitty-types";
4+
import { CONFIG_SEARCH_INDEX } from "./config-index";
5+
6+
const SECTIONS = [
7+
"fonts",
8+
"cursor",
9+
"scrollback",
10+
"mouse",
11+
"performance",
12+
"bell",
13+
"window_layout",
14+
"tab_bar",
15+
"colors",
16+
"advanced",
17+
"os_specific",
18+
] as const satisfies readonly (keyof KittyConfigAST)[];
19+
20+
/** Every option the app models, mapped to the section it lives in. */
21+
const MODELLED = new Map<string, string>(
22+
SECTIONS.flatMap((section) =>
23+
Object.keys(DEFAULT_KITTY_CONFIG[section]).map(
24+
(key) => [key, section] as const,
25+
),
26+
),
27+
);
28+
29+
describe("CONFIG_SEARCH_INDEX", () => {
30+
it("indexes every modelled option", () => {
31+
const indexed = new Set(CONFIG_SEARCH_INDEX.map((item) => item.key));
32+
const missing = [...MODELLED.keys()].filter((key) => !indexed.has(key));
33+
34+
expect(missing).toEqual([]);
35+
});
36+
37+
it("has no entry for an option that does not exist", () => {
38+
const ghosts = CONFIG_SEARCH_INDEX.filter(
39+
(item) => !MODELLED.has(item.key),
40+
).map((item) => item.key);
41+
42+
expect(ghosts).toEqual([]);
43+
});
44+
45+
it("files every entry under the section that actually holds it", () => {
46+
// Selecting a result navigates by category, so a wrong one lands the user
47+
// in a form that does not contain the setting they searched for.
48+
const misfiled = CONFIG_SEARCH_INDEX.filter(
49+
(item) => MODELLED.get(item.key) !== item.category,
50+
).map((item) => `${item.key}: indexed=${item.category}`);
51+
52+
expect(misfiled).toEqual([]);
53+
});
54+
55+
it("has no duplicate keys", () => {
56+
const seen = new Set<string>();
57+
const duplicates = CONFIG_SEARCH_INDEX.filter(
58+
(item) => seen.size === seen.add(item.key).size,
59+
).map((item) => item.key);
60+
61+
expect(duplicates).toEqual([]);
62+
});
63+
64+
it("gives every entry a label and a description", () => {
65+
const incomplete = CONFIG_SEARCH_INDEX.filter(
66+
(item) => !item.label?.trim() || !item.description?.trim(),
67+
).map((item) => item.key);
68+
69+
expect(incomplete).toEqual([]);
70+
});
71+
});

0 commit comments

Comments
 (0)