mirror of
https://github.com/abue-ammar/tinycast.git
synced 2026-10-02 08:14:38 +08:00
* Add Spotlight-backed file search * Document file search architecture * Add file search performance baseline * Serialize Spotlight file searches * Cancel file search on click-away * Correct file search documentation counts * Stabilize file search scroll origin * Keep file search disabled by default * Configure file search scopes, ignore patterns and its command File search resolved its policy from hardcoded rules: home plus the cloud roots, minus six baked-in directory names. All three are now the user's. Search Scopes is an editable folder list seeded with home. A configured home root still expands into its visible children plus the cloud roots, since ~/Library can never be an MDQuery scope; every other root is handed to Spotlight verbatim. A cleared list searches nothing rather than falling back. Ignore Patterns are gitignore-flavoured globs run through fnmatch with FNM_CASEFOLD and without FNM_PATHNAME, so **/[Cc]ache/** behaves as written. FileSearchIgnoreList compiles each pattern once into a literal name set, name globs and path globs, so matching stays cheap enough for every candidate. The six shipped rules are compiled in and never persisted, which is what makes them non-removable and lets the list change without losing to a stale copy on disk. Bare * name globs also join the Spotlight expression as exclusions, so ignored files cannot consume the 1,000-candidate cap. Only that shape is pushed: ? and [ are literals to Spotlight and kMDItemPath is not queryable, so path globs stay local. Pushed patterns are escaped and any still carrying a quote is dropped, since an unescaped one would nil MDQueryCreate and break every search until it was deleted. Search Files gains a HotKeyAction of its own, the first built-in command to have one, so its launcher row prints the chord and both settings panes carry the same recorder. Its launcher-visibility checkbox binds to VisibilityStore on the CommandCatalog entry rather than a new setting, so it is the same switch as the one in Settings > Commands. LegacyHotKeyRecords now returns nil for an action that postdates the old scheme instead of inventing a migration key. Editing either list cancels the session: a result found under the old rules must not publish under the new ones. * Configure file search scopes, ignore patterns and its command File search resolved its policy from hardcoded rules: home plus the cloud roots, minus six baked-in directory names. All three are now the user's. Search Scopes is an editable folder list seeded with home. A configured home root still expands into its visible children plus the cloud roots, since ~/Library can never be an MDQuery scope; every other root is handed to Spotlight verbatim. A cleared list searches nothing rather than falling back. Ignore Patterns are gitignore-flavoured globs run through fnmatch with FNM_CASEFOLD and without FNM_PATHNAME, so **/[Cc]ache/** behaves as written. FileSearchIgnoreList compiles each pattern once into a literal name set, name globs and path globs, so matching stays cheap enough for every candidate. The six shipped rules are compiled in and never persisted, which is what makes them non-removable and lets the list change without losing to a stale copy on disk. Bare * name globs also join the Spotlight expression as exclusions, so ignored files cannot consume the 1,000-candidate cap. Only that shape is pushed: ? and [ are literals to Spotlight and kMDItemPath is not queryable, so path globs stay local. Pushed patterns are escaped and any still carrying a quote is dropped, since an unescaped one would nil MDQueryCreate and break every search until it was deleted. Search Files gains a HotKeyAction of its own, the first built-in command to have one, so its launcher row prints the chord and both settings panes carry the same recorder. Its launcher-visibility checkbox binds to VisibilityStore on the CommandCatalog entry rather than a new setting, so it is the same switch as the one in Settings > Commands. LegacyHotKeyRecords now returns nil for an action that postdates the old scheme instead of inventing a migration key. Editing either list cancels the session: a result found under the old rules must not publish under the new ones. --------- Co-authored-by: abue-ammar <iabueammar@gmail.com>
61 lines
2.5 KiB
YAML
61 lines
2.5 KiB
YAML
# SwiftLint is the only code-quality tool here — there is no formatter, deliberately.
|
|
# So this config sticks to rules that catch defects, and stays quiet
|
|
# about style a formatter would otherwise own. See docs/standards.md.
|
|
|
|
included:
|
|
- Tinycast
|
|
- Tests
|
|
|
|
excluded:
|
|
- Tinycast/DesignSystem/Scrolling/EdgeDissolve.swift
|
|
- Tinycast/DesignSystem/Scrolling/ThinScrollbar.swift
|
|
- Tinycast/Features/Emoji/Model/EmojiData.generated.swift
|
|
- Tinycast/Features/Calculator/Model/CurrencyData.generated.swift
|
|
|
|
# Noisy here, or actively wrong for this codebase.
|
|
disabled_rules:
|
|
- todo # tracked in issues, not by the linter
|
|
- trailing_whitespace # cosmetic, and nothing auto-fixes it on save
|
|
- identifier_name # rejects `id`, `dx`, `x` — all correct here
|
|
- type_body_length # a SwiftUI view is legitimately long
|
|
- function_body_length
|
|
- file_length # RootPaletteView is 662 lines by design
|
|
- cyclomatic_complexity # a switch over AppEntry.Kind is not complex
|
|
- nesting # namespace enums are the house style
|
|
- large_tuple
|
|
- function_parameter_count # SwiftUI initialisers
|
|
- multiple_closures_with_trailing_closure # fights SwiftUI
|
|
- opening_brace # ─┐ a formatter's job, and there is no formatter
|
|
- trailing_comma # ─┘ here, so these would just be standing noise
|
|
# `count` is a hit count on LauncherRankingRecord and PaletteRowIndex, not a collection count.
|
|
# This rule rewrites `count == 0` to `isEmpty` on both, which does not compile.
|
|
- empty_count
|
|
|
|
# Each one prevents a real class of defect, not a style preference.
|
|
opt_in_rules:
|
|
- first_where
|
|
- last_where
|
|
- contains_over_filter_count
|
|
- contains_over_first_not_nil
|
|
- optional_data_string_conversion
|
|
- implicitly_unwrapped_optional
|
|
- redundant_nil_coalescing
|
|
- toggle_bool
|
|
- static_over_final_class
|
|
- unneeded_parentheses_in_closure_argument
|
|
- weak_delegate
|
|
|
|
# A `try!` is never acceptable. A `force_cast` sometimes is — the AX and AppKit bridges have four —
|
|
# so it warns rather than blocks.
|
|
force_try: error
|
|
force_cast: warning
|
|
|
|
type_name:
|
|
min_length: 2 # `ID` is the correct name for an Identifiable's ID
|
|
|
|
# Warning-only: length is a judgement call, and a harness header comment is not a defect.
|
|
line_length:
|
|
warning: 130
|
|
ignores_urls: true
|
|
ignores_comments: false
|