aboutsummaryrefslogtreecommitdiffstats
path: root/WireGuard/WireGuard/UI/macOS/View
diff options
context:
space:
mode:
authorEric Kuck <eric@bluelinelabs.com>2019-01-07 14:47:27 +0200
committerRoopesh Chander <roop@roopc.net>2019-01-14 14:52:34 +0530
commit59bfa7f1df470af711187335f604422dfafca634 (patch)
treebcc80efb0af5a800fc830837616c63d06301a878 /WireGuard/WireGuard/UI/macOS/View
parentmacOS: Tunnel edit view (diff)
downloadwireguard-apple-59bfa7f1df470af711187335f604422dfafca634.tar.xz
wireguard-apple-59bfa7f1df470af711187335f604422dfafca634.zip
Added syntax highlighting conf textview
Signed-off-by: Eric Kuck <eric@bluelinelabs.com>
Diffstat (limited to 'WireGuard/WireGuard/UI/macOS/View')
-rw-r--r--WireGuard/WireGuard/UI/macOS/View/ConfTextStorage.swift174
-rw-r--r--WireGuard/WireGuard/UI/macOS/View/ConfTextView.swift57
2 files changed, 231 insertions, 0 deletions
diff --git a/WireGuard/WireGuard/UI/macOS/View/ConfTextStorage.swift b/WireGuard/WireGuard/UI/macOS/View/ConfTextStorage.swift
new file mode 100644
index 0000000..2db3d87
--- /dev/null
+++ b/WireGuard/WireGuard/UI/macOS/View/ConfTextStorage.swift
@@ -0,0 +1,174 @@
+// SPDX-License-Identifier: MIT
+// Copyright © 2018 WireGuard LLC. All Rights Reserved.
+
+import Cocoa
+
+class ConfTextStorage: NSTextStorage {
+
+ struct TextColorTheme {
+ let black: NSColor
+ let red: NSColor
+ let green: NSColor
+ let yellow: NSColor
+ let blue: NSColor
+ let magenta: NSColor
+ let cyan: NSColor
+ let white: NSColor
+ let `default`: NSColor
+ }
+
+ let defaultFont = NSFont.systemFont(ofSize: 16)
+ private let boldFont = NSFont.boldSystemFont(ofSize: 16)
+
+ private var defaultAttributes: [NSAttributedString.Key: Any]! //swiftlint:disable:this implicitly_unwrapped_optional
+ private var highlightAttributes: [UInt32: [NSAttributedString.Key: Any]]! //swiftlint:disable:this implicitly_unwrapped_optional
+
+ private let backingStore: NSMutableAttributedString
+ private(set) var hasError = false
+
+ override init() {
+ backingStore = NSMutableAttributedString(string: "")
+ super.init()
+ }
+
+ required init?(coder aDecoder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
+ required init?(pasteboardPropertyList propertyList: Any, ofType type: NSPasteboard.PasteboardType) {
+ fatalError("init(pasteboardPropertyList:ofType:) has not been implemented")
+ }
+
+ //swiftlint:disable:next function_body_length
+ func updateAttributes(for theme: TextColorTheme) {
+ self.defaultAttributes = [
+ .foregroundColor: theme.default,
+ .font: defaultFont
+ ]
+
+ self.highlightAttributes = [
+ HighlightSection.rawValue: [
+ .foregroundColor: theme.black,
+ .font: boldFont
+ ],
+ HighlightKeytype.rawValue: [
+ .foregroundColor: theme.blue,
+ .font: boldFont
+ ],
+ HighlightKey.rawValue: [
+ .foregroundColor: theme.yellow,
+ .font: boldFont
+ ],
+ HighlightCmd.rawValue: [
+ .foregroundColor: theme.white,
+ .font: defaultFont
+ ],
+ HighlightIP.rawValue: [
+ .foregroundColor: theme.green,
+ .font: defaultFont
+ ],
+ HighlightCidr.rawValue: [
+ .foregroundColor: theme.yellow,
+ .font: defaultFont
+ ],
+ HighlightHost.rawValue: [
+ .foregroundColor: theme.green,
+ .font: boldFont
+ ],
+ HighlightPort.rawValue: [
+ .foregroundColor: theme.magenta,
+ .font: defaultFont
+ ],
+ HighlightTable.rawValue: [
+ .foregroundColor: theme.blue,
+ .font: defaultFont
+ ],
+ HighlightFwMark.rawValue: [
+ .foregroundColor: theme.blue,
+ .font: defaultFont
+ ],
+ HighlightMTU.rawValue: [
+ .foregroundColor: theme.blue,
+ .font: defaultFont
+ ],
+ HighlightSaveConfig.rawValue: [
+ .foregroundColor: theme.blue,
+ .font: defaultFont
+ ],
+ HighlightKeepalive.rawValue: [
+ .foregroundColor: theme.blue,
+ .font: defaultFont
+ ],
+ HighlightComment.rawValue: [
+ .foregroundColor: theme.cyan,
+ .font: defaultFont
+ ],
+ HighlightDelimiter.rawValue: [
+ .foregroundColor: theme.cyan,
+ .font: defaultFont
+ ],
+ HighlightError.rawValue: [
+ .foregroundColor: theme.red,
+ .font: defaultFont,
+ .underlineStyle: 1
+ ]
+ ]
+
+ highlightSyntax()
+ }
+
+ override var string: String {
+ return backingStore.string
+ }
+
+ override func attributes(at location: Int, effectiveRange range: NSRangePointer?) -> [NSAttributedString.Key: Any] {
+ return backingStore.attributes(at: location, effectiveRange: range)
+ }
+
+ override func replaceCharacters(in range: NSRange, with str: String) {
+ beginEditing()
+ backingStore.replaceCharacters(in: range, with: str)
+ edited(.editedCharacters, range: range, changeInLength: str.count - range.length)
+ endEditing()
+ }
+
+ override func replaceCharacters(in range: NSRange, with attrString: NSAttributedString) {
+ beginEditing()
+ backingStore.replaceCharacters(in: range, with: attrString)
+ edited(.editedCharacters, range: range, changeInLength: attrString.length - range.length)
+ endEditing()
+ }
+
+ override func setAttributes(_ attrs: [NSAttributedString.Key: Any]?, range: NSRange) {
+ beginEditing()
+ backingStore.setAttributes(attrs, range: range)
+ edited(.editedAttributes, range: range, changeInLength: 0)
+ endEditing()
+ }
+
+ func highlightSyntax() {
+ hasError = false
+
+ backingStore.beginEditing()
+ var spans = highlight_config(backingStore.string.cString(using: String.Encoding.utf8))!
+
+ while spans.pointee.type != HighlightEnd {
+ let span = spans.pointee
+
+ let attributes = self.highlightAttributes[span.type.rawValue] ?? defaultAttributes
+ backingStore.setAttributes(attributes, range: NSRange(location: span.start, length: span.len))
+
+ if span.type == HighlightError {
+ hasError = true
+ }
+
+ spans = spans.successor()
+ }
+ backingStore.endEditing()
+
+ beginEditing()
+ edited(.editedAttributes, range: NSRange(location: 0, length: (backingStore.string as NSString).length), changeInLength: 0)
+ endEditing()
+ }
+
+}
diff --git a/WireGuard/WireGuard/UI/macOS/View/ConfTextView.swift b/WireGuard/WireGuard/UI/macOS/View/ConfTextView.swift
new file mode 100644
index 0000000..8526e6c
--- /dev/null
+++ b/WireGuard/WireGuard/UI/macOS/View/ConfTextView.swift
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: MIT
+// Copyright © 2018 WireGuard LLC. All Rights Reserved.
+
+import Cocoa
+
+class ConfTextView: NSTextView {
+
+ private let confTextStorage = ConfTextStorage()
+
+ var hasError: Bool { return confTextStorage.hasError }
+
+ override var string: String {
+ didSet {
+ confTextStorage.highlightSyntax()
+ }
+ }
+
+ init() {
+ let textContainer = NSTextContainer()
+ let layoutManager = NSLayoutManager()
+ layoutManager.addTextContainer(textContainer)
+ confTextStorage.addLayoutManager(layoutManager)
+ super.init(frame: CGRect(x: 0, y: 0, width: 1, height: 60), textContainer: textContainer)
+ font = confTextStorage.defaultFont
+ updateTheme()
+ delegate = self
+ }
+
+ required init?(coder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
+ override func viewDidChangeEffectiveAppearance() {
+ updateTheme()
+ }
+
+ private func updateTheme() {
+ let theme: ConfTextStorage.TextColorTheme
+ switch effectiveAppearance.bestMatch(from: [.aqua, .darkAqua]) ?? .aqua {
+ case .darkAqua:
+ theme = ConfTextStorage.TextColorTheme(black: NSColor(hex: "#c7c7c7"), red: NSColor(hex: "#dc322f"), green: NSColor(hex: "#859900"), yellow: NSColor(hex: "#c7c400"), blue: NSColor(hex: "#268bd2"), magenta: NSColor(hex: "#d33682"), cyan: NSColor(hex: "#2aa198"), white: NSColor(hex: "#383838"), default: NSColor(hex: "#c7c7c7"))
+ default:
+ theme = ConfTextStorage.TextColorTheme(black: NSColor(hex: "#000000"), red: NSColor(hex: "#c91b00"), green: NSColor(hex: "#00c200"), yellow: NSColor(hex: "#c7c400"), blue: NSColor(hex: "#0225c7"), magenta: NSColor(hex: "#c930c7"), cyan: NSColor(hex: "#00c5c7"), white: NSColor(hex: "#c7c7c7"), default: NSColor(hex: "#000000"))
+ }
+ confTextStorage.updateAttributes(for: theme)
+ }
+
+}
+
+extension ConfTextView: NSTextViewDelegate {
+
+ func textDidChange(_ notification: Notification) {
+ confTextStorage.highlightSyntax()
+ needsDisplay = true
+ }
+
+}