Skip to content

Commit c25bbac

Browse files
committed
Merge branch 'main' into feat/editor-configuration
2 parents c23027b + c2fdc98 commit c25bbac

File tree

10 files changed

+472
-7
lines changed

10 files changed

+472
-7
lines changed

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

Lines changed: 113 additions & 0 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
@@ -30,6 +30,7 @@ struct ContentView: View {
3030
@AppStorage("showGutter") private var showGutter: Bool = true
3131
@AppStorage("showMinimap") private var showMinimap: Bool = true
3232
@AppStorage("showReformattingGuide") private var showReformattingGuide: Bool = false
33+
@State private var invisibleCharactersConfig: InvisibleCharactersConfig = .empty
3334

3435
@State private var isInLongParse = false
3536
@State private var settingsIsPresented: Bool = false
@@ -79,7 +80,8 @@ struct ContentView: View {
7980
showMinimap: $showMinimap,
8081
indentOption: $indentOption,
8182
reformatAtColumn: $reformatAtColumn,
82-
showReformattingGuide: $showReformattingGuide
83+
showReformattingGuide: $showReformattingGuide,
84+
invisibles: $invisibleCharactersConfig
8385
)
8486
}
8587
.ignoresSafeArea()

Example/CodeEditSourceEditorExample/CodeEditSourceEditorExample/Views/StatusBar.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ struct StatusBar: View {
2727
@Binding var indentOption: IndentOption
2828
@Binding var reformatAtColumn: Int
2929
@Binding var showReformattingGuide: Bool
30+
@Binding var invisibles: InvisibleCharactersConfig
3031

3132
var body: some View {
3233
HStack {
@@ -52,6 +53,33 @@ struct StatusBar: View {
5253
.disabled(true)
5354
.help("macOS 14 required")
5455
}
56+
57+
Menu {
58+
Toggle("Spaces", isOn: $invisibles.showSpaces)
59+
Toggle("Tabs", isOn: $invisibles.showTabs)
60+
Toggle("Line Endings", isOn: $invisibles.showLineEndings)
61+
Divider()
62+
Toggle(
63+
"Warning Characters",
64+
isOn: Binding(
65+
get: {
66+
!invisibles.warningCharacters.isEmpty
67+
},
68+
set: { newValue in
69+
// In this example app, we only add one character
70+
// For real apps, consider providing a table where users can add UTF16
71+
// char codes to warn about, as well as a set of good defaults.
72+
if newValue {
73+
invisibles.warningCharacters.insert(0x200B) // zero-width space
74+
} else {
75+
invisibles.warningCharacters.removeAll()
76+
}
77+
}
78+
)
79+
)
80+
} label: {
81+
Text("Invisibles")
82+
}
5583
} label: {}
5684
.background {
5785
Image(systemName: "switch.2")

Package.resolved

Lines changed: 2 additions & 2 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.11.1"
20+
from: "0.11.2"
2121
),
2222
// tree-sitter languages
2323
.package(

Sources/CodeEditSourceEditor/Controller/TextViewController.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,8 @@ public class TextViewController: NSViewController {
209209
delegate: self
210210
)
211211

212+
textView.layoutManager.invisibleCharacterDelegate = invisibleCharactersCoordinator
213+
212214
coordinators.forEach {
213215
$0.prepareCoordinator(controller: self)
214216
}
@@ -255,4 +257,4 @@ public class TextViewController: NSViewController {
255257
}
256258
localEvenMonitor = nil
257259
}
258-
}
260+
} // swiftlint:disable:this file_length
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
//
2+
// InvisibleCharactersConfig.swift
3+
// CodeEditSourceEditor
4+
//
5+
// Created by Khan Winter on 6/11/25.
6+
//
7+
8+
/// Configuration for how the editor draws invisible characters.
9+
///
10+
/// Enable specific categories using the ``showSpaces``, ``showTabs``, and ``showLineEndings`` toggles. Customize
11+
/// drawing further with the ``spaceReplacement`` and family variables.
12+
public struct InvisibleCharactersConfig: Equatable, Hashable, Sendable, Codable {
13+
/// An empty configuration.
14+
public static var empty: InvisibleCharactersConfig {
15+
InvisibleCharactersConfig(showSpaces: false, showTabs: false, showLineEndings: false)
16+
}
17+
18+
/// Set to true to draw spaces with a dot.
19+
public var showSpaces: Bool
20+
21+
/// Set to true to draw tabs with a small arrow.
22+
public var showTabs: Bool
23+
24+
/// Set to true to draw line endings.
25+
public var showLineEndings: Bool
26+
27+
/// Replacement when drawing the space character, enabled by ``showSpaces``.
28+
public var spaceReplacement: String = "·"
29+
/// Replacement when drawing the tab character, enabled by ``showTabs``.
30+
public var tabReplacement: String = ""
31+
/// Replacement when drawing the carriage return character, enabled by ``showLineEndings``.
32+
public var carriageReturnReplacement: String = ""
33+
/// Replacement when drawing the line feed character, enabled by ``showLineEndings``.
34+
public var lineFeedReplacement: String = "¬"
35+
/// Replacement when drawing the paragraph separator character, enabled by ``showLineEndings``.
36+
public var paragraphSeparatorReplacement: String = ""
37+
/// Replacement when drawing the line separator character, enabled by ``showLineEndings``.
38+
public var lineSeparatorReplacement: String = ""
39+
40+
public init(showSpaces: Bool, showTabs: Bool, showLineEndings: Bool) {
41+
self.showSpaces = showSpaces
42+
self.showTabs = showTabs
43+
self.showLineEndings = showLineEndings
44+
}
45+
46+
/// Determines what characters should trigger a custom drawing action.
47+
func triggerCharacters() -> Set<UInt16> {
48+
var set = Set<UInt16>()
49+
50+
if showSpaces {
51+
set.insert(Symbols.space)
52+
}
53+
54+
if showTabs {
55+
set.insert(Symbols.tab)
56+
}
57+
58+
if showLineEndings {
59+
set.insert(Symbols.lineFeed)
60+
set.insert(Symbols.carriageReturn)
61+
set.insert(Symbols.paragraphSeparator)
62+
set.insert(Symbols.lineSeparator)
63+
}
64+
65+
return set
66+
}
67+
68+
/// Some commonly used whitespace symbols in their unichar representation.
69+
public enum Symbols {
70+
public static let space: UInt16 = 0x20
71+
public static let tab: UInt16 = 0x9
72+
public static let lineFeed: UInt16 = 0xA // \n
73+
public static let carriageReturn: UInt16 = 0xD // \r
74+
public static let paragraphSeparator: UInt16 = 0x2029 // ¶
75+
public static let lineSeparator: UInt16 = 0x2028 // line separator
76+
}
77+
}

0 commit comments

Comments
 (0)