Sources/OrgEditorAppKit/EditorCommands.swift
158 lines · 10649 bytes
1#if os(macOS)
2import AppKit
3import OrgCore
4
5/// Every command a key, menu or the palette can run, by id.
6public struct EditorCommand: Sendable {
7 public enum Action: Sendable {
8 /// An `OrgCore` command, run through `OrgEditor.perform`.
9 case text(any OrgCommand)
10 /// Folding and other view changes the editor makes itself.
11 case view
12 /// A text-system action; `extending` is its variant that extends the selection, used
13 /// while a mark is active.
14 case edit(selector: String, extending: String? = nil)
15 /// Mark handling in the editor.
16 case mark
17 /// The find bar.
18 case find(NSTextFinder.Action)
19 /// Handled by the app (save, quick open, palette).
20 case app
21 }
22
23 public let id: String
24 public let title: String
25 public let action: Action
26
27 /// Shown in the palette; text-system movement and editing are left to keys.
28 public var inPalette: Bool {
29 switch action {
30 case .edit, .mark: false
31 default: true
32 }
33 }
34}
35
36public enum EditorCommands {
37 public static let all: [EditorCommand] = Commands.everything.map { EditorCommand(id: $0.id, title: $0.title, action: .text($0)) } + [
38 EditorCommand(id: "org.cycle", title: "Cycle Visibility", action: .view),
39 EditorCommand(id: "org.cycle-global", title: "Cycle Global Visibility", action: .view),
40 EditorCommand(id: "org.fold.toggle", title: "Toggle Fold", action: .view),
41 EditorCommand(id: "org.fold.open", title: "Open Fold", action: .view),
42 EditorCommand(id: "org.fold.close", title: "Close Fold", action: .view),
43 EditorCommand(id: "org.narrow.subtree", title: "Narrow to Subtree", action: .view),
44 EditorCommand(id: "org.narrow.block", title: "Narrow to Block", action: .view),
45 EditorCommand(id: "org.widen", title: "Widen", action: .view),
46 EditorCommand(id: "org.narrow.toggle", title: "Narrow to Subtree or Widen", action: .view),
47 EditorCommand(id: "org.toggle-inline-images", title: "Show or Hide Inline Images", action: .view),
48 EditorCommand(id: "editor.complete", title: "Complete at Point", action: .view),
49 EditorCommand(id: "editor.toggle-spell-check", title: "Check Spelling While Typing", action: .view),
50 EditorCommand(id: "editor.toggle-truncate-lines", title: "Truncate or Wrap Long Lines", action: .view),
51 EditorCommand(id: "org.table.toggle-column-width", title: "Shrink or Expand Table Column", action: .view),
52 EditorCommand(id: "org.table.shrink", title: "Shrink Table Columns with Widths", action: .view),
53 EditorCommand(id: "org.table.expand", title: "Expand Table Columns", action: .view),
54 EditorCommand(id: "org.link.insert", title: "Insert Link…", action: .app),
55 EditorCommand(id: "org.link.store", title: "Store Link", action: .app),
56 EditorCommand(id: "org.id.store-link", title: "Store ID Link", action: .app),
57 EditorCommand(id: "org.subtree.paste", title: "Paste Subtree", action: .app),
58 EditorCommand(id: "app.block.save", title: "Save Block", action: .app),
59 EditorCommand(id: "app.block.cancel", title: "Leave Block", action: .app),
60
61 EditorCommand(id: "app.save", title: "Save", action: .app),
62 EditorCommand(id: "app.quit", title: "Quit Orgstar", action: .app),
63 EditorCommand(id: "app.save-all", title: "Save All Buffers", action: .app),
64 EditorCommand(id: "app.buffer.switch", title: "Switch to Buffer…", action: .app),
65 EditorCommand(id: "app.buffer.kill", title: "Close Buffer", action: .app),
66 EditorCommand(id: "app.buffer.kill-others", title: "Close Other Buffers", action: .app),
67 EditorCommand(id: "app.buffer.kill-all", title: "Close All Buffers", action: .app),
68 EditorCommand(id: "app.buffer.next", title: "Next Buffer", action: .app),
69 EditorCommand(id: "app.buffer.previous", title: "Previous Buffer", action: .app),
70 EditorCommand(id: "app.buffer.last", title: "Last Buffer", action: .app),
71 EditorCommand(id: "app.babel.cancel", title: "Cancel Running Task", action: .app),
72 EditorCommand(id: "app.toggle-tab-bar", title: "Show or Hide Tab Bar", action: .app),
73 EditorCommand(id: "app.toggle-outline", title: "Show or Hide Outline", action: .app),
74 EditorCommand(id: "app.toggle-backlinks", title: "Show or Hide Backlinks", action: .app),
75 EditorCommand(id: "app.toggle-inspector", title: "Show or Hide Columns and Clock", action: .app),
76 EditorCommand(id: "app.toggle-markup", title: "Show or Hide Markup", action: .app),
77 EditorCommand(id: "app.edit-config", title: "Edit Config File", action: .app),
78 EditorCommand(id: "app.import-emacs", title: "Import from Emacs…", action: .app),
79 EditorCommand(id: "app.toggle-line-numbers", title: "Show or Hide Line Numbers", action: .app),
80 EditorCommand(id: "app.quick-open", title: "Quick Open…", action: .app),
81 EditorCommand(id: "app.palette", title: "Command Palette…", action: .app),
82 EditorCommand(id: "app.search", title: "Search Notes", action: .app),
83 EditorCommand(id: "app.reload-keymap", title: "Reload Keymap", action: .app),
84 EditorCommand(id: "app.refile", title: "Refile…", action: .app),
85 EditorCommand(id: "app.archive", title: "Archive Subtree", action: .app),
86 EditorCommand(id: "app.agenda", title: "Agenda", action: .app),
87 EditorCommand(id: "app.capture", title: "Capture…", action: .app),
88 EditorCommand(id: "app.board", title: "Board", action: .app),
89 EditorCommand(id: "app.clock.in", title: "Clock In", action: .app),
90 EditorCommand(id: "app.clock.in-recent", title: "Clock In to Recent Entry…", action: .app),
91 EditorCommand(id: "app.clock.in-last", title: "Clock In to Last Entry", action: .app),
92 EditorCommand(id: "app.clock.out", title: "Clock Out", action: .app),
93 EditorCommand(id: "app.clock.cancel", title: "Cancel Clock", action: .app),
94 EditorCommand(id: "app.clock.goto", title: "Go to Clocked Entry", action: .app),
95 EditorCommand(id: "app.clock.goto-recent", title: "Go to Recent Clocked Entry…", action: .app),
96 EditorCommand(id: "app.clock.default", title: "Mark as Default Clock Task", action: .app),
97 EditorCommand(id: "app.clock.resolve", title: "Resolve Open Clocks…", action: .app),
98 EditorCommand(id: "app.clock.report", title: "Clock Report", action: .app),
99 EditorCommand(id: "app.table-import", title: "Import Table from File…", action: .app),
100 EditorCommand(id: "app.table-export", title: "Export Table to File…", action: .app),
101 EditorCommand(id: "app.export-dialog", title: "Export…", action: .app),
102 EditorCommand(id: "app.sync-conflicts", title: "Resolve Sync Conflicts…", action: .app),
103 EditorCommand(id: "app.revert", title: "Revert to File on Disk", action: .app),
104 EditorCommand(id: "app.recovery", title: "Recovery Versions…", action: .app),
105 EditorCommand(id: "app.export.html", title: "Export to HTML", action: .app),
106 EditorCommand(id: "app.export.html-open", title: "Export to HTML and Open", action: .app),
107 EditorCommand(id: "app.export.markdown", title: "Export to Markdown", action: .app),
108 EditorCommand(id: "app.export.pdf", title: "Export to PDF with Emacs", action: .app),
109 EditorCommand(id: "app.export.odt", title: "Export to ODT with Emacs", action: .app),
110 EditorCommand(id: "app.export.latex", title: "Export to LaTeX with Emacs", action: .app),
111 EditorCommand(id: "app.export.text", title: "Export to Plain Text with Emacs", action: .app),
112
113 movement("forward-char", "Forward Character", "moveForward:"),
114 movement("backward-char", "Backward Character", "moveBackward:"),
115 movement("next-line", "Next Line", "moveDown:"),
116 movement("previous-line", "Previous Line", "moveUp:"),
117 movement("beginning-of-line", "Beginning of Line", "moveToBeginningOfParagraph:"),
118 movement("end-of-line", "End of Line", "moveToEndOfParagraph:"),
119 movement("forward-word", "Forward Word", "moveWordForward:"),
120 movement("backward-word", "Backward Word", "moveWordBackward:"),
121 movement("beginning-of-buffer", "Beginning of Buffer", "moveToBeginningOfDocument:"),
122 movement("end-of-buffer", "End of Buffer", "moveToEndOfDocument:"),
123 movement("scroll-up", "Scroll Up", "pageDown:"),
124 movement("scroll-down", "Scroll Down", "pageUp:"),
125 edit("recenter", "Recenter", "centerSelectionInVisibleArea:"),
126 edit("delete-char", "Delete Character", "deleteForward:"),
127 edit("kill-word", "Kill Word", "deleteWordForward:"),
128 edit("backward-kill-word", "Kill Word Backward", "deleteWordBackward:"),
129 edit("kill-line", "Kill Line", "deleteToEndOfParagraph:"),
130 edit("yank", "Yank", "yank:"),
131 edit("select-all", "Select All", "selectAll:"),
132 edit("kill-region", "Kill Region", "cut:"),
133 edit("copy-region", "Copy Region", "copy:"),
134 edit("undo", "Undo", "undo:"),
135 edit("transpose-chars", "Transpose Characters", "transpose:"),
136 EditorCommand(id: "edit.find", title: "Find", action: .find(.showFindInterface)),
137 EditorCommand(id: "edit.replace", title: "Find and Replace", action: .find(.showReplaceInterface)),
138 EditorCommand(id: "edit.find-next", title: "Find Next", action: .find(.nextMatch)),
139 EditorCommand(id: "edit.find-previous", title: "Find Previous", action: .find(.previousMatch)),
140 EditorCommand(id: "edit.use-selection-for-find", title: "Use Selection for Find", action: .find(.setSearchString)),
141 EditorCommand(id: "edit.set-mark", title: "Set Mark", action: .mark),
142 EditorCommand(id: "edit.keyboard-quit", title: "Quit", action: .mark),
143 ]
144
145 private static func movement(_ name: String, _ title: String, _ selector: String) -> EditorCommand {
146 let extending = String(selector.dropLast()) + "AndModifySelection:"
147 return EditorCommand(id: "edit.\(name)", title: title, action: .edit(selector: selector, extending: extending))
148 }
149
150 private static func edit(_ name: String, _ title: String, _ selector: String) -> EditorCommand {
151 EditorCommand(id: "edit.\(name)", title: title, action: .edit(selector: selector))
152 }
153
154 private static let byID = Dictionary(uniqueKeysWithValues: all.map { ($0.id, $0) })
155
156 public static func command(_ id: String) -> EditorCommand? { byID[id] }
157}
158#endif