mirror of
https://github.com/bitsycore/Allofit.git
synced 2026-10-07 05:17:26 +00:00
Security - Elevated copies: root only reads the original; the copy is written by the user (sudo -u tee), so root never chowns / chmods a user-controlled path. Staging folder forced to 0700. - Service logs moved from fixed /tmp names to /Library/Logs/Allofit (root-owned) and ~/Library/Logs/Allofit; Diagnostics reveals instead of opening the log. - Index files are owner-only (0600; the root daemon's belongs to the installing user), set on the temp file before an atomic rename. - Root install passes the plist inline (base64, plutil -lint) instead of a user-writable temp file; the binary comes from Bundle.main. - Cache loader caps and checks the declared payload size; each save uses its own temp file. - Release action pinned to a commit; non-system LC_RPATHs stripped. Correctness - Move to Trash removes the files from the index (the watcher ignores the app's own operations) and registers Undo (Put Back); trashed folders are matched with the original URLs; failures are shown. - The saved event id stays below pending subtree walks (GUI and service). - Roots / exclusions changes restart the watcher from the snapshot's id. - Case-only renames no longer leave a ghost entry. - Service mode is saved only after a successful install; a saved but missing service falls back to the in-process indexer. Performance - New folders are merged without the O(n) removal pass. - Size / date sorts use a compact key array (539 -> 47 ms for 630k). - Selection, preview and actions use the selected records directly. - Service saves at most every 15 s; reader reloads pause while hidden and are deferred instead of dropped; window close saves only when dirty. Usability - Results appear during the first index; empty-list explanations. - Down arrow moves to the results, Up on the first row back; history on Up / Option-Up / Option-Down. - Search syntax popover and Help menu; shortcuts shown in the context menu; confirmations for Clear Cache and Uninstall; privacy usage strings; Group Containers excluded by default; wording, VoiceOver labels, plural.
54 lines
2.0 KiB
Swift
54 lines
2.0 KiB
Swift
import SwiftUI
|
|
|
|
// SyntaxHelpView is the search syntax cheat sheet shown by the "?" button
|
|
// next to the search field and by Help > Search Syntax.
|
|
struct SyntaxHelpView: View {
|
|
|
|
// one example query and what it matches
|
|
private struct Example: Identifiable {
|
|
let query: String
|
|
let meaning: String
|
|
var id: String { query }
|
|
}
|
|
|
|
// the rows of the cheat sheet, same order as the README
|
|
private let kExamples: [Example] = [
|
|
Example(query: "report", meaning: "names containing \"report\" (case and accents ignored)"),
|
|
Example(query: "annual report", meaning: "names containing both words (AND)"),
|
|
Example(query: "*.png | *.jpg", meaning: "either one (OR, binds tighter than AND)"),
|
|
Example(query: "report !draft", meaning: "without \"draft\" (NOT)"),
|
|
Example(query: "\"my file\"", meaning: "quotes keep spaces in one term"),
|
|
Example(query: "Start*.pdf", meaning: "* any characters, the whole name must match"),
|
|
Example(query: "IMG_????.heic", meaning: "? exactly one character"),
|
|
Example(query: "ext:pdf;docx", meaning: "by extension"),
|
|
Example(query: "file: folder:", meaning: "files or folders only (also as a prefix: folder:build)"),
|
|
Example(query: "src/main", meaning: "a term with / matches the full path"),
|
|
Example(query: "\"photos/**/\" *.heic", meaning: "** spans folders, * stays in one; trailing / = inside"),
|
|
]
|
|
|
|
var body: some View {
|
|
VStack(alignment: .leading, spacing: 10) {
|
|
Text("Search syntax")
|
|
.font(.headline)
|
|
Grid(alignment: .leading, horizontalSpacing: 14, verticalSpacing: 6) {
|
|
ForEach(kExamples) { vExample in
|
|
GridRow {
|
|
Text(vExample.query)
|
|
.font(.system(.body, design: .monospaced))
|
|
.textSelection(.enabled)
|
|
Text(vExample.meaning)
|
|
.foregroundColor(.secondary)
|
|
}
|
|
}
|
|
}
|
|
Divider()
|
|
Text("↓ moves from the search field to the results, ↑ on the first row comes back. Hold ⌥ to freeze the list while files change.")
|
|
.font(.caption)
|
|
.foregroundColor(.secondary)
|
|
.fixedSize(horizontal: false, vertical: true)
|
|
}
|
|
.padding(16)
|
|
.frame(width: 560)
|
|
}
|
|
}
|