feat: improve note formatting shortcuts and code styling
This commit is contained in:
@@ -25,9 +25,10 @@ final class NotesController: NSViewController, NSTextViewDelegate {
|
||||
private let formatting = NSStackView()
|
||||
private static let formattingKeys: [(key: String, modifiers: NSEvent.ModifierFlags)] = [
|
||||
("h", [.command, .shift]), ("b", .command), ("i", .command),
|
||||
("x", [.command, .shift]), ("e", .command), ("k", [.command, .shift]),
|
||||
("s", [.command, .shift]), ("e", .command), ("k", [.command, .shift]),
|
||||
("e", [.command, .shift]), ("b", [.command, .shift]),
|
||||
("o", [.command, .shift]), ("u", [.command, .shift]), ("t", [.command, .shift]),
|
||||
("o", [.command, .shift]), ("l", [.command, .shift]), ("t", [.command, .shift]),
|
||||
("u", [.command, .shift]),
|
||||
]
|
||||
private let defaults: UserDefaults
|
||||
private var store: NotesStore?
|
||||
@@ -85,6 +86,7 @@ final class NotesController: NSViewController, NSTextViewDelegate {
|
||||
("strikethrough", "Strikethrough"), ("chevron.left.forwardslash.chevron.right", "Inline code"),
|
||||
("link", "Link"), ("curlybraces.square", "Code block"), ("text.quote", "Quote"),
|
||||
("list.number", "Ordered list"), ("list.bullet", "Bullet list"), ("checklist", "Checklist"),
|
||||
("underline", "Underline"),
|
||||
]
|
||||
for (index, tool) in tools.enumerated() {
|
||||
let button = iconButton(tool.0, label: tool.1, action: #selector(formatNote(_:)))
|
||||
@@ -219,7 +221,7 @@ final class NotesController: NSViewController, NSTextViewDelegate {
|
||||
if selection.length > 0, source.character(at: NSMaxRange(selection) - 1) == 10 { selection.length -= 1 }
|
||||
}
|
||||
let wrappers = [1: ("**", "**"), 2: ("*", "*"), 3: ("~~", "~~"), 4: ("`", "`"),
|
||||
5: ("[", "](url)"), 6: ("```\n", "\n```")]
|
||||
5: ("[", "](url)"), 6: ("```\n", "\n```"), 11: ("<u>", "</u>")]
|
||||
if let (open, close) = wrappers[sender.tag] {
|
||||
let before = selection.location - open.utf16.count
|
||||
let after = NSMaxRange(selection)
|
||||
@@ -677,12 +679,14 @@ private final class RoundedImageAttachmentCell: NSTextAttachmentCell {
|
||||
enum MarkdownHighlighting {
|
||||
// ponytail: whole-note highlighting; incremental parsing if large notes make typing slow.
|
||||
static let hiddenMarkup = NSAttributedString.Key("Conjure.hiddenMarkup")
|
||||
static let codeBackground = NSAttributedString.Key("Conjure.codeBackground")
|
||||
private static let inlineCode = try! NSRegularExpression(pattern: "(?<![\\\\`])(?<marker>`+)(?<body>[^`\\n]+)\\k<marker>(?!`)")
|
||||
private static let rules: [(NSRegularExpression, [NSAttributedString.Key: Any])] = [
|
||||
(try! NSRegularExpression(pattern: "(?<![\\\\*_])(?<marker>\\*{2,3}|_{2,3})(?<body>\\S(?:[^\\n]*?\\S)?)\\k<marker>(?![*_])"), [.font: NSFont.monospacedSystemFont(ofSize: NotesAppearance.font.pointSize, weight: .bold)]),
|
||||
(try! NSRegularExpression(pattern: "(?<![\\\\*_])(?<marker>[*_])(?<body>[^\\s*_](?:[^*_\\n]*?[^\\s*_])?)\\k<marker>(?![*_])"), [.font: NSFontManager.shared.convert(NotesAppearance.font, toHaveTrait: .italicFontMask)]),
|
||||
(try! NSRegularExpression(pattern: "(?<!\\\\)!?\\[(?<body>[^\\]\\n]+)\\]\\([^\\n)]+\\)|(?m)^\\s*(?:[-+*]|[0-9]+\\.)\\s"), [.foregroundColor: SunsetPalette.accent]),
|
||||
(try! NSRegularExpression(pattern: "(?<!\\\\)~~(?<body>\\S(?:[^\\n]*?\\S)?)~~"), [.strikethroughStyle: NSUnderlineStyle.single.rawValue]),
|
||||
(try! NSRegularExpression(pattern: "(?<!\\\\)<u>(?<body>[^\\n]+?)</u>"), [.underlineStyle: NSUnderlineStyle.single.rawValue]),
|
||||
(try! NSRegularExpression(pattern: "(?m)^(?:>[ \\t]*)+(?<body>[^\\n]+)"), [:]),
|
||||
]
|
||||
private static let heading = try! NSRegularExpression(pattern: "(?m)^(#{1,6}) (?<body>.+)$")
|
||||
@@ -717,6 +721,14 @@ enum MarkdownHighlighting {
|
||||
return blocks
|
||||
}
|
||||
|
||||
static func removeCodeBackground(from contents: NSMutableAttributedString) {
|
||||
let range = NSRange(location: 0, length: contents.length)
|
||||
contents.enumerateAttribute(codeBackground, in: range) { value, run, _ in
|
||||
if value as? Bool == true { contents.removeAttribute(.backgroundColor, range: run) }
|
||||
}
|
||||
contents.removeAttribute(codeBackground, range: range)
|
||||
}
|
||||
|
||||
static func apply(to editor: NSTextView) {
|
||||
guard let storage = editor.textStorage else { return }
|
||||
let text = editor.string
|
||||
@@ -735,6 +747,9 @@ enum MarkdownHighlighting {
|
||||
}
|
||||
}
|
||||
storage.removeAttribute(.strikethroughStyle, range: range)
|
||||
storage.removeAttribute(.underlineStyle, range: range)
|
||||
removeCodeBackground(from: storage)
|
||||
storage.addAttribute(codeBackground, value: false, range: range)
|
||||
storage.addAttribute(hiddenMarkup, value: false, range: range)
|
||||
storage.addAttributes([.font: NotesAppearance.font, .foregroundColor: SunsetPalette.text,
|
||||
.paragraphStyle: NotesAppearance.paragraph], range: range)
|
||||
@@ -755,7 +770,9 @@ enum MarkdownHighlighting {
|
||||
!blocks.contains { NSIntersectionRange($0.range, match.range).length > 0 }
|
||||
}
|
||||
for match in codeSpans {
|
||||
storage.addAttributes([.font: NotesAppearance.font, .foregroundColor: NSColor.systemGreen], range: match.range)
|
||||
let body = match.range(withName: "body")
|
||||
storage.addAttributes([.font: NotesAppearance.font, .foregroundColor: SunsetPalette.accent,
|
||||
.backgroundColor: SunsetPalette.selectionFill, codeBackground: true], range: body)
|
||||
hideSyntax(match)
|
||||
}
|
||||
for (expression, attributes) in rules {
|
||||
@@ -781,15 +798,6 @@ enum MarkdownHighlighting {
|
||||
}
|
||||
}
|
||||
for block in blocks {
|
||||
let source = text as NSString
|
||||
let opening = source.lineRange(for: NSRange(location: block.range.location, length: 0))
|
||||
let openingText = source.substring(with: opening).trimmingCharacters(in: .newlines)
|
||||
storage.addAttribute(hiddenMarkup, value: true,
|
||||
range: NSRange(location: opening.location, length: openingText.utf16.count))
|
||||
if NSMaxRange(block.body) < NSMaxRange(block.range) {
|
||||
storage.addAttribute(hiddenMarkup, value: true,
|
||||
range: NSRange(location: NSMaxRange(block.body), length: NSMaxRange(block.range) - NSMaxRange(block.body)))
|
||||
}
|
||||
storage.addAttributes([.font: NotesAppearance.font,
|
||||
.foregroundColor: SunsetPalette.secondaryText], range: block.range)
|
||||
storage.addAttribute(.foregroundColor, value: SunsetPalette.text, range: block.body)
|
||||
|
||||
Reference in New Issue
Block a user