Sources/OrgCore/Commands/Dwim.swift
39 lines · 2146 bytes
1import Foundation
2
3/// Doom's `+org/dwim-at-point` (RET in normal state): on a heading, TODO becomes the first
4/// done keyword of its sequence and a done keyword the first TODO one; on an item, its
5/// checkbox toggles; in a src block, the block runs; on a `#+TBLFM` line or in a table with
6/// formulas, the table recalculates, otherwise aligns.
7public struct OrgDwim: OrgCommand {
8 public init() {}
9 public var id: String { "org.dwim" }
10 public var title: String { "Act at Point" }
11
12 public func applies(in context: EditContext) -> Bool { true }
13
14 public func run(in context: EditContext) -> CommandStep {
15 if TableRecalculate.tblfmLine(in: context) != nil { return TableRecalculate(all: true).run(in: context) }
16 if KeyContext.holds("src", in: context) { return ExecuteSrcBlock().run(in: context) }
17 if KeyContext.holds("table", in: context) {
18 let buffer = EmacsBuffer(context.text, point: context.caret, settings: context.tree.settings)
19 if buffer.firstTblfm(after: buffer.tableEnd()) != nil { return TableRecalculate(all: true).run(in: context) }
20 return TableCommand(.align).run(in: context)
21 }
22 if KeyContext.holds("item", in: context) {
23 let toggle = ToggleCheckbox()
24 if toggle.applies(in: context) { return toggle.run(in: context) }
25 }
26 guard headingOnLine(at: context.caret, in: context.tree) != nil else { return .failed("Nothing to do here") }
27 let settings = context.tree.settings
28 return commitBuffer(context) { buffer in
29 guard let current = buffer.todoKeyword,
30 let sequence = settings.todoSequences.first(where: { ($0.active + $0.done).contains { $0.name == current } }) else { return }
31 if settings.isDone(current) {
32 buffer.setTodoKeyword(sequence.active.first?.name)
33 } else if let done = sequence.done.first?.name {
34 buffer.setTodoKeyword(done)
35 if let (marker, note) = try buffer.autoRepeat(doneWord: done, previous: current) { buffer.storeNote(marker, note) }
36 }
37 }
38 }
39}