Sources/OrgDocument/Buffer.swift
41 lines · 1545 bytes
6 symbols in this file
1import Foundation
2import OrgCore
3
4/// Where an open document's live state is kept: the editor while one shows it, a
5/// `StateBuffer` before that.
6@MainActor
7public protocol DocumentBuffer: AnyObject {
8 var document: DocumentState { get }
9 /// Selected ranges; the first holds the caret.
10 var selection: [Range<Int>] { get }
11 /// Runs a command at the selection as one undoable change.
12 func perform(_ command: any OrgCommand, now: Date, answers: [String: String]) -> CommandStep
13 /// Applies a change made outside typing (save, disk change, revert) and updates whatever
14 /// shows the document.
15 func update<T>(_ change: (inout DocumentState) throws -> T) rethrows -> T
16}
17
18@MainActor
19public final class StateBuffer: DocumentBuffer {
20 public private(set) var document: DocumentState
21 public var selection: [Range<Int>] = [0..<0]
22 public var options: EditingOptions = .org
23
24 public init(_ document: DocumentState) {
25 self.document = document
26 }
27
28 public func perform(_ command: any OrgCommand, now: Date, answers: [String: String]) -> CommandStep {
29 do {
30 let step = try document.run(command, selection: selection, now: now, answers: answers, options: options)
31 if case .commit(let result) = step, let new = result.selection { selection = new }
32 return step
33 } catch {
34 return .failed("\(error)")
35 }
36 }
37
38 public func update<T>(_ change: (inout DocumentState) throws -> T) rethrows -> T {
39 try change(&document)
40 }
41}