Skip to content

Commit c0d2c90

Browse files
thecoolwinterFastestMolasses0xWDG
authored
Jump To Definition (#348)
### Description Adds jump to definition, including a new key command (control-command-J) to initiate a jump, and an interaction (command + mouse click). The destination(s) for a jump is provided via a new object protocol, provided via the SwiftUI API. The popover presented when multiple links are present reuses the completion window, with a slight modification so that it appears as a popover with an arrow rather than a floating window. Detailed changes: - Numerous fixes and improvements to the `SuggestionController` and `SuggestionViewController`, making them work when presented as a popover, as well as some resizing bugs. - New `CodeSuggestionPreviewView`. Displays preview information for a code suggestion, including a syntax-highlighted source preview, documentation, and a path component. - This only appears when one of the three potential information is available, otherwise it is hidden. - This view is a visual effect view, so it will inherit the style of the suggestion controller from the user's theme with a slight tint. - New `JumpToDefinitionModel` manages the mouse interaction, as well as providing the layer between the jump delegate and the code suggestion window. - New `JumpToDefinitionDelegate` protocol defines how the editor can use the delegate object to query links and open them once selected. ### Related Issues * CodeEditApp/CodeEdit#1902 ### Checklist - [x] I read and understood the [contributing guide](https://github.com/CodeEditApp/CodeEdit/blob/main/CONTRIBUTING.md) as well as the [code of conduct](https://github.com/CodeEditApp/CodeEdit/blob/main/CODE_OF_CONDUCT.md) - [x] The issues this PR addresses are related to each other - [x] My changes generate no new warnings - [x] My code builds and runs on my machine - [x] My changes are all related to the related issue above - [x] I documented my code ### Screenshots https://github.com/user-attachments/assets/81d5b24c-6332-4a33-8d2a-8f637bec3bce --------- Co-authored-by: Abe M <[email protected]> Co-authored-by: Wesley de Groot <[email protected]>
1 parent cf39f6d commit c0d2c90

32 files changed

+1045
-179
lines changed

Example/CodeEditSourceEditorExample/CodeEditSourceEditorExample.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
6C1365462B8A7F2D004A1D18 /* LanguagePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C1365452B8A7F2D004A1D18 /* LanguagePicker.swift */; };
2121
6C1365482B8A7FBF004A1D18 /* EditorTheme+Default.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C1365472B8A7FBF004A1D18 /* EditorTheme+Default.swift */; };
2222
6C13654D2B8A821E004A1D18 /* NSColor+Hex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C13654C2B8A821E004A1D18 /* NSColor+Hex.swift */; };
23+
6C730A042E32CA2A00FE1F32 /* MockJumpToDefinitionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C730A032E32CA2A00FE1F32 /* MockJumpToDefinitionDelegate.swift */; };
2324
6C8B564C2E3018CC00DC3F29 /* MockCompletionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C8B564B2E3018CC00DC3F29 /* MockCompletionDelegate.swift */; };
2425
6CF31D4E2DB6A252006A77FD /* StatusBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CF31D4D2DB6A252006A77FD /* StatusBar.swift */; };
2526
/* End PBXBuildFile section */
@@ -39,6 +40,7 @@
3940
6C1365452B8A7F2D004A1D18 /* LanguagePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguagePicker.swift; sourceTree = "<group>"; };
4041
6C1365472B8A7FBF004A1D18 /* EditorTheme+Default.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EditorTheme+Default.swift"; sourceTree = "<group>"; };
4142
6C13654C2B8A821E004A1D18 /* NSColor+Hex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSColor+Hex.swift"; sourceTree = "<group>"; };
43+
6C730A032E32CA2A00FE1F32 /* MockJumpToDefinitionDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockJumpToDefinitionDelegate.swift; sourceTree = "<group>"; };
4244
6C8B564B2E3018CC00DC3F29 /* MockCompletionDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCompletionDelegate.swift; sourceTree = "<group>"; };
4345
6CF31D4D2DB6A252006A77FD /* StatusBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusBar.swift; sourceTree = "<group>"; };
4446
/* End PBXFileReference section */
@@ -123,6 +125,7 @@
123125
6CF31D4D2DB6A252006A77FD /* StatusBar.swift */,
124126
6C1365452B8A7F2D004A1D18 /* LanguagePicker.swift */,
125127
1CB30C392DAA1C28008058A7 /* IndentPicker.swift */,
128+
6C730A032E32CA2A00FE1F32 /* MockJumpToDefinitionDelegate.swift */,
126129
);
127130
path = Views;
128131
sourceTree = "<group>";
@@ -212,6 +215,7 @@
212215
isa = PBXSourcesBuildPhase;
213216
buildActionMask = 2147483647;
214217
files = (
218+
6C730A042E32CA2A00FE1F32 /* MockJumpToDefinitionDelegate.swift in Sources */,
215219
6C1365482B8A7FBF004A1D18 /* EditorTheme+Default.swift in Sources */,
216220
6C13654D2B8A821E004A1D18 /* NSColor+Hex.swift in Sources */,
217221
6C1365302B8A7B94004A1D18 /* CodeEditSourceEditorExampleDocument.swift in Sources */,

Example/CodeEditSourceEditorExample/CodeEditSourceEditorExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

Lines changed: 0 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Example/CodeEditSourceEditorExample/CodeEditSourceEditorExample/Views/ContentView.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ struct ContentView: View {
2323
cursorPositions: [CursorPosition(line: 1, column: 1)]
2424
)
2525
@StateObject private var suggestions: MockCompletionDelegate = MockCompletionDelegate()
26+
@StateObject private var jumpToDefinition: MockJumpToDefinitionDelegate = MockJumpToDefinitionDelegate()
2627

2728
@State private var font: NSFont = NSFont.monospacedSystemFont(ofSize: 12, weight: .medium)
2829
@AppStorage("wrapLines") private var wrapLines: Bool = true
@@ -73,7 +74,8 @@ struct ContentView: View {
7374
)
7475
),
7576
state: $editorState,
76-
completionDelegate: suggestions
77+
completionDelegate: suggestions,
78+
jumpToDefinitionDelegate: jumpToDefinition
7779
)
7880
.overlay(alignment: .bottom) {
7981
StatusBar(

Example/CodeEditSourceEditorExample/CodeEditSourceEditorExample/Views/MockCompletionDelegate.swift

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,18 @@ class MockCompletionDelegate: CodeSuggestionDelegate, ObservableObject {
4848
class Suggestion: CodeSuggestionEntry {
4949
var label: String
5050
var detail: String?
51-
var pathComponents: [String]? { nil }
52-
var targetPosition: CursorPosition? { nil }
53-
var sourcePreview: String? { nil }
51+
var pathComponents: [String]?
52+
var targetPosition: CursorPosition? = CursorPosition(line: 10, column: 20)
53+
var sourcePreview: String?
5454
var image: Image = Image(systemName: "dot.square.fill")
5555
var imageColor: Color = .gray
5656
var deprecated: Bool = false
5757

58-
init(text: String) {
58+
init(text: String, detail: String?, sourcePreview: String?, pathComponents: [String]?) {
5959
self.label = text
60+
self.detail = detail
61+
self.sourcePreview = sourcePreview
62+
self.pathComponents = pathComponents
6063
}
6164
}
6265

@@ -67,7 +70,14 @@ class MockCompletionDelegate: CodeSuggestionDelegate, ObservableObject {
6770
let randomString = (0..<Int.random(in: 1..<text.count)).map {
6871
text[$0]
6972
}.shuffled().joined(separator: " ")
70-
suggestions.append(Suggestion(text: randomString))
73+
suggestions.append(
74+
Suggestion(
75+
text: randomString,
76+
detail: text.randomElement()!,
77+
sourcePreview: randomString,
78+
pathComponents: (0..<Int.random(in: 0..<10)).map { text[$0] }
79+
)
80+
)
7181
}
7282
return suggestions
7383
}
@@ -103,10 +113,12 @@ class MockCompletionDelegate: CodeSuggestionDelegate, ObservableObject {
103113
textView: TextViewController,
104114
cursorPosition: CursorPosition?
105115
) {
106-
guard let suggestion = item as? Suggestion else {
116+
guard let suggestion = item as? Suggestion, let cursorPosition else {
107117
return
108118
}
109119
textView.textView.undoManager?.beginUndoGrouping()
120+
textView.textView.selectionManager.setSelectedRange(cursorPosition.range)
121+
110122
textView.textView.insertText(suggestion.label)
111123
textView.textView.undoManager?.endUndoGrouping()
112124
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//
2+
// MockJumpToDefinitionDelegate.swift
3+
// CodeEditSourceEditorExample
4+
//
5+
// Created by Khan Winter on 7/24/25.
6+
//
7+
8+
import AppKit
9+
import CodeEditSourceEditor
10+
11+
final class MockJumpToDefinitionDelegate: JumpToDefinitionDelegate, ObservableObject {
12+
func queryLinks(forRange range: NSRange, textView: TextViewController) async -> [JumpToDefinitionLink]? {
13+
[
14+
JumpToDefinitionLink(
15+
url: nil,
16+
targetRange: CursorPosition(line: 0, column: 10),
17+
typeName: "Start of Document",
18+
sourcePreview: "// Comment at start"
19+
),
20+
JumpToDefinitionLink(
21+
url: URL(string: "https://codeedit.app/"),
22+
targetRange: CursorPosition(line: 1024, column: 10),
23+
typeName: "CodeEdit Website",
24+
sourcePreview: "https://codeedit.app/"
25+
)
26+
]
27+
}
28+
29+
func openLink(link: JumpToDefinitionLink) {
30+
if let url = link.url {
31+
NSWorkspace.shared.open(url)
32+
}
33+
}
34+
}

Example/CodeEditSourceEditorExample/CodeEditSourceEditorExample/Views/StatusBar.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ struct StatusBar: View {
211211
}
212212

213213
// When there's a single cursor, display the line and column.
214-
return "Line: \(cursorPositions[0].line) Col: \(cursorPositions[0].column) Range: \(cursorPositions[0].range)"
214+
// swiftlint:disable:next line_length
215+
return "Line: \(cursorPositions[0].start.line) Col: \(cursorPositions[0].start.column) Range: \(cursorPositions[0].range)"
215216
}
216217
}

Package.resolved

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ let package = Package(
1717
// A fast, efficient, text view for code.
1818
.package(
1919
url: "https://github.com/CodeEditApp/CodeEditTextView.git",
20-
from: "0.12.0"
20+
from: "0.12.1"
2121
),
2222
// tree-sitter languages
2323
.package(

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/CodeSuggestionEntry.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import SwiftUI
1212
public protocol CodeSuggestionEntry {
1313
var label: String { get }
1414
var detail: String? { get }
15+
var documentation: String? { get }
1516

1617
/// Leave as `nil` if the link is in the same document.
1718
var pathComponents: [String]? { get }

0 commit comments

Comments
 (0)