Skip to content

Commit ffaa183

Browse files
committed
Update suggestion panel to highlight async and dim typed content
1 parent 2a4c5c6 commit ffaa183

3 files changed

Lines changed: 381 additions & 119 deletions

File tree

Core/Sources/SuggestionWidget/SuggestionPanelContent/CodeBlockSuggestionPanel.swift

Lines changed: 135 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1+
import Combine
2+
import Perception
13
import SharedUIComponents
4+
import SuggestionModel
25
import SwiftUI
6+
import XcodeInspector
37

48
struct CodeBlockSuggestionPanel: View {
5-
@ObservedObject var suggestion: CodeSuggestionProvider
9+
let suggestion: CodeSuggestionProvider
10+
@Environment(CursorPositionTracker.self) var cursorPositionTracker
611
@Environment(\.colorScheme) var colorScheme
712
@AppStorage(\.suggestionCodeFont) var codeFont
813
@AppStorage(\.suggestionDisplayCompactMode) var suggestionDisplayCompactMode
@@ -15,141 +20,154 @@ struct CodeBlockSuggestionPanel: View {
1520
@AppStorage(\.codeBackgroundColorDark) var codeBackgroundColorDark
1621

1722
struct ToolBar: View {
18-
@ObservedObject var suggestion: CodeSuggestionProvider
23+
let suggestion: CodeSuggestionProvider
1924

2025
var body: some View {
21-
HStack {
22-
Button(action: {
23-
suggestion.selectPreviousSuggestion()
24-
}) {
25-
Image(systemName: "chevron.left")
26-
}.buttonStyle(.plain)
27-
28-
Text(
29-
"\(suggestion.currentSuggestionIndex + 1) / \(suggestion.suggestionCount)"
30-
)
31-
.monospacedDigit()
32-
33-
Button(action: {
34-
suggestion.selectNextSuggestion()
35-
}) {
36-
Image(systemName: "chevron.right")
37-
}.buttonStyle(.plain)
38-
39-
Spacer()
40-
41-
Button(action: {
42-
suggestion.dismissSuggestion()
43-
}) {
44-
Text("Dismiss").foregroundStyle(.tertiary).padding(.trailing, 4)
45-
}.buttonStyle(.plain)
46-
47-
Button(action: {
48-
suggestion.rejectSuggestion()
49-
}) {
50-
Text("Reject")
51-
}.buttonStyle(CommandButtonStyle(color: .gray))
52-
53-
Button(action: {
54-
suggestion.acceptSuggestion()
55-
}) {
56-
Text("Accept")
57-
}.buttonStyle(CommandButtonStyle(color: .accentColor))
26+
WithPerceptionTracking {
27+
HStack {
28+
Button(action: {
29+
suggestion.selectPreviousSuggestion()
30+
}) {
31+
Image(systemName: "chevron.left")
32+
}.buttonStyle(.plain)
33+
34+
Text(
35+
"\(suggestion.currentSuggestionIndex + 1) / \(suggestion.suggestionCount)"
36+
)
37+
.monospacedDigit()
38+
39+
Button(action: {
40+
suggestion.selectNextSuggestion()
41+
}) {
42+
Image(systemName: "chevron.right")
43+
}.buttonStyle(.plain)
44+
45+
Spacer()
46+
47+
Button(action: {
48+
suggestion.dismissSuggestion()
49+
}) {
50+
Text("Dismiss").foregroundStyle(.tertiary).padding(.trailing, 4)
51+
}.buttonStyle(.plain)
52+
53+
Button(action: {
54+
suggestion.rejectSuggestion()
55+
}) {
56+
Text("Reject")
57+
}.buttonStyle(CommandButtonStyle(color: .gray))
58+
59+
Button(action: {
60+
suggestion.acceptSuggestion()
61+
}) {
62+
Text("Accept")
63+
}.buttonStyle(CommandButtonStyle(color: .accentColor))
64+
}
65+
.padding()
66+
.foregroundColor(.secondary)
67+
.background(.regularMaterial)
5868
}
59-
.padding()
60-
.foregroundColor(.secondary)
61-
.background(.regularMaterial)
6269
}
6370
}
6471

6572
struct CompactToolBar: View {
66-
@ObservedObject var suggestion: CodeSuggestionProvider
73+
let suggestion: CodeSuggestionProvider
6774

6875
var body: some View {
69-
HStack {
70-
Button(action: {
71-
suggestion.selectPreviousSuggestion()
72-
}) {
73-
Image(systemName: "chevron.left")
74-
}.buttonStyle(.plain)
75-
76-
Text(
77-
"\(suggestion.currentSuggestionIndex + 1) / \(suggestion.suggestionCount)"
78-
)
79-
.monospacedDigit()
80-
81-
Button(action: {
82-
suggestion.selectNextSuggestion()
83-
}) {
84-
Image(systemName: "chevron.right")
85-
}.buttonStyle(.plain)
86-
87-
Spacer()
88-
89-
Button(action: {
90-
suggestion.dismissSuggestion()
91-
}) {
92-
Image(systemName: "xmark")
93-
}.buttonStyle(.plain)
76+
WithPerceptionTracking {
77+
HStack {
78+
Button(action: {
79+
suggestion.selectPreviousSuggestion()
80+
}) {
81+
Image(systemName: "chevron.left")
82+
}.buttonStyle(.plain)
83+
84+
Text(
85+
"\(suggestion.currentSuggestionIndex + 1) / \(suggestion.suggestionCount)"
86+
)
87+
.monospacedDigit()
88+
89+
Button(action: {
90+
suggestion.selectNextSuggestion()
91+
}) {
92+
Image(systemName: "chevron.right")
93+
}.buttonStyle(.plain)
94+
95+
Spacer()
96+
97+
Button(action: {
98+
suggestion.dismissSuggestion()
99+
}) {
100+
Image(systemName: "xmark")
101+
}.buttonStyle(.plain)
102+
}
103+
.padding(4)
104+
.font(.caption)
105+
.foregroundColor(.secondary)
106+
.background(.regularMaterial)
94107
}
95-
.padding(4)
96-
.font(.caption)
97-
.foregroundColor(.secondary)
98-
.background(.regularMaterial)
99108
}
100109
}
101110

102111
var body: some View {
103-
VStack(spacing: 0) {
104-
CustomScrollView {
105-
CodeBlock(
106-
code: suggestion.code,
107-
language: suggestion.language,
108-
startLineIndex: suggestion.startLineIndex,
109-
scenario: "suggestion",
110-
colorScheme: colorScheme,
111-
font: codeFont.value.nsFont,
112-
droppingLeadingSpaces: hideCommonPrecedingSpaces,
113-
proposedForegroundColor: {
114-
if syncHighlightTheme {
115-
if colorScheme == .light,
116-
let color = codeForegroundColorLight.value?.swiftUIColor
117-
{
118-
return color
119-
} else if let color = codeForegroundColorDark.value?.swiftUIColor {
120-
return color
112+
WithPerceptionTracking {
113+
VStack(spacing: 0) {
114+
CustomScrollView {
115+
WithPerceptionTracking {
116+
AsyncCodeBlock(
117+
code: suggestion.code,
118+
language: suggestion.language,
119+
startLineIndex: suggestion.startLineIndex,
120+
scenario: "suggestion",
121+
font: codeFont.value.nsFont,
122+
droppingLeadingSpaces: hideCommonPrecedingSpaces,
123+
proposedForegroundColor: {
124+
if syncHighlightTheme {
125+
if colorScheme == .light,
126+
let color = codeForegroundColorLight.value?.swiftUIColor
127+
{
128+
return color
129+
} else if let color = codeForegroundColorDark.value?
130+
.swiftUIColor
131+
{
132+
return color
133+
}
134+
}
135+
return nil
136+
}(),
137+
dimmedCharacterCount: suggestion.startLineIndex
138+
== cursorPositionTracker.cursorPosition.line
139+
? cursorPositionTracker.cursorPosition.character
140+
: 0
141+
)
142+
.frame(maxWidth: .infinity)
143+
.background({ () -> Color in
144+
if syncHighlightTheme {
145+
if colorScheme == .light,
146+
let color = codeBackgroundColorLight.value?.swiftUIColor
147+
{
148+
return color
149+
} else if let color = codeBackgroundColorDark.value?.swiftUIColor {
150+
return color
151+
}
121152
}
122-
}
123-
return nil
124-
}()
125-
)
126-
.frame(maxWidth: .infinity)
127-
.background({ () -> Color in
128-
if syncHighlightTheme {
129-
if colorScheme == .light,
130-
let color = codeBackgroundColorLight.value?.swiftUIColor
131-
{
132-
return color
133-
} else if let color = codeBackgroundColorDark.value?.swiftUIColor {
134-
return color
135-
}
153+
return Color.contentBackground
154+
}())
136155
}
137-
return Color.contentBackground
138-
}())
139-
}
156+
}
140157

141-
if suggestionDisplayCompactMode {
142-
CompactToolBar(suggestion: suggestion)
143-
} else {
144-
ToolBar(suggestion: suggestion)
158+
if suggestionDisplayCompactMode {
159+
CompactToolBar(suggestion: suggestion)
160+
} else {
161+
ToolBar(suggestion: suggestion)
162+
}
145163
}
164+
.xcodeStyleFrame(cornerRadius: {
165+
switch suggestionPresentationMode {
166+
case .nearbyTextCursor: 6
167+
case .floatingWidget: nil
168+
}
169+
}())
146170
}
147-
.xcodeStyleFrame(cornerRadius: {
148-
switch suggestionPresentationMode {
149-
case .nearbyTextCursor: 6
150-
case .floatingWidget: nil
151-
}
152-
}())
153171
}
154172
}
155173

Tool/Package.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ let package = Package(
207207
dependencies: [
208208
"SuggestionModel",
209209
"Workspace",
210-
.product(name: "CopilotForXcodeKit", package: "CopilotForXcodeKit")
210+
.product(name: "CopilotForXcodeKit", package: "CopilotForXcodeKit"),
211211
]
212212
),
213213

@@ -217,7 +217,9 @@ let package = Package(
217217
"Highlightr",
218218
"Preferences",
219219
"SuggestionModel",
220+
"DebounceFunction",
220221
.product(name: "STTextView", package: "STTextView"),
222+
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
221223
]
222224
),
223225
.testTarget(name: "SharedUIComponentsTests", dependencies: ["SharedUIComponents"]),
@@ -248,7 +250,7 @@ let package = Package(
248250
"Workspace",
249251
"SuggestionProvider",
250252
"XPCShared",
251-
"BuiltinExtension"
253+
"BuiltinExtension",
252254
]
253255
),
254256

0 commit comments

Comments
 (0)