@@ -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