Skip to content

Commit de90bbc

Browse files
committed
Finish JumpToDefinitionModel
1 parent a49de0c commit de90bbc

File tree

6 files changed

+54
-97
lines changed

6 files changed

+54
-97
lines changed

Sources/CodeEditSourceEditor/CodeSuggestion/Model/CodeSuggestionDelegate.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
// Created by Abe Malla on 12/26/24.
66
//
77

8+
@MainActor
89
public protocol CodeSuggestionDelegate: AnyObject {
910
func completionTriggerCharacters() -> Set<String>
1011

Sources/CodeEditSourceEditor/CodeSuggestion/Model/SuggestionViewModel.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import AppKit
99

10+
@MainActor
1011
final class SuggestionViewModel: ObservableObject {
1112
/// The items to be displayed in the window
1213
@Published var items: [CodeSuggestionEntry] = []

Sources/CodeEditSourceEditor/CodeSuggestion/Window/SuggestionController.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ public final class SuggestionController: NSWindowController {
3131
/// Tracks when the window is placed above the cursor
3232
var isWindowAboveCursor = false
3333

34+
private var popover: NSPopover?
35+
3436
/// An event monitor for keyboard events
3537
private var localEventMonitor: Any?
3638
/// Holds the observer for the window resign notifications
@@ -76,6 +78,7 @@ public final class SuggestionController: NSWindowController {
7678
popover.behavior = .transient
7779
popover.contentViewController = self.contentViewController
7880
popover.show(relativeTo: textViewPosition, of: textView.textView, preferredEdge: .maxY)
81+
self.popover = popover
7982
} else {
8083
self.showWindow(attachedTo: parentWindow)
8184
self.constrainWindowToScreenEdges(cursorRect: cursorRect)
@@ -112,6 +115,10 @@ public final class SuggestionController: NSWindowController {
112115
public override func close() {
113116
model.willClose()
114117
removeEventMonitors()
118+
119+
popover?.close()
120+
popover = nil
121+
115122
super.close()
116123
}
117124

Sources/CodeEditSourceEditor/Controller/TextViewController.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ public class TextViewController: NSViewController {
247247

248248
if let treeSitterClient {
249249
jumpToDefinitionModel = JumpToDefinitionModel(
250-
textView: textView,
250+
controller: self,
251251
treeSitterClient: treeSitterClient,
252252
delegate: nil
253253
)

Sources/CodeEditSourceEditor/JumpToDefinition/JumpToDefinitionLinkList.swift

Lines changed: 0 additions & 85 deletions
This file was deleted.

Sources/CodeEditSourceEditor/JumpToDefinition/JumpToDefinitionModel.swift

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,22 @@ final class JumpToDefinitionModel {
1919

2020
weak var delegate: JumpToDefinitionDelegate?
2121

22-
private weak var textView: TextView?
22+
private weak var controller: TextViewController?
2323
private weak var treeSitterClient: TreeSitterClient?
2424

2525
private(set) public var hoveredRange: NSRange?
2626
private var hoverRequestTask: Task<Void, Never>?
2727

2828
private var jumpRequestTask: Task<Void, Never>?
2929

30-
init(textView: TextView, treeSitterClient: TreeSitterClient, delegate: JumpToDefinitionDelegate?) {
31-
self.textView = textView
30+
private var currentLinks: [JumpToDefinitionLink]?
31+
32+
private var textView: TextView? {
33+
controller?.textView
34+
}
35+
36+
init(controller: TextViewController, treeSitterClient: TreeSitterClient, delegate: JumpToDefinitionDelegate?) {
37+
self.controller = controller
3238
self.treeSitterClient = treeSitterClient
3339
self.delegate = delegate
3440
}
@@ -55,9 +61,13 @@ final class JumpToDefinitionModel {
5561
func performJump(at location: NSRange) {
5662
jumpRequestTask?.cancel()
5763
jumpRequestTask = Task {
64+
currentLinks = nil
5865
guard let links = await delegate?.queryLinks(forRange: location),
5966
!links.isEmpty else {
6067
NSSound.beep()
68+
if let textView {
69+
BezelNotification.show(symbolName: "questionmark", over: textView)
70+
}
6171
return
6272
}
6373
if links.count == 1 {
@@ -79,10 +89,26 @@ final class JumpToDefinitionModel {
7989

8090
func presentLinkPopover(on range: NSRange, links: [JumpToDefinitionLink]) {
8191
let halfway = range.location + (range.length / 2)
82-
guard let textView = textView, let firstRect = textView.layoutManager.rectForOffset(halfway) else { return }
83-
let popover = NSPopover()
84-
popover.behavior = .transient
85-
popover.show(relativeTo: firstRect, of: textView, preferredEdge: .minY)
92+
let range = NSRange(location: halfway, length: 0)
93+
guard let controller,
94+
let position = controller.resolveCursorPosition(CursorPosition(range: range)) else {
95+
return
96+
}
97+
currentLinks = links
98+
SuggestionController.shared.showCompletions(
99+
textView: controller,
100+
delegate: self,
101+
cursorPosition: position,
102+
asPopover: true
103+
)
104+
}
105+
106+
// MARK: - Local Link
107+
108+
func openLocalLink(link: JumpToDefinitionLink) {
109+
guard let controller = controller else { return }
110+
controller.textView.selectionManager.setSelectedRange(link.targetRange)
111+
controller.textView.scrollSelectionToVisible()
86112
}
87113

88114
// MARK: - Mouse Interaction
@@ -138,21 +164,28 @@ extension JumpToDefinitionModel: CodeSuggestionDelegate {
138164
textView: TextViewController,
139165
cursorPosition: CursorPosition
140166
) async -> (windowPosition: CursorPosition, items: [CodeSuggestionEntry])? {
141-
nil
167+
guard let links = currentLinks else { return nil }
168+
defer { self.currentLinks = nil }
169+
return (cursorPosition, links)
142170
}
143171

144-
nonisolated func completionOnCursorMove(
172+
func completionOnCursorMove(
145173
textView: TextViewController,
146174
cursorPosition: CursorPosition
147175
) -> [CodeSuggestionEntry]? {
148176
nil
149177
}
150178

151-
nonisolated func completionWindowApplyCompletion(
179+
func completionWindowApplyCompletion(
152180
item: CodeSuggestionEntry,
153181
textView: TextViewController,
154182
cursorPosition: CursorPosition
155183
) {
156-
184+
guard let link = item as? JumpToDefinitionLink else { return }
185+
if let url = link.url {
186+
delegate?.openLink(url: url, targetRange: link.targetRange)
187+
} else {
188+
openLocalLink(link: link)
189+
}
157190
}
158191
}

0 commit comments

Comments
 (0)