aboutsummaryrefslogtreecommitdiff
path: root/Sources
diff options
context:
space:
mode:
authorRuben Beltran del Rio <jj@r.bdr.sh>2026-06-16 15:22:08 +0200
committerRuben Beltran del Rio <jj@r.bdr.sh>2026-06-16 15:22:08 +0200
commite5e024a5f4c8709cf2a28dc3bfab79d8037516e1 (patch)
treeb458cc77b4bbd0580ed5248e90e78148b697199c /Sources
parent3402f5764f794a60f85a152a13c4eacaa2a719f6 (diff)
Support all bare modifiers1.0.0
Diffstat (limited to 'Sources')
-rw-r--r--Sources/NorgKeyboardToolbar/EditorSnippet.swift29
1 files changed, 28 insertions, 1 deletions
diff --git a/Sources/NorgKeyboardToolbar/EditorSnippet.swift b/Sources/NorgKeyboardToolbar/EditorSnippet.swift
index b87d2b1..4773eac 100644
--- a/Sources/NorgKeyboardToolbar/EditorSnippet.swift
+++ b/Sources/NorgKeyboardToolbar/EditorSnippet.swift
@@ -29,7 +29,7 @@ enum EditorSnippet: String, CaseIterable, Identifiable, Sendable {
switch self {
case .heading where isInBareMarker(characters, at: position, markers: ["*"]):
return promoteHeading(characters, at: position)
- case .task where isInBareMarker(characters, at: position, markers: ["*", "~"]):
+ case .task where isInBareDetachedModifier(characters, at: position):
return addTask(toMarker: characters, at: position)
default:
return insertOnNewLine(in: characters, cursor: position)
@@ -38,6 +38,11 @@ enum EditorSnippet: String, CaseIterable, Identifiable, Sendable {
// MARK: - Marker-aware behaviours
+ /// The detached-modifier markers that can carry a task status, matching
+ /// NorgKit's task scanner. Any of these — headings, un/ordered lists,
+ /// quotes, definitions, footnotes — may be turned into a task in place.
+ private static let detachedModifierMarkers: Set<Character> = ["*", "-", "~", ">", "$", "^", ":"]
+
/// Whether the is at a position with only `markers` and spaces, and contains
/// at least one marker.
private func isInBareMarker(_ characters: [Character], at position: Int, markers: Set<Character>)
@@ -48,6 +53,28 @@ enum EditorSnippet: String, CaseIterable, Identifiable, Sendable {
&& prefix.allSatisfy { markers.contains($0) || $0 == " " }
}
+ /// Whether the cursor sits just past a bare detached modifier: leading
+ /// spaces, a run of a single marker, then at least one space, with nothing
+ /// else before the cursor. The trailing space requirement keeps delimiters
+ /// such as `---` (which carry no whitespace) from being treated as tasks.
+ private func isInBareDetachedModifier(_ characters: [Character], at position: Int) -> Bool {
+ let lineStart = LineScanner.lineStart(in: characters, at: position)
+ var index = lineStart
+ while index < position, characters[index] == " " { index += 1 }
+
+ guard index < position, Self.detachedModifierMarkers.contains(characters[index]) else {
+ return false
+ }
+ let marker = characters[index]
+ while index < position, characters[index] == marker { index += 1 }
+
+ // A space must separate the marker run from the cursor, and the cursor may
+ // only sit within that run of separating spaces (i.e. before any content).
+ guard index < position, characters[index] == " " else { return false }
+ while index < position, characters[index] == " " { index += 1 }
+ return index == position
+ }
+
/// Adds a `*` after the leading run of spaces and stars on the cursor's line.
private func promoteHeading(_ characters: [Character], at position: Int) -> (
text: String, cursor: Int