Ariver
2026-07-02 01bab5422712299b49f656e6b4c42a3bf314f519
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
#!/usr/bin/env bash
set -euo pipefail
 
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
APP_DELEGATE="$ROOT_DIR/Apptag/ApptagApp.swift"
QUICK_SEARCH="$ROOT_DIR/Apptag/QuickSearch.swift"
CONTENT_VIEW="$ROOT_DIR/Apptag/ContentView.swift"
 
python3 - "$APP_DELEGATE" "$QUICK_SEARCH" "$CONTENT_VIEW" <<'PY'
import re
import sys
from pathlib import Path
 
app_delegate = Path(sys.argv[1]).read_text(encoding="utf-8")
quick_search = Path(sys.argv[2]).read_text(encoding="utf-8")
content_view = Path(sys.argv[3]).read_text(encoding="utf-8")
 
 
def fail(message: str) -> None:
    print(f"FAIL: {message}", file=sys.stderr)
    sys.exit(1)
 
 
def require(condition: bool, message: str) -> None:
    if not condition:
        fail(message)
 
 
def require_contains(text: str, needle: str, message: str) -> None:
    require(needle in text, message)
 
 
local_monitor = re.search(
    r"private func installQuickSearchLocalMouseMonitor\(\).*?private func removeQuickSearchExternalMouseMonitor\(\)",
    app_delegate,
    re.S,
)
require(local_monitor is not None, "Quick Search local mouse monitor block is missing")
local_monitor_body = local_monitor.group(0)
require_contains(
    local_monitor_body,
    "if event.window === self.overlayWindow {\n                return event\n            }",
    "local mouse monitor must pass through overlayWindow events so result rows receive clicks",
)
require(
    "tagLauncherQuickSearchDismissRequested" not in local_monitor_body,
    "local mouse monitor must not dismiss/swallow clicks inside the overlay window",
)
 
panel_apply = re.search(
    r"func apply\(_ configuration: QuickSearchPanelConfiguration, anchorView: QuickSearchPanelAnchorView\).*?func closePanel\(\)",
    quick_search,
    re.S,
)
require(panel_apply is not None, "QuickSearchPanel apply block is missing")
panel_apply_body = panel_apply.group(0)
activate_index = panel_apply_body.find("NSApp.activate(ignoringOtherApps: true)")
make_key_index = panel_apply_body.find("panel.makeKeyAndOrderFront(nil)")
require(activate_index >= 0, "Quick Search panel must activate the app before accepting keyboard input")
require(make_key_index >= 0, "Quick Search panel must be made key and ordered front")
require(
    activate_index < make_key_index,
    "Quick Search panel activation must happen before makeKeyAndOrderFront",
)
 
panel_factory = re.search(
    r"private func ensurePanel\(parentWindow: NSWindow\).*?let panel = QuickSearchPanel\((.*?)\n            \)",
    quick_search,
    re.S,
)
require(panel_factory is not None, "QuickSearchPanel factory block is missing")
require(
    ".nonactivatingPanel" not in panel_factory.group(0),
    "Quick Search panel must not use .nonactivatingPanel; Return can otherwise go to the previous app",
)
require_contains(
    quick_search,
    "override var canBecomeKey: Bool { true }",
    "Quick Search panel must be allowed to become key",
)
panel_class = re.search(
    r"private final class QuickSearchPanel: NSPanel.*?final class QuickSearchPanelAnchorView",
    quick_search,
    re.S,
)
require(panel_class is not None, "QuickSearchPanel class block is missing")
panel_class_body = panel_class.group(0)
for needle, message in [
    ("override func sendEvent(_ event: NSEvent)", "Quick Search panel must intercept mouse events before SwiftUI/scroll intermediate views can drop result clicks"),
    ("event.type == .leftMouseDown", "Quick Search panel click fallback must be limited to left mouse down"),
    ("quickSearchResultRow(at: event.locationInWindow)", "Quick Search panel must resolve the clicked result row from the window point"),
    ("row.launchFromMouseClick()", "Quick Search panel must launch the resolved result row directly"),
    ("quickSearchResultRowFromHitTest(atWindowPoint: windowPoint)", "Quick Search panel should keep the direct hitTest path for normal AppKit row clicks"),
    ("quickSearchResultRowDescendant(containingWindowPoint: windowPoint)", "Quick Search panel must use a recursive geometry fallback when SwiftUI/scroll intermediate views hide rows from hitTest"),
]:
    require_contains(panel_class_body, needle, message)
 
for needle, message in [
    ("func quickSearchResultRowDescendant(containingWindowPoint windowPoint: NSPoint) -> QuickSearchResultRowView?", "Quick Search must expose a recursive row lookup fallback"),
    ("for subview in subviews.reversed()", "Quick Search recursive lookup must scan frontmost subviews first"),
    ("row.containsWindowPointForLaunch(windowPoint)", "Quick Search recursive lookup must verify the clicked window point is inside a result row"),
]:
    require_contains(quick_search, needle, message)
 
text_field = re.search(
    r"private struct QuickSearchTextField: NSViewRepresentable.*?private final class QuickSearchNativeTextField",
    quick_search,
    re.S,
)
require(text_field is not None, "QuickSearchTextField block is missing")
text_field_body = text_field.group(0)
for needle, message in [
    ("field.target = context.coordinator", "Quick Search text field must set a target for Return submit fallback"),
    ("field.action = #selector(Coordinator.submitAction(_:))", "Quick Search text field must set submitAction as its action"),
    ("@objc func submitAction(_ sender: Any?)", "Quick Search coordinator must expose submitAction"),
    ("onCommand?(.submit)", "Quick Search submitAction/delegate path must emit .submit"),
]:
    require_contains(text_field_body, needle, message)
 
row_view = re.search(
    r"final class QuickSearchResultRowView: NSView.*?private func setup\(\)",
    quick_search,
    re.S,
)
require(row_view is not None, "QuickSearchResultRowView block is missing")
row_view_body = row_view.group(0)
require_contains(
    row_view_body,
    "override func acceptsFirstMouse(for event: NSEvent?) -> Bool {\n        true\n    }",
    "Quick Search result rows must accept first mouse",
)
require_contains(
    row_view_body,
    "override func mouseDown(with event: NSEvent)",
    "Quick Search result rows must handle mouseDown",
)
require_contains(
    row_view_body,
    "onLaunch(result)",
    "Quick Search result rows must launch their result on click",
)
require_contains(
    row_view_body,
    "func launchFromMouseClick() -> Bool",
    "Quick Search result rows must expose a panel-level click fallback",
)
require_contains(
    row_view_body,
    "func containsWindowPointForLaunch(_ windowPoint: NSPoint) -> Bool",
    "Quick Search result rows must expose geometry-based click containment for panel fallback",
)
require_contains(
    row_view_body,
    "bounds.contains(localPoint) && visibleRect.contains(localPoint)",
    "Quick Search result row geometry fallback must reject hidden or clipped row areas",
)
require_contains(
    row_view_body,
    "DispatchQueue.main.async { [onLaunch, result] in",
    "Quick Search row launch fallback must capture the clicked result before async launch",
)
 
command_submit = re.search(
    r"private func handleQuickSearchCommand\(_ command: QuickSearchCommand\).*?private var selectedQuickSearchResult",
    content_view,
    re.S,
)
require(command_submit is not None, "ContentView Quick Search command handler is missing")
require_contains(
    command_submit.group(0),
    "case .submit:\n            guard let selected = selectedQuickSearchResult else { return }\n            launchQuickSearchResult(selected)",
    "Quick Search submit command must launch the selected result",
)
require_contains(
    content_view,
    "NSWorkspace.shared.openApplication(at: app.path, configuration: configuration)",
    "Quick Search launch path must still use NSWorkspace.openApplication",
)
 
print("PASS quick search launch contract")
PY