Skip to content

Commit b5b5a8f

Browse files
committed
Add Bold and Italics Support To Themes
1 parent 2810b76 commit b5b5a8f

File tree

4 files changed

+92
-67
lines changed

4 files changed

+92
-67
lines changed

Example/CodeEditSourceEditorExample/CodeEditSourceEditorExample/Extensions/EditorTheme+Default.swift

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,22 @@ import CodeEditSourceEditor
1212
extension EditorTheme {
1313
static var standard: EditorTheme {
1414
EditorTheme(
15-
text: .init(hex: "000000"),
16-
insertionPoint: .init(hex: "000000"),
17-
invisibles: .init(hex: "D6D6D6"),
18-
background: .init(hex: "FFFFFF"),
19-
lineHighlight: .init(hex: "ECF5FF"),
20-
selection: .init(hex: "B2D7FF"),
21-
keywords: .init(hex: "9B2393"),
22-
commands: .init(hex: "326D74"),
23-
types: .init(hex: "0B4F79"),
24-
attributes: .init(hex: "815F03"),
25-
variables: .init(hex: "0F68A0"),
26-
values: .init(hex: "6C36A9"),
27-
numbers: .init(hex: "1C00CF"),
28-
strings: .init(hex: "C41A16"),
29-
characters: .init(hex: "1C00CF"),
30-
comments: .init(hex: "267507")
15+
text: Attribute(color: NSColor(hex: "000000")),
16+
insertionPoint: NSColor(hex: "000000"),
17+
invisibles: Attribute(color: NSColor(hex: "D6D6D6")),
18+
background: NSColor(hex: "FFFFFF"),
19+
lineHighlight: NSColor(hex: "ECF5FF"),
20+
selection: NSColor(hex: "B2D7FF"),
21+
keywords: Attribute(color: NSColor(hex: "9B2393"), bold: true),
22+
commands: Attribute(color: NSColor(hex: "326D74")),
23+
types: Attribute(color: NSColor(hex: "0B4F79")),
24+
attributes: Attribute(color: NSColor(hex: "815F03")),
25+
variables: Attribute(color: NSColor(hex: "0F68A0")),
26+
values: Attribute(color: NSColor(hex: "6C36A9")),
27+
numbers: Attribute(color: NSColor(hex: "1C00CF")),
28+
strings: Attribute(color: NSColor(hex: "C41A16"), bold: true, italic: true),
29+
characters: Attribute(color: NSColor(hex: "1C00CF")),
30+
comments: Attribute(color: NSColor(hex: "267507"), italic: true)
3131
)
3232
}
3333
}

Sources/CodeEditSourceEditor/Controller/TextViewController+Highlighter.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ extension TextViewController {
2929
extension TextViewController: ThemeAttributesProviding {
3030
public func attributesFor(_ capture: CaptureName?) -> [NSAttributedString.Key: Any] {
3131
[
32-
.font: font,
32+
.font: theme.fontFor(for: capture, from: font),
3333
.foregroundColor: theme.colorFor(capture),
3434
.kern: textView.kern
3535
]

Sources/CodeEditSourceEditor/Controller/TextViewController.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ public class TextViewController: NSViewController {
262262
self.textView = TextView(
263263
string: string,
264264
font: font,
265-
textColor: theme.text,
265+
textColor: theme.text.color,
266266
lineHeightMultiplier: lineHeightMultiple,
267267
wrapLines: wrapLines,
268268
isEditable: isEditable,

Sources/CodeEditSourceEditor/Theme/EditorTheme.swift

Lines changed: 74 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -7,43 +7,67 @@
77

88
import SwiftUI
99

10-
/// A collection of `NSColor` used for syntax higlighting
11-
public struct EditorTheme {
10+
/// A collection of attributes used for syntax highlighting and other colors for the editor.
11+
///
12+
/// Attributes of a theme that do not apply to text (background, line highlight) are a single `NSColor` for simplicity.
13+
/// All other attributes use the ``EditorTheme/Attribute`` type to store
14+
public struct EditorTheme: Equatable {
15+
/// Represents attributes that can be applied to style text.
16+
public struct Attribute: Equatable, Hashable, Sendable {
17+
let color: NSColor
18+
let bold: Bool
19+
let italic: Bool
1220

13-
public var text: NSColor
21+
public init(color: NSColor, bold: Bool = false, italic: Bool = false) {
22+
self.color = color
23+
self.bold = bold
24+
self.italic = italic
25+
}
26+
27+
var fontDescriptorTraits: NSFontDescriptor.SymbolicTraits {
28+
switch (bold, italic) {
29+
case (true, true): return [.bold, .italic]
30+
case (true, false): return [.bold]
31+
case (false, true): return [.italic]
32+
case (false, false): return []
33+
}
34+
}
35+
}
36+
37+
public var text: Attribute
1438
public var insertionPoint: NSColor
15-
public var invisibles: NSColor
39+
public var invisibles: Attribute
1640
public var background: NSColor
1741
public var lineHighlight: NSColor
1842
public var selection: NSColor
19-
public var keywords: NSColor
20-
public var commands: NSColor
21-
public var types: NSColor
22-
public var attributes: NSColor
23-
public var variables: NSColor
24-
public var values: NSColor
25-
public var numbers: NSColor
26-
public var strings: NSColor
27-
public var characters: NSColor
28-
public var comments: NSColor
43+
public var keywords: Attribute
44+
public var commands: Attribute
45+
public var types: Attribute
46+
public var attributes: Attribute
47+
public var variables: Attribute
48+
public var values: Attribute
49+
public var numbers: Attribute
50+
public var strings: Attribute
51+
public var characters: Attribute
52+
public var comments: Attribute
2953

3054
public init(
31-
text: NSColor,
55+
text: Attribute,
3256
insertionPoint: NSColor,
33-
invisibles: NSColor,
57+
invisibles: Attribute,
3458
background: NSColor,
3559
lineHighlight: NSColor,
3660
selection: NSColor,
37-
keywords: NSColor,
38-
commands: NSColor,
39-
types: NSColor,
40-
attributes: NSColor,
41-
variables: NSColor,
42-
values: NSColor,
43-
numbers: NSColor,
44-
strings: NSColor,
45-
characters: NSColor,
46-
comments: NSColor
61+
keywords: Attribute,
62+
commands: Attribute,
63+
types: Attribute,
64+
attributes: Attribute,
65+
variables: Attribute,
66+
values: Attribute,
67+
numbers: Attribute,
68+
strings: Attribute,
69+
characters: Attribute,
70+
comments: Attribute
4771
) {
4872
self.text = text
4973
self.insertionPoint = insertionPoint
@@ -63,10 +87,10 @@ public struct EditorTheme {
6387
self.comments = comments
6488
}
6589

66-
/// Get the color from ``theme`` for the specified capture name.
67-
/// - Parameter capture: The capture name
68-
/// - Returns: A `NSColor`
69-
func colorFor(_ capture: CaptureName?) -> NSColor {
90+
/// Maps a capture type to the attributes for that capture determined by the theme.
91+
/// - Parameter capture: The capture to map to.
92+
/// - Returns: Theme attributes for the capture.
93+
private func mapCapture(_ capture: CaptureName?) -> Attribute {
7094
switch capture {
7195
case .include, .constructor, .keyword, .boolean, .variableBuiltin,
7296
.keywordReturn, .keywordFunction, .repeat, .conditional, .tag:
@@ -82,25 +106,26 @@ public struct EditorTheme {
82106
default: return text
83107
}
84108
}
85-
}
86109

87-
extension EditorTheme: Equatable {
88-
public static func == (lhs: EditorTheme, rhs: EditorTheme) -> Bool {
89-
return lhs.text == rhs.text &&
90-
lhs.insertionPoint == rhs.insertionPoint &&
91-
lhs.invisibles == rhs.invisibles &&
92-
lhs.background == rhs.background &&
93-
lhs.lineHighlight == rhs.lineHighlight &&
94-
lhs.selection == rhs.selection &&
95-
lhs.keywords == rhs.keywords &&
96-
lhs.commands == rhs.commands &&
97-
lhs.types == rhs.types &&
98-
lhs.attributes == rhs.attributes &&
99-
lhs.variables == rhs.variables &&
100-
lhs.values == rhs.values &&
101-
lhs.numbers == rhs.numbers &&
102-
lhs.strings == rhs.strings &&
103-
lhs.characters == rhs.characters &&
104-
lhs.comments == rhs.comments
110+
/// Get the color from ``theme`` for the specified capture name.
111+
/// - Parameter capture: The capture name
112+
/// - Returns: A `NSColor`
113+
func colorFor(_ capture: CaptureName?) -> NSColor {
114+
return mapCapture(capture).color
115+
}
116+
117+
/// Returns the correct font with attributes (bold and italics) for a given capture name.
118+
/// - Parameters:
119+
/// - capture: The capture name.
120+
/// - font: The font to add attributes to.
121+
/// - Returns: A new font that has the correct attributes for the capture.
122+
func fontFor(for capture: CaptureName?, from font: NSFont) -> NSFont {
123+
let attributes = mapCapture(capture)
124+
guard attributes.bold || attributes.italic else {
125+
return font
126+
}
127+
128+
let descriptor = font.fontDescriptor.withSymbolicTraits(attributes.fontDescriptorTraits)
129+
return NSFont(descriptor: descriptor, size: font.pointSize) ?? font
105130
}
106131
}

0 commit comments

Comments
 (0)