Skip to content

Commit

Permalink
Add @mainactor annotations to improve thread safety in completion han…
Browse files Browse the repository at this point in the history
…dling

This commit applies the @mainactor attribute to methods associated with
autocomplete functionality in STTextView. This ensures that operations
that involve UI updates occur on the main thread, preventing potential
threading issues. Additionally, it improves the handling of completion
window visibility and closing logic.
  • Loading branch information
krzyzanowskim committed Nov 2, 2024
1 parent 878565e commit 984e18c
Showing 1 changed file with 13 additions and 12 deletions.
25 changes: 13 additions & 12 deletions Sources/STTextViewAppKit/STTextView+Complete.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ extension STTextView {
/// Supporting Autocomplete
///
/// see NSStandardKeyBindingResponding
@MainActor
open override func complete(_ sender: Any?) {
if let completionWindowController, completionWindowController.isVisible {
completionWindowController.close()
Expand All @@ -17,29 +18,29 @@ extension STTextView {
}
}

@MainActor
open override func cancelOperation(_ sender: Any?) {
self.complete(sender)
}

@MainActor
private func performCompletion() {
dispatchPrecondition(condition: .onQueue(.main))

guard let insertionPointLocation = textLayoutManager.insertionPointLocations.first,
let textCharacterSegmentRect = textLayoutManager.textSegmentFrame(at: insertionPointLocation, type: .standard)
let textCharacterSegmentRect = textLayoutManager.textSegmentFrame(at: insertionPointLocation, type: .standard),
let completionItems = delegateProxy.textView(self, completionItemsAtLocation: insertionPointLocation),
completionItems.isEmpty == false
else {
self.completionWindowController?.close()
if let completionWindowController, completionWindowController.isVisible {
self.completionWindowController?.close()
}
return
}

// move left by arbitrary 14px
let characterSegmentFrame = textCharacterSegmentRect.moved(dx: -14, dy: textCharacterSegmentRect.height)

let completionItems = delegateProxy.textView(self, completionItemsAtLocation: insertionPointLocation) ?? []

dispatchPrecondition(condition: .onQueue(.main))

if completionItems.isEmpty {
self.completionWindowController?.close()
} else if let window = self.window {
if let window = self.window {
// move left by arbitrary 14px
let characterSegmentFrame = textCharacterSegmentRect.moved(dx: -14, dy: textCharacterSegmentRect.height)
let completionWindowOrigin = window.convertPoint(toScreen: contentView.convert(characterSegmentFrame.origin, to: nil))
completionWindowController?.showWindow(at: completionWindowOrigin, items: completionItems, parent: window)
completionWindowController?.delegate = self
Expand Down

0 comments on commit 984e18c

Please sign in to comment.