Skip to content

Give the host Swift names and Swift idioms - #40

Merged
Mx-Iris merged 5 commits into
mainfrom
refactor/swift-idiomatic-cleanup
Oct 10, 2026
Merged

Mx-Iris merged 5 commits into
mainfrom
refactor/swift-idiomatic-cleanup

Conversation

@Mx-Iris

@Mx-Iris Mx-Iris commented Oct 8, 2026

Copy link
Copy Markdown
Collaborator

The 3.0 Swift host was translated from Objective-C file by file, so it still reads like Objective-C: LK / Lookin prefixes on every type and member, implicitly unwrapped optionals everywhere, @objc(LK…) names nothing looks up, and @objc protocols that only Swift implements. This PR gives it Swift names and Swift idioms. It depends on LookInside-Server #12, whose LookinCore it mirrors.

Commits

  1. Sync LookinCore (088bc7b): mirrors the Server branch, where the LookinCore Swift names lost their prefixes and the implicitly unwrapped optionals became optionals. The host follows the new names and handles the values that are optional now.
  2. Type names (43c34d8): LKHierarchyView → HierarchyView, LookinLiveDocument → LiveDocument; descriptive names where the bare one would clash (LKLabel → TextLabel, LKWindow → AppWindow, LKChannel → ServerChannel). Files, the target's membershipExceptions and the test scripts follow.
  3. Member and constant names (bcb255e): lk_ / lk / LK prefixes go; lkLock gives way to Foundation's withLock, the duplicated NSColor helpers to LookinCore's, lkDebugDescription to CustomDebugStringConvertible.
  4. Implicitly unwrapped optionals (f5733bd): views and controllers that always exist are non-optional (created where declared, lazily when their target is self, or before super.init); the rest are optional and handled.
  5. Leftovers (20eed03): logging through FrameworkToolbox's @Loggable / #log (a direct FoundationToolbox dependency, 0.9.x); the @objc(LK…) class names and @objcMembers go, except the three document classes Info.plist names; three Swift-only @objc protocols become Swift protocols.

What does not change

  • Anything persisted or sent: UserDefaults keys, toolbar item identifiers, notification names, the .lookin archive format, the wire protocol, the MCP JSON (Codable names unchanged; the custom-object encoder reports NSStringFromClass, so class names are the same as before).
  • The log subsystems and categories of the loggers that existed. NSLog output moves to the unified log under com.lookinside.app, category = type name, at the default level, unredacted.

Behavior to review

  • HierarchyDataSource.reload(with:keepState:) accepted a nil hierarchy only to trap on it; it now reloads to an empty tree.
  • A dashboard attribute section without an identifier is treated as hidden instead of trapping.
  • StaticViewController creates its child controllers in init, before the superclass initializer builds its view (which is when they used to be created); StaticWindowController creates its data source, update manager and view controller before super.init(window:).

Testing

  • xcodebuild build (Debug, -skipMacroValidation, CODE_SIGNING_ALLOWED=NO).
  • Scripts/test-gesture-models.sh, test-mcp-bridge.sh, test-dashboard.sh, test-xcode-viewhierarchy.sh, test-launch-toolbar-read.sh, test-security-gates.sh: all pass, as on main.
  • No UI testing was done. The changes to view setup and the hierarchy delegate need a manual pass: open a live app and a .lookin file, select, hover, double-click, expand/collapse recursively, show/hide previews from the menu, search, edit attributes, open the console and the gesture debugger.

Mx-Iris and others added 5 commits October 9, 2026 00:51
Mirrors LookInside-Server's refactor/swift-idiomatic-cleanup (330c5b5), where
the Swift types and members lost their LK / LKS / Lookin prefixes and the
implicitly unwrapped optionals became optionals. The Objective-C names, the
archive format and the wire protocol are unchanged, so .lookin documents and
connected servers keep working.

The host follows the new names: LookinDisplayItem is DisplayItem,
LookinAttributesGroup is AttributesGroup, lookin_bindObject(_:forKey:) is
bindObject(_:forKey:), and so on. Where a model value is optional now, the
host handles nil instead of trapping: an attribute section without an
identifier is treated as hidden, an attribute without one encodes an empty
identifier for MCP, and the dashboard looks up cards by
`uniqueKey() ?? ""` as it already did elsewhere. Both DisplayItemDelegate
implementations take the item non-optionally, as the protocol does now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The host's own types follow the same rules as LookinCore's: the prefix goes
(LKHierarchyView -> HierarchyView, LookinLiveDocument -> LiveDocument), a
name that would be too generic or clash with SwiftUI gets a descriptive one
(LKLabel -> TextLabel, LKWindow -> AppWindow, LKChannel -> ServerChannel,
LKHelper -> AppHelper), abbreviations are spelled out
(LKDashboardAttributeJsonView -> DashboardAttributeJSONView,
LookinMsgAttribute -> MessageAttribute), and LookinPreferredAppeanranceType
is PreferredAppearanceType. Files follow their main type, including the
category files named after a LookinCore type
(LookinDisplayItem+LookinClient.swift -> DisplayItem+LookinClient.swift); the
target's membershipExceptions list and the test scripts that compile host
files by path follow the file names.

The @objc(...) names stay as they are in this commit, so the three document
classes Info.plist names and every runtime lookup keep working. The custom
object encoder of the MCP bridge reports NSStringFromClass now: the
LookinCore model classes kept their Objective-C names, so the class names it
sends are the same as before.

Also mirrors LookInside-Server 53abf34, where DisplayItem types its
previewNode with the renamed DisplayItemNode.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ames

The host's extension members, private helpers and file-level constants lose
their prefixes (lk_isDarkMode -> isDarkMode, lkRunOnMain -> runOnMain,
LKToolBarIdentifier_Reload -> toolbarIdentifierReload). Where the system or
LookinCore already has the same thing, the host uses it:

- NSLock's lkLock(_:) is gone; Foundation's withLock(_:) does the same.
- NSColor's lk_rgbaComponents() and lk_color(fromRGBAComponents:) were line
  for line the LookinCore helpers sRGBAComponents() and
  sRGBColor(fromRGBAComponents:); the host calls those now.
- SwiftUISupportActivationState conforms to CustomDebugStringConvertible
  instead of carrying lkDebugDescription.
- lkLayout is frameLayout, lk_button(with:target:action:) is
  borderlessImageButton(with:target:action:), lk_capitalizedString() is
  capitalizingFirstLetter().

The number input heights are static members of NumberInputView. The values
of persisted or posted strings (toolbar item identifiers, window size names,
notification names) are unchanged. Files holding several types lose the
prefix too (LKSuggestions.swift -> HitTargetSuggestions.swift), with the
project's membershipExceptions and the test scripts following.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each declaration now says whether it can be nil:

- Views and controllers that always exist are non-optional. The subviews
  StaticViewController, DashboardViewController, PreviewController and the
  JSON attribute view used to create during view setup are created where
  they are declared; the controls whose target is self are lazy and still
  created where init first touches them. StaticViewController creates its
  child controllers in init, before the superclass initializer builds its
  view (which is when buildContent() used to create them), and
  StaticWindowController creates its data source, update manager and view
  controller before super.init(window:).
- HierarchyView, HierarchyController and HierarchyRowView take their data
  source non-optionally and cannot fail to initialize.
- HierarchyViewDelegate says which item can be nil: the selection, the
  hovered row and the search string can; the double-clicked, expanded,
  collapsed and previewed items cannot, and the menu handlers check before
  they call. TableViewDelegate passes its sender non-optionally.
- HierarchyDataSource.preferenceManager() always returns one.
- reload(with:keepState:) accepts the nil it is handed when the server's
  reply is not a hierarchy, where the implicit unwrap used to trap.
- InjectableFrameworkInstaller runs the main-thread install with
  DispatchQueue.main.sync's return value instead of a captured result.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…otocols

- Logging: the NSLog calls and the hand-written os.Logger properties use
  FrameworkToolbox's @loggable and #log. The MCP bridge services, the
  installer ("Installer") and the SwiftUI support gatekeeper ("Activation")
  keep their subsystem and category; the types that used NSLog log under
  com.lookinside.app with their type name as the category, at NSLog's
  default level and with every interpolation public, as NSLog printed it.
  The target depends on FrameworkToolbox's FoundationToolbox product
  directly (0.9.x, the version UIFoundation already resolves).
  JSONAttributeItem.swift keeps its NSLog: Scripts/test-dashboard.sh compiles
  it on its own, without the package.
- The host's classes lose their @objc(LK...) / @objc(Lookin...) names and the
  classes their @objcMembers. Nothing looks them up by name: the archives hold
  LookinCore classes only, there are no nibs, and the SwiftUI support
  gatekeeper checks `is StaticWindowController` instead of comparing the class
  name. The three document classes that Info.plist names keep theirs.
  HierarchyView.searchTextFieldView, which the DEBUG UI snapshots read by key,
  is @objc explicitly.
- HierarchyViewDelegate, UserActionManagerDelegate and
  StaticAsyncUpdateManagerDelegate are Swift protocols. The two optional
  preview methods of HierarchyViewDelegate are required, with empty
  implementations in HierarchyController that the static and read
  controllers override; UserActionType is a Swift enum.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 8, 2026 17:41

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@Mx-Iris
Mx-Iris merged commit 53d67cd into main Oct 10, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants