Skip to content

Commit 2c8bc06

Browse files
Lint
1 parent 14049c1 commit 2c8bc06

File tree

3 files changed

+196
-185
lines changed

3 files changed

+196
-185
lines changed

CodeEdit/Features/NavigatorArea/IssueNavigator/OutlineView/IssueNavigatorViewController.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,9 +159,11 @@ final class IssueNavigatorViewController: NSViewController {
159159
toggleExpansion(of: fileNode)
160160
openFileTab(fileUri: fileNode.uri)
161161
} else if let diagnosticNode = item as? DiagnosticIssueNode {
162-
openFileTab(fileUri: diagnosticNode.fileUri,
163-
line: diagnosticNode.diagnostic.range.start.line,
164-
column: diagnosticNode.diagnostic.range.start.character)
162+
openFileTab(
163+
fileUri: diagnosticNode.fileUri,
164+
line: diagnosticNode.diagnostic.range.start.line,
165+
column: diagnosticNode.diagnostic.range.start.character
166+
)
165167
}
166168
}
167169

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
//
2+
// IssueNodes.swift
3+
// CodeEdit
4+
//
5+
// Created by Abe Malla on 6/7/25.
6+
//
7+
8+
import SwiftUI
9+
import LanguageServerProtocol
10+
11+
/// Protocol defining the common interface for nodes in the issue navigator
12+
protocol IssueNode: Identifiable, Hashable {
13+
var id: UUID { get }
14+
var name: String { get }
15+
var isExpandable: Bool { get }
16+
var nsIcon: NSImage { get }
17+
}
18+
19+
/// Represents the project (root) node in the issue navigator
20+
class ProjectIssueNode: IssueNode, ObservableObject, Equatable {
21+
let id: UUID = UUID()
22+
let name: String
23+
24+
@Published var files: [FileIssueNode]
25+
@Published var isExpanded: Bool
26+
27+
var nsIcon: NSImage {
28+
return NSImage(systemSymbolName: "folder.fill", accessibilityDescription: "Root folder")!
29+
}
30+
31+
var isExpandable: Bool {
32+
!files.isEmpty
33+
}
34+
35+
var diagnosticsCount: Int {
36+
files.reduce(0) { $0 + $1.diagnostics.count }
37+
}
38+
39+
var errorCount: Int {
40+
files.reduce(0) { $0 + $1.diagnostics.filter { $0.diagnostic.severity == .error }.count }
41+
}
42+
43+
var warningCount: Int {
44+
files.reduce(0) { $0 + $1.diagnostics.filter { $0.diagnostic.severity == .warning }.count }
45+
}
46+
47+
init(name: String, files: [FileIssueNode] = [], isExpanded: Bool = true) {
48+
self.name = name
49+
self.files = files
50+
self.isExpanded = isExpanded
51+
}
52+
53+
static func == (lhs: ProjectIssueNode, rhs: ProjectIssueNode) -> Bool {
54+
lhs.id == rhs.id
55+
}
56+
57+
func hash(into hasher: inout Hasher) {
58+
hasher.combine(id)
59+
}
60+
}
61+
62+
/// Represents a file node in the issue navigator
63+
class FileIssueNode: IssueNode, ObservableObject, Equatable {
64+
let id: UUID = UUID()
65+
let uri: DocumentUri
66+
let name: String
67+
68+
@Published var diagnostics: [DiagnosticIssueNode]
69+
@Published var isExpanded: Bool
70+
71+
/// Returns the extension of the file or an empty string if no extension is present.
72+
var type: FileIcon.FileType {
73+
let fileExtension = (uri as NSString).pathExtension.lowercased()
74+
if !fileExtension.isEmpty {
75+
if let type = FileIcon.FileType(rawValue: fileExtension) {
76+
return type
77+
}
78+
}
79+
return .txt
80+
}
81+
82+
/// Returns a `Color` for a specific `fileType`
83+
///
84+
/// If not specified otherwise this will return `Color.accentColor`
85+
var iconColor: SwiftUI.Color {
86+
FileIcon.iconColor(fileType: type)
87+
}
88+
89+
/// Return the icon of the file as `NSImage`
90+
var nsIcon: NSImage {
91+
let systemImage = FileIcon.fileIcon(fileType: type)
92+
if let customImage = NSImage.symbol(named: systemImage) {
93+
return customImage
94+
} else {
95+
return NSImage(systemSymbolName: systemImage, accessibilityDescription: systemImage)
96+
?? NSImage(systemSymbolName: "doc", accessibilityDescription: "doc")!
97+
}
98+
}
99+
100+
var isExpandable: Bool {
101+
!diagnostics.isEmpty
102+
}
103+
104+
var errorCount: Int {
105+
diagnostics.filter { $0.diagnostic.severity == .error }.count
106+
}
107+
108+
var warningCount: Int {
109+
diagnostics.filter { $0.diagnostic.severity == .warning }.count
110+
}
111+
112+
init(uri: DocumentUri, name: String? = nil, diagnostics: [DiagnosticIssueNode] = [], isExpanded: Bool = false) {
113+
self.uri = uri
114+
self.name = name ?? (URL(string: uri)?.lastPathComponent ?? "Unknown")
115+
self.diagnostics = diagnostics
116+
self.isExpanded = isExpanded
117+
}
118+
119+
static func == (lhs: FileIssueNode, rhs: FileIssueNode) -> Bool {
120+
lhs.id == rhs.id
121+
}
122+
123+
func hash(into hasher: inout Hasher) {
124+
hasher.combine(id)
125+
}
126+
}
127+
128+
/// Represents a diagnostic node in the issue navigator
129+
class DiagnosticIssueNode: IssueNode, ObservableObject, Equatable {
130+
let id: UUID = UUID()
131+
let diagnostic: Diagnostic
132+
let fileUri: DocumentUri
133+
134+
var name: String {
135+
diagnostic.message.trimmingCharacters(in: .newlines)
136+
}
137+
138+
var isExpandable: Bool {
139+
false
140+
}
141+
142+
var nsIcon: NSImage {
143+
switch diagnostic.severity {
144+
case .error:
145+
return NSImage(
146+
systemSymbolName: "xmark.octagon.fill",
147+
accessibilityDescription: "Error"
148+
)!
149+
case .warning:
150+
return NSImage(systemSymbolName: "exclamationmark.triangle.fill", accessibilityDescription: "Warning")!
151+
case .information:
152+
return NSImage(systemSymbolName: "exclamationmark.triangle.fill", accessibilityDescription: "Information")!
153+
case .hint:
154+
return NSImage(systemSymbolName: "lightbulb.fill", accessibilityDescription: "Hint")!
155+
case nil:
156+
return NSImage(systemSymbolName: "circle.fill", accessibilityDescription: "Unknown Issue Type")!
157+
}
158+
}
159+
160+
var severityColor: NSColor {
161+
switch diagnostic.severity {
162+
case .error:
163+
return .errorRed
164+
case .warning:
165+
return .warningYellow
166+
case .information:
167+
return .blue
168+
case .hint:
169+
return .gray
170+
case nil:
171+
return .secondaryLabelColor
172+
}
173+
}
174+
175+
var locationString: String {
176+
"Line \(diagnostic.range.start.line + 1), Column \(diagnostic.range.start.character + 1)"
177+
}
178+
179+
init(diagnostic: Diagnostic, fileUri: DocumentUri) {
180+
self.diagnostic = diagnostic
181+
self.fileUri = fileUri
182+
}
183+
184+
static func == (lhs: DiagnosticIssueNode, rhs: DiagnosticIssueNode) -> Bool {
185+
lhs.id == rhs.id
186+
}
187+
188+
func hash(into hasher: inout Hasher) {
189+
hasher.combine(id)
190+
}
191+
}

CodeEdit/Features/NavigatorArea/ViewModels/IssueNavigatorViewModel.swift

Lines changed: 0 additions & 182 deletions
Original file line numberDiff line numberDiff line change
@@ -227,188 +227,6 @@ class IssueNavigatorViewModel: ObservableObject {
227227
}
228228
}
229229

230-
/// Protocol defining the common interface for nodes in the issue navigator
231-
protocol IssueNode: Identifiable, Hashable {
232-
var id: UUID { get }
233-
var name: String { get }
234-
var isExpandable: Bool { get }
235-
var nsIcon: NSImage { get }
236-
}
237-
238-
/// Represents the project (root) node in the issue navigator
239-
class ProjectIssueNode: IssueNode, ObservableObject, Equatable {
240-
let id: UUID = UUID()
241-
let name: String
242-
243-
@Published var files: [FileIssueNode]
244-
@Published var isExpanded: Bool
245-
246-
var nsIcon: NSImage {
247-
return NSImage(systemSymbolName: "folder.fill", accessibilityDescription: "Root folder")!
248-
}
249-
250-
var isExpandable: Bool {
251-
!files.isEmpty
252-
}
253-
254-
var diagnosticsCount: Int {
255-
files.reduce(0) { $0 + $1.diagnostics.count }
256-
}
257-
258-
var errorCount: Int {
259-
files.reduce(0) { $0 + $1.diagnostics.filter { $0.diagnostic.severity == .error }.count }
260-
}
261-
262-
var warningCount: Int {
263-
files.reduce(0) { $0 + $1.diagnostics.filter { $0.diagnostic.severity == .warning }.count }
264-
}
265-
266-
init(name: String, files: [FileIssueNode] = [], isExpanded: Bool = true) {
267-
self.name = name
268-
self.files = files
269-
self.isExpanded = isExpanded
270-
}
271-
272-
static func == (lhs: ProjectIssueNode, rhs: ProjectIssueNode) -> Bool {
273-
lhs.id == rhs.id
274-
}
275-
276-
func hash(into hasher: inout Hasher) {
277-
hasher.combine(id)
278-
}
279-
}
280-
281-
/// Represents a file node in the issue navigator
282-
class FileIssueNode: IssueNode, ObservableObject, Equatable {
283-
let id: UUID = UUID()
284-
let uri: DocumentUri
285-
let name: String
286-
287-
@Published var diagnostics: [DiagnosticIssueNode]
288-
@Published var isExpanded: Bool
289-
290-
/// Returns the extension of the file or an empty string if no extension is present.
291-
var type: FileIcon.FileType {
292-
let fileExtension = (uri as NSString).pathExtension.lowercased()
293-
if !fileExtension.isEmpty {
294-
if let type = FileIcon.FileType(rawValue: fileExtension) {
295-
return type
296-
}
297-
}
298-
return .txt
299-
}
300-
301-
/// Returns a `Color` for a specific `fileType`
302-
///
303-
/// If not specified otherwise this will return `Color.accentColor`
304-
var iconColor: SwiftUI.Color {
305-
FileIcon.iconColor(fileType: type)
306-
}
307-
308-
/// Return the icon of the file as `NSImage`
309-
var nsIcon: NSImage {
310-
let systemImage = FileIcon.fileIcon(fileType: type)
311-
if let customImage = NSImage.symbol(named: systemImage) {
312-
return customImage
313-
} else {
314-
return NSImage(systemSymbolName: systemImage, accessibilityDescription: systemImage)
315-
?? NSImage(systemSymbolName: "doc", accessibilityDescription: "doc")!
316-
}
317-
}
318-
319-
var isExpandable: Bool {
320-
!diagnostics.isEmpty
321-
}
322-
323-
var errorCount: Int {
324-
diagnostics.filter { $0.diagnostic.severity == .error }.count
325-
}
326-
327-
var warningCount: Int {
328-
diagnostics.filter { $0.diagnostic.severity == .warning }.count
329-
}
330-
331-
init(uri: DocumentUri, name: String? = nil, diagnostics: [DiagnosticIssueNode] = [], isExpanded: Bool = false) {
332-
self.uri = uri
333-
self.name = name ?? (URL(string: uri)?.lastPathComponent ?? "Unknown")
334-
self.diagnostics = diagnostics
335-
self.isExpanded = isExpanded
336-
}
337-
338-
static func == (lhs: FileIssueNode, rhs: FileIssueNode) -> Bool {
339-
lhs.id == rhs.id
340-
}
341-
342-
func hash(into hasher: inout Hasher) {
343-
hasher.combine(id)
344-
}
345-
}
346-
347-
/// Represents a diagnostic node in the issue navigator
348-
class DiagnosticIssueNode: IssueNode, ObservableObject, Equatable {
349-
let id: UUID = UUID()
350-
let diagnostic: Diagnostic
351-
let fileUri: DocumentUri
352-
353-
var name: String {
354-
diagnostic.message.trimmingCharacters(in: .newlines)
355-
}
356-
357-
var isExpandable: Bool {
358-
false
359-
}
360-
361-
var nsIcon: NSImage {
362-
switch diagnostic.severity {
363-
case .error:
364-
return NSImage(
365-
systemSymbolName: "xmark.octagon.fill",
366-
accessibilityDescription: "Error"
367-
)!
368-
case .warning:
369-
return NSImage(systemSymbolName: "exclamationmark.triangle.fill", accessibilityDescription: "Warning")!
370-
case .information:
371-
return NSImage(systemSymbolName: "exclamationmark.triangle.fill", accessibilityDescription: "Information")!
372-
case .hint:
373-
return NSImage(systemSymbolName: "lightbulb.fill", accessibilityDescription: "Hint")!
374-
case nil:
375-
return NSImage(systemSymbolName: "circle.fill", accessibilityDescription: "Unknown Issue Type")!
376-
}
377-
}
378-
379-
var severityColor: NSColor {
380-
switch diagnostic.severity {
381-
case .error:
382-
return .errorRed
383-
case .warning:
384-
return .warningYellow
385-
case .information:
386-
return .blue
387-
case .hint:
388-
return .gray
389-
case nil:
390-
return .secondaryLabelColor
391-
}
392-
}
393-
394-
var locationString: String {
395-
"Line \(diagnostic.range.start.line + 1), Column \(diagnostic.range.start.character + 1)"
396-
}
397-
398-
init(diagnostic: Diagnostic, fileUri: DocumentUri) {
399-
self.diagnostic = diagnostic
400-
self.fileUri = fileUri
401-
}
402-
403-
static func == (lhs: DiagnosticIssueNode, rhs: DiagnosticIssueNode) -> Bool {
404-
lhs.id == rhs.id
405-
}
406-
407-
func hash(into hasher: inout Hasher) {
408-
hasher.combine(id)
409-
}
410-
}
411-
412230
/// Options for filtering diagnostics in the issue navigator
413231
struct IssueFilterOptions {
414232
var showErrors: Bool = true

0 commit comments

Comments
 (0)