krz/orgstar

A native macOS editor for org-mode files. editor org-mode swift

Sources/OrgCore/Keymap/Presets.swift

1341 lines · 37858 bytes

3 symbols in this file
   1/// The keymaps the app ships. The user's `keymap.toml` is layered on top of the chosen one.
   2public enum KeymapPreset: String, Sendable, CaseIterable {
   3    case emacs, mac, doom
   4
   5    public var title: String {
   6        switch self {
   7        case .emacs: "Emacs"
   8        case .mac: "Mac"
   9        case .doom: "Doom (Vim keys)"
  10        }
  11    }
  12
  13    /// Whether the preset edits modally.
  14    public var isModal: Bool { self == .doom }
  15
  16    public var keymap: Keymap {
  17        var problems: [String] = []
  18        let map = try! Keymap(toml: toml, problems: &problems)
  19        precondition(problems.isEmpty, "preset \(rawValue): \(problems)")
  20        return map
  21    }
  22
  23    public var toml: String {
  24        switch self {
  25        case .emacs: Self.common + Self.speedBindings(mode: nil) + Self.emacsBindings
  26        case .mac: Self.common + Self.speedBindings(mode: nil) + Self.macBindings
  27        case .doom: Self.doomToml + Self.speedBindings(mode: "insert")
  28        }
  29    }
  30
  31    /// `org-speed-commands`, for the start of a heading line when `org-use-speed-commands` is on.
  32    static let speedCommands: [(key: String, command: String)] = [
  33        ("n", "org.heading.next"), ("p", "org.heading.previous"), ("f", "org.heading.forward-same-level"),
  34        ("b", "org.heading.backward-same-level"), ("u", "org.heading.up"), ("j", "org.goto"),
  35        ("c", "org.cycle"), ("C", "org.cycle-global"), ("s", "org.narrow.toggle"), ("k", "org.subtree.cut"),
  36        ("U", "org.subtree.up"), ("D", "org.subtree.down"), ("r", "org.heading.demote"), ("l", "org.heading.promote"),
  37        ("R", "org.subtree.demote"), ("L", "org.subtree.promote"), ("i", "org.heading.insert-after-subtree"),
  38        ("^", "org.sort"), ("w", "app.refile"), ("a", "app.archive"), ("@", "org.subtree.mark"),
  39        ("#", "org.heading.toggle-comment"), ("I", "app.clock.in"), ("O", "app.clock.out"), ("t", "org.todo.cycle"),
  40        (",", "org.priority.set"), ("0", "org.priority.remove"), ("1", "org.priority.set-a"), ("2", "org.priority.set-b"),
  41        ("3", "org.priority.set-c"), (":", "org.tags.set"), ("e", "org.effort.set"), ("v", "app.agenda"),
  42        ("/", "org.sparse-tree"), ("o", "org.link.open"),
  43    ]
  44
  45    static func speedBindings(mode: String?) -> String {
  46        speedCommands.map { key, command in
  47            "[[bind]]\nkeys = \"\(key)\"\ncommand = \"\(command)\"\nwhen = \"speed\"\n" + (mode.map { "mode = \"\($0)\"\n" } ?? "")
  48        }.joined()
  49    }
  50
  51    /// Doom: the Emacs preset's org bindings in every evil state (as org-mode-map's are), with
  52    /// evil-org's `M-h/j/k/l` forms, then Doom's leader, localleader and evil-org keys.
  53    static var doomToml: String {
  54        var problems: [String] = []
  55        let emacs = try! Keymap(toml: common + emacsBindings, problems: &problems)
  56        let translations: [String: String] = ["<left>": "h", "<right>": "l", "<up>": "k", "<down>": "j"]
  57        var out = ""
  58        func bind(_ keys: String, _ command: String, when: String?, mode: String) {
  59            out += "[[bind]]\nkeys = \"\(keys.replacingOccurrences(of: "\\", with: "\\\\"))\"\ncommand = \"\(command)\"\n"
  60            if let when { out += "when = \"\(when)\"\n" }
  61            out += "mode = \"\(mode)\"\n"
  62        }
  63        for binding in emacs.bindings {
  64            let first = binding.keys[0]
  65            let keys = KeySequence.format(binding.keys)
  66            let orgKey = first.key == "c" && first.modifiers == [.control] || first.key == "x" && first.modifiers == [.control]
  67                || (first.modifiers.contains(.meta) && ["<left>", "<right>", "<up>", "<down>", "RET"].contains(first.key))
  68                || (first.modifiers.contains(.shift) && ["<left>", "<right>", "<up>", "<down>"].contains(first.key))
  69                || (first.modifiers == [.control] && first.key == "RET")
  70                || keys == "M-x" || keys == "M-q"
  71            guard orgKey else { continue }
  72            for mode in ["normal", "insert", "visual"] { bind(keys, binding.command, when: binding.when, mode: mode) }
  73            // evil-org: M-h/j/k/l and M-H/J/K/L in normal, visual and insert.
  74            if binding.keys.count == 1, first.modifiers.contains(.meta), let letter = translations[first.key] {
  75                let shifted = first.modifiers.contains(.shift)
  76                let key = "M-" + (shifted ? letter.uppercased() : letter)
  77                for mode in ["normal", "insert", "visual"] { bind(key, binding.command, when: binding.when, mode: mode) }
  78            }
  79            // Doom: C-S-h/j/k/l are org-shift* in normal and insert.
  80            if binding.keys.count == 1, first.modifiers == [.shift], let letter = translations[first.key] {
  81                for mode in ["normal", "insert"] { bind("C-" + letter.uppercased(), binding.command, when: binding.when, mode: mode) }
  82            }
  83            // evil-org insert state: C-t demotes, C-d promotes.
  84            if binding.keys.count == 1, first.modifiers == [.meta], first.key == "<right>" || first.key == "<left>" {
  85                bind(first.key == "<right>" ? "C-t" : "C-d", binding.command, when: binding.when, mode: "insert")
  86            }
  87        }
  88        return out + doomBindings
  89    }
  90
  91    static let doomBindings = """
  92        # Leader
  93        [[bind]]
  94        keys = "SPC SPC"
  95        command = "app.quick-open"
  96        mode = "normal"
  97        [[bind]]
  98        keys = "SPC q q"
  99        command = "app.quit"
 100        mode = "normal"
 101        [[bind]]
 102        keys = "SPC ."
 103        command = "app.quick-open"
 104        mode = "normal"
 105        [[bind]]
 106        keys = "SPC f f"
 107        command = "app.quick-open"
 108        mode = "normal"
 109        [[bind]]
 110        keys = "SPC f s"
 111        command = "app.save"
 112        mode = "normal"
 113        # Buffers
 114        [[bind]]
 115        keys = "SPC b b"
 116        command = "app.buffer.switch"
 117        mode = "normal"
 118        [[bind]]
 119        keys = "SPC b B"
 120        command = "app.buffer.switch"
 121        mode = "normal"
 122        [[bind]]
 123        keys = "SPC ,"
 124        command = "app.buffer.switch"
 125        mode = "normal"
 126        [[bind]]
 127        keys = "SPC `"
 128        command = "app.buffer.last"
 129        mode = "normal"
 130        [[bind]]
 131        keys = "SPC b k"
 132        command = "app.buffer.kill"
 133        mode = "normal"
 134        [[bind]]
 135        keys = "SPC b d"
 136        command = "app.buffer.kill"
 137        mode = "normal"
 138        [[bind]]
 139        keys = "SPC b K"
 140        command = "app.buffer.kill-all"
 141        mode = "normal"
 142        [[bind]]
 143        keys = "SPC b O"
 144        command = "app.buffer.kill-others"
 145        mode = "normal"
 146        [[bind]]
 147        keys = "SPC b n"
 148        command = "app.buffer.next"
 149        mode = "normal"
 150        [[bind]]
 151        keys = "SPC b p"
 152        command = "app.buffer.previous"
 153        mode = "normal"
 154        [[bind]]
 155        keys = "SPC b ]"
 156        command = "app.buffer.next"
 157        mode = "normal"
 158        [[bind]]
 159        keys = "SPC b ["
 160        command = "app.buffer.previous"
 161        mode = "normal"
 162        [[bind]]
 163        keys = "] b"
 164        command = "app.buffer.next"
 165        mode = "normal"
 166        [[bind]]
 167        keys = "[ b"
 168        command = "app.buffer.previous"
 169        mode = "normal"
 170        [[bind]]
 171        keys = "SPC b s"
 172        command = "app.save"
 173        mode = "normal"
 174        [[bind]]
 175        keys = "SPC b S"
 176        command = "app.save-all"
 177        mode = "normal"
 178        [[bind]]
 179        keys = "SPC s s"
 180        command = "edit.find"
 181        mode = "normal"
 182        [[bind]]
 183        keys = "SPC /"
 184        command = "app.search"
 185        mode = "normal"
 186        [[bind]]
 187        keys = "SPC s p"
 188        command = "app.search"
 189        mode = "normal"
 190        [[bind]]
 191        keys = "SPC :"
 192        command = "app.palette"
 193        mode = "normal"
 194        [[bind]]
 195        keys = "SPC o a"
 196        command = "app.agenda"
 197        mode = "normal"
 198        [[bind]]
 199        keys = "SPC X"
 200        command = "app.capture"
 201        mode = "normal"
 202        [[bind]]
 203        keys = "SPC z t"
 204        command = "app.clock.report"
 205        mode = "normal"
 206        [[bind]]
 207        keys = "SPC h r r"
 208        command = "app.reload-keymap"
 209        mode = "normal"
 210        [[bind]]
 211        keys = "SPC t s"
 212        command = "editor.toggle-spell-check"
 213        mode = "normal"
 214        [[bind]]
 215        keys = "SPC t w"
 216        command = "editor.toggle-truncate-lines"
 217        mode = "normal"
 218
 219        # Localleader (SPC m)
 220        [[bind]]
 221        keys = "SPC m '"
 222        command = "org.edit-special"
 223        mode = "normal"
 224        [[bind]]
 225        keys = "SPC m s c"
 226        command = "org.subtree.clone"
 227        mode = "normal"
 228        [[bind]]
 229        keys = "SPC m s d"
 230        command = "org.subtree.cut"
 231        mode = "normal"
 232        [[bind]]
 233        keys = "SPC m s S"
 234        command = "org.sort"
 235        mode = "normal"
 236        [[bind]]
 237        keys = "SPC m s n"
 238        command = "org.narrow.subtree"
 239        mode = "normal"
 240        [[bind]]
 241        keys = "SPC m s s"
 242        command = "org.sparse-tree"
 243        mode = "normal"
 244        [[bind]]
 245        keys = "SPC m s N"
 246        command = "org.widen"
 247        mode = "normal"
 248        [[bind]]
 249        keys = "SPC m ."
 250        command = "org.goto"
 251        mode = "normal"
 252        [[bind]]
 253        keys = "SPC m h"
 254        command = "org.heading.toggle"
 255        mode = "normal"
 256        [[bind]]
 257        keys = "SPC m i"
 258        command = "org.item.toggle"
 259        mode = "normal"
 260        [[bind]]
 261        keys = "SPC m l l"
 262        command = "org.link.insert"
 263        mode = "normal"
 264        [[bind]]
 265        keys = "SPC m l s"
 266        command = "org.link.store"
 267        mode = "normal"
 268        [[bind]]
 269        keys = "SPC m l i"
 270        command = "org.id.store-link"
 271        mode = "normal"
 272        [[bind]]
 273        keys = "SPC n l"
 274        command = "org.link.store"
 275        mode = "normal"
 276        [[bind]]
 277        keys = "SPC m t"
 278        command = "org.todo.cycle"
 279        mode = "normal"
 280        [[bind]]
 281        keys = "SPC m q"
 282        command = "org.tags.set"
 283        mode = "normal"
 284        [[bind]]
 285        keys = "SPC m x"
 286        command = "org.checkbox.toggle"
 287        mode = "normal"
 288        [[bind]]
 289        keys = "SPC m A"
 290        command = "app.archive"
 291        mode = "normal"
 292        [[bind]]
 293        keys = "SPC m e h h"
 294        command = "app.export.html"
 295        mode = "normal"
 296        [[bind]]
 297        keys = "SPC m e h o"
 298        command = "app.export.html-open"
 299        mode = "normal"
 300        [[bind]]
 301        keys = "SPC m e m m"
 302        command = "app.export.markdown"
 303        mode = "normal"
 304        [[bind]]
 305        keys = "SPC m e l p"
 306        command = "app.export.pdf"
 307        mode = "normal"
 308        [[bind]]
 309        keys = "SPC m d d"
 310        command = "org.deadline"
 311        mode = "normal"
 312        [[bind]]
 313        keys = "SPC m d s"
 314        command = "org.schedule"
 315        mode = "normal"
 316        [[bind]]
 317        keys = "SPC m d t"
 318        command = "org.timestamp.active"
 319        mode = "normal"
 320        [[bind]]
 321        keys = "SPC m d T"
 322        command = "org.timestamp.inactive"
 323        mode = "normal"
 324        [[bind]]
 325        keys = "SPC m r r"
 326        command = "app.refile"
 327        mode = "normal"
 328        [[bind]]
 329        keys = "SPC m s r"
 330        command = "app.refile"
 331        mode = "normal"
 332        [[bind]]
 333        keys = "SPC m s A"
 334        command = "app.archive"
 335        mode = "normal"
 336        [[bind]]
 337        keys = "SPC m s a"
 338        command = "org.archive.toggle-tag"
 339        mode = "normal"
 340        [[bind]]
 341        keys = "SPC m s h"
 342        command = "org.subtree.promote"
 343        mode = "normal"
 344        [[bind]]
 345        keys = "SPC m s l"
 346        command = "org.subtree.demote"
 347        mode = "normal"
 348        [[bind]]
 349        keys = "SPC m s j"
 350        command = "org.subtree.down"
 351        mode = "normal"
 352        [[bind]]
 353        keys = "SPC m s k"
 354        command = "org.subtree.up"
 355        mode = "normal"
 356        [[bind]]
 357        keys = "SPC m c i"
 358        command = "app.clock.in"
 359        mode = "normal"
 360        [[bind]]
 361        keys = "SPC m c o"
 362        command = "app.clock.out"
 363        mode = "normal"
 364        [[bind]]
 365        keys = "SPC m c c"
 366        command = "app.clock.cancel"
 367        mode = "normal"
 368        [[bind]]
 369        keys = "SPC m c g"
 370        command = "app.clock.goto"
 371        mode = "normal"
 372        [[bind]]
 373        keys = "SPC m c G"
 374        command = "app.clock.goto-recent"
 375        mode = "normal"
 376        [[bind]]
 377        keys = "SPC m c I"
 378        command = "app.clock.in-last"
 379        mode = "normal"
 380        [[bind]]
 381        keys = "SPC m c d"
 382        command = "app.clock.default"
 383        mode = "normal"
 384        [[bind]]
 385        keys = "SPC m c r"
 386        command = "app.clock.resolve"
 387        mode = "normal"
 388        [[bind]]
 389        keys = "SPC m c R"
 390        command = "app.clock.report"
 391        mode = "normal"
 392        [[bind]]
 393        keys = "SPC m c E"
 394        command = "org.effort.set"
 395        mode = "normal"
 396        [[bind]]
 397        keys = "SPC m p p"
 398        command = "org.priority.set"
 399        mode = "normal"
 400        [[bind]]
 401        keys = "SPC m o"
 402        command = "org.property.read-and-set"
 403        mode = "normal"
 404        [[bind]]
 405        keys = "SPC m p u"
 406        command = "org.priority.up"
 407        mode = "normal"
 408        [[bind]]
 409        keys = "SPC m p d"
 410        command = "org.priority.down"
 411        mode = "normal"
 412        [[bind]]
 413        keys = "SPC m b -"
 414        command = "org.table.insert-hline"
 415        mode = "normal"
 416        [[bind]]
 417        keys = "SPC m b a"
 418        command = "org.table.align"
 419        mode = "normal"
 420        [[bind]]
 421        keys = "SPC m b r"
 422        command = "org.table.recalc-all"
 423        mode = "normal"
 424        [[bind]]
 425        keys = "SPC m b d c"
 426        command = "org.table.delete-column"
 427        mode = "normal"
 428        [[bind]]
 429        keys = "SPC m b d r"
 430        command = "org.table.kill-row"
 431        mode = "normal"
 432        [[bind]]
 433        keys = "SPC m b i c"
 434        command = "org.table.insert-column"
 435        mode = "normal"
 436        [[bind]]
 437        keys = "SPC m b i r"
 438        command = "org.table.insert-row"
 439        mode = "normal"
 440        [[bind]]
 441        keys = "SPC m b i h"
 442        command = "org.table.insert-hline"
 443        mode = "normal"
 444
 445        # evil-org and Doom's org keys
 446        [[bind]]
 447        keys = "TAB"
 448        command = "org.cycle"
 449        mode = "normal"
 450        [[bind]]
 451        keys = "S-TAB"
 452        command = "org.cycle-global"
 453        mode = "normal"
 454        [[bind]]
 455        keys = "RET"
 456        command = "org.dwim"
 457        mode = "normal"
 458        [[bind]]
 459        keys = "z a"
 460        command = "org.fold.toggle"
 461        mode = "normal"
 462        [[bind]]
 463        keys = "z c"
 464        command = "org.fold.close"
 465        mode = "normal"
 466        [[bind]]
 467        keys = "z o"
 468        command = "org.fold.open"
 469        mode = "normal"
 470        [[bind]]
 471        keys = "z A"
 472        command = "org.cycle-global"
 473        mode = "normal"
 474        [[bind]]
 475        keys = "g h"
 476        command = "org.heading.up"
 477        mode = "normal"
 478        [[bind]]
 479        keys = "] h"
 480        command = "org.heading.forward-same-level"
 481        mode = "normal"
 482        [[bind]]
 483        keys = "[ h"
 484        command = "org.heading.backward-same-level"
 485        mode = "normal"
 486        [[bind]]
 487        keys = "RET"
 488        command = "org.table.next-row"
 489        when = "table"
 490        mode = "insert"
 491        [[bind]]
 492        keys = "TAB"
 493        command = "org.cycle"
 494        mode = "visual"
 495        [[bind]]
 496        keys = "S-TAB"
 497        command = "org.cycle-global"
 498        mode = "visual"
 499
 500        # Doom's corfu: completion-at-point in insert state.
 501        [[bind]]
 502        keys = "C-SPC"
 503        command = "editor.complete"
 504        mode = "insert"
 505        [[bind]]
 506        keys = "C-@"
 507        command = "editor.complete"
 508        mode = "insert"
 509
 510        # Insert state: org-cycle and org-shifttab with Doom's +org-indent-maybe-h, which
 511        # demotes or promotes a heading and indents or outdents an item tree.
 512        [[bind]]
 513        keys = "S-TAB"
 514        command = "org.cycle-global"
 515        mode = "insert"
 516        [[bind]]
 517        keys = "TAB"
 518        command = "org.table.next-field"
 519        when = "table"
 520        mode = "insert"
 521        [[bind]]
 522        keys = "S-TAB"
 523        command = "org.table.previous-field"
 524        when = "table"
 525        mode = "insert"
 526        [[bind]]
 527        keys = "TAB"
 528        command = "org.item.indent-tree"
 529        when = "item"
 530        mode = "insert"
 531        [[bind]]
 532        keys = "S-TAB"
 533        command = "org.item.outdent-tree"
 534        when = "item"
 535        mode = "insert"
 536        [[bind]]
 537        keys = "TAB"
 538        command = "org.heading.demote"
 539        when = "heading"
 540        mode = "insert"
 541        [[bind]]
 542        keys = "S-TAB"
 543        command = "org.heading.promote"
 544        when = "heading"
 545        mode = "insert"
 546
 547        """
 548
 549
 550    static let common = """
 551        [[bind]]
 552        keys = "TAB"
 553        command = "org.cycle"
 554        when = "heading"
 555        [[bind]]
 556        keys = "TAB"
 557        command = "org.cycle"
 558        when = "fold-line"
 559
 560        [[bind]]
 561        keys = "S-TAB"
 562        command = "org.cycle-global"
 563        [[bind]]
 564        keys = "TAB"
 565        command = "org.table.next-field"
 566        when = "table"
 567        [[bind]]
 568        keys = "S-TAB"
 569        command = "org.table.previous-field"
 570        when = "table"
 571        [[bind]]
 572        keys = "RET"
 573        command = "org.table.next-row"
 574        when = "table"
 575
 576        """
 577
 578    static let emacsBindings = """
 579        # Movement and editing. With a mark set (C-SPC), movement extends the region.
 580        [[bind]]
 581        keys = "C-f"
 582        command = "edit.forward-char"
 583        [[bind]]
 584        keys = "C-b"
 585        command = "edit.backward-char"
 586        [[bind]]
 587        keys = "C-n"
 588        command = "edit.next-line"
 589        [[bind]]
 590        keys = "C-p"
 591        command = "edit.previous-line"
 592        [[bind]]
 593        keys = "C-a"
 594        command = "edit.beginning-of-line"
 595        [[bind]]
 596        keys = "C-e"
 597        command = "edit.end-of-line"
 598        [[bind]]
 599        keys = "M-f"
 600        command = "edit.forward-word"
 601        [[bind]]
 602        keys = "M-b"
 603        command = "edit.backward-word"
 604        [[bind]]
 605        keys = "M-<"
 606        command = "edit.beginning-of-buffer"
 607        [[bind]]
 608        keys = "M->"
 609        command = "edit.end-of-buffer"
 610        [[bind]]
 611        keys = "C-v"
 612        command = "edit.scroll-up"
 613        [[bind]]
 614        keys = "M-v"
 615        command = "edit.scroll-down"
 616        [[bind]]
 617        keys = "C-l"
 618        command = "edit.recenter"
 619        [[bind]]
 620        keys = "C-d"
 621        command = "edit.delete-char"
 622        [[bind]]
 623        keys = "M-d"
 624        command = "edit.kill-word"
 625        [[bind]]
 626        keys = "M-DEL"
 627        command = "edit.backward-kill-word"
 628        [[bind]]
 629        keys = "C-k"
 630        command = "edit.kill-line"
 631        [[bind]]
 632        keys = "C-y"
 633        command = "edit.yank"
 634        [[bind]]
 635        keys = "C-SPC"
 636        command = "edit.set-mark"
 637        [[bind]]
 638        keys = "C-M-i"
 639        command = "editor.complete"
 640        [[bind]]
 641        keys = "C-x h"
 642        command = "edit.select-all"
 643        [[bind]]
 644        keys = "C-w"
 645        command = "edit.kill-region"
 646        [[bind]]
 647        keys = "M-w"
 648        command = "edit.copy-region"
 649        [[bind]]
 650        keys = "C-/"
 651        command = "edit.undo"
 652        [[bind]]
 653        keys = "C-_"
 654        command = "edit.undo"
 655        [[bind]]
 656        keys = "C-x u"
 657        command = "edit.undo"
 658        [[bind]]
 659        keys = "C-g"
 660        command = "edit.keyboard-quit"
 661        [[bind]]
 662        keys = "C-t"
 663        command = "edit.transpose-chars"
 664        [[bind]]
 665        keys = "C-s"
 666        command = "edit.find"
 667        [[bind]]
 668        keys = "C-r"
 669        command = "edit.find"
 670        [[bind]]
 671        keys = "M-%"
 672        command = "edit.replace"
 673
 674        # Files and commands
 675        [[bind]]
 676        keys = "C-x C-s"
 677        command = "app.save"
 678        [[bind]]
 679        keys = "C-c C-o"
 680        command = "org.link.open"
 681        [[bind]]
 682        keys = "C-c C-l"
 683        command = "org.link.insert"
 684        [[bind]]
 685        keys = "C-c l"
 686        command = "org.link.store"
 687        [[bind]]
 688        keys = "C-c ;"
 689        command = "org.heading.toggle-comment"
 690        [[bind]]
 691        keys = "C-c *"
 692        command = "org.heading.toggle"
 693        [[bind]]
 694        keys = "C-c -"
 695        command = "org.item.toggle"
 696        [[bind]]
 697        keys = "C-c @"
 698        command = "org.subtree.mark"
 699        [[bind]]
 700        keys = "C-c C-x C-w"
 701        command = "org.subtree.cut"
 702        [[bind]]
 703        keys = "C-c C-x M-w"
 704        command = "org.subtree.copy"
 705        [[bind]]
 706        keys = "C-c C-x C-y"
 707        command = "org.subtree.paste"
 708        [[bind]]
 709        keys = "C-c C-x c"
 710        command = "org.subtree.clone"
 711        [[bind]]
 712        keys = "C-c ^"
 713        command = "org.sort"
 714        [[bind]]
 715        keys = "C-c C-c"
 716        command = "org.ctrl-c-ctrl-c"
 717        [[bind]]
 718        keys = "C-c C-y"
 719        command = "org.timestamp.evaluate-range"
 720        [[bind]]
 721        keys = "C-c C-x f"
 722        command = "org.footnote.action"
 723        [[bind]]
 724        keys = "C-c ="
 725        command = "org.table.column-formula"
 726        [[bind]]
 727        keys = "C-c TAB"
 728        command = "org.table.toggle-column-width"
 729        when = "table"
 730        [[bind]]
 731        keys = "C-x n s"
 732        command = "org.narrow.subtree"
 733        [[bind]]
 734        keys = "C-x n b"
 735        command = "org.narrow.block"
 736        [[bind]]
 737        keys = "C-x n w"
 738        command = "org.widen"
 739        [[bind]]
 740        keys = "C-x x t"
 741        command = "editor.toggle-truncate-lines"
 742        [[bind]]
 743        keys = "C-c C-j"
 744        command = "org.goto"
 745        [[bind]]
 746        keys = "C-c /"
 747        command = "org.sparse-tree"
 748        [[bind]]
 749        keys = "C-c ,"
 750        command = "org.priority.set"
 751        [[bind]]
 752        keys = "C-c C-x p"
 753        command = "org.property.read-and-set"
 754        [[bind]]
 755        keys = "C-c C-x i"
 756        command = "org.columns.insert-dblock"
 757        [[bind]]
 758        keys = "C-c C-x a"
 759        command = "org.archive.toggle-tag"
 760        [[bind]]
 761        keys = "C-c C-x A"
 762        command = "org.archive.to-sibling"
 763        [[bind]]
 764        keys = "C-c C-x C-v"
 765        command = "org.toggle-inline-images"
 766        [[bind]]
 767        keys = "C-c C-x C-c"
 768        command = "org.columns"
 769        [[bind]]
 770        keys = "S-<right>"
 771        command = "org.property.next-value"
 772        when = "property"
 773        [[bind]]
 774        keys = "S-<left>"
 775        command = "org.property.previous-value"
 776        when = "property"
 777        [[bind]]
 778        keys = "C-c C-x C-r"
 779        command = "org.clock.report"
 780        [[bind]]
 781        keys = "C-c C-x C-u"
 782        command = "org.dblock.update"
 783        [[bind]]
 784        keys = "C-c C-x e"
 785        command = "org.effort.set"
 786        [[bind]]
 787        keys = "C-c C-c"
 788        command = "org.dblock.update"
 789        when = "dblock"
 790        [[bind]]
 791        keys = "C-c C-,"
 792        command = "org.structure-template"
 793        [[bind]]
 794        keys = "C-c '"
 795        command = "org.edit-special"
 796        [[bind]]
 797        keys = "C-c C-v t"
 798        command = "org.babel.tangle"
 799        [[bind]]
 800        keys = "C-c C-v C-t"
 801        command = "org.babel.tangle"
 802        [[bind]]
 803        keys = "C-c `"
 804        command = "org.table.edit-field"
 805        when = "table"
 806        [[bind]]
 807        keys = "C-x b"
 808        command = "app.buffer.switch"
 809        [[bind]]
 810        keys = "C-x C-b"
 811        command = "app.buffer.switch"
 812        [[bind]]
 813        keys = "C-x k"
 814        command = "app.buffer.kill"
 815        [[bind]]
 816        keys = "C-x <right>"
 817        command = "app.buffer.next"
 818        [[bind]]
 819        keys = "C-x <left>"
 820        command = "app.buffer.previous"
 821        [[bind]]
 822        keys = "C-x s"
 823        command = "app.save-all"
 824        [[bind]]
 825        keys = "C-x C-f"
 826        command = "app.quick-open"
 827        [[bind]]
 828        keys = "M-x"
 829        command = "app.palette"
 830        [[bind]]
 831        keys = "C-c a"
 832        command = "app.agenda"
 833        [[bind]]
 834        keys = "C-c c"
 835        command = "app.capture"
 836        [[bind]]
 837        keys = "C-c C-x C-i"
 838        command = "app.clock.in"
 839        [[bind]]
 840        keys = "C-c C-x C-o"
 841        command = "app.clock.out"
 842        [[bind]]
 843        keys = "C-c C-x C-q"
 844        command = "app.clock.cancel"
 845        [[bind]]
 846        keys = "C-c C-x C-j"
 847        command = "app.clock.goto"
 848        [[bind]]
 849        keys = "C-c C-x C-x"
 850        command = "app.clock.in-last"
 851        [[bind]]
 852        keys = "C-c C-x C-z"
 853        command = "app.clock.resolve"
 854        [[bind]]
 855        keys = "C-c C-e h h"
 856        command = "app.export.html"
 857        [[bind]]
 858        keys = "C-c C-e h o"
 859        command = "app.export.html-open"
 860        [[bind]]
 861        keys = "C-c C-e m m"
 862        command = "app.export.markdown"
 863        [[bind]]
 864        keys = "C-c C-e l p"
 865        command = "app.export.pdf"
 866        [[bind]]
 867        keys = "C-c C-e l l"
 868        command = "app.export.latex"
 869        [[bind]]
 870        keys = "C-c C-e o o"
 871        command = "app.export.odt"
 872        [[bind]]
 873        keys = "C-c C-e t u"
 874        command = "app.export.text"
 875
 876        # Org
 877        [[bind]]
 878        keys = "C-c C-t"
 879        command = "org.todo.cycle"
 880        [[bind]]
 881        keys = "S-<right>"
 882        command = "org.todo.next"
 883        when = "heading"
 884        [[bind]]
 885        keys = "S-<left>"
 886        command = "org.todo.previous"
 887        when = "heading"
 888        [[bind]]
 889        keys = "S-<up>"
 890        command = "org.priority.up"
 891        when = "heading"
 892        [[bind]]
 893        keys = "S-<down>"
 894        command = "org.priority.down"
 895        when = "heading"
 896        [[bind]]
 897        keys = "M-<left>"
 898        command = "org.heading.promote"
 899        when = "heading"
 900        [[bind]]
 901        keys = "M-<right>"
 902        command = "org.heading.demote"
 903        when = "heading"
 904        [[bind]]
 905        keys = "M-S-<left>"
 906        command = "org.subtree.promote"
 907        when = "heading"
 908        [[bind]]
 909        keys = "M-S-<right>"
 910        command = "org.subtree.demote"
 911        when = "heading"
 912        [[bind]]
 913        keys = "M-<up>"
 914        command = "org.subtree.up"
 915        when = "heading"
 916        [[bind]]
 917        keys = "M-<down>"
 918        command = "org.subtree.down"
 919        when = "heading"
 920        [[bind]]
 921        keys = "M-RET"
 922        command = "org.heading.insert"
 923        [[bind]]
 924        keys = "C-RET"
 925        command = "org.heading.insert-after-subtree"
 926        [[bind]]
 927        keys = "M-S-RET"
 928        command = "org.heading.insert-todo"
 929        [[bind]]
 930        keys = "C-c C-n"
 931        command = "org.heading.next"
 932        [[bind]]
 933        keys = "C-c C-p"
 934        command = "org.heading.previous"
 935        [[bind]]
 936        keys = "C-c C-f"
 937        command = "org.heading.forward-same-level"
 938        [[bind]]
 939        keys = "C-c C-b"
 940        command = "org.heading.backward-same-level"
 941        [[bind]]
 942        keys = "C-c C-u"
 943        command = "org.heading.up"
 944        [[bind]]
 945        keys = "C-c C-q"
 946        command = "org.tags.set"
 947        [[bind]]
 948        keys = "M-RET"
 949        command = "org.item.insert"
 950        when = "item"
 951        [[bind]]
 952        keys = "M-S-RET"
 953        command = "org.item.insert-checkbox"
 954        when = "item"
 955        [[bind]]
 956        keys = "M-<left>"
 957        command = "org.item.outdent"
 958        when = "item"
 959        [[bind]]
 960        keys = "M-<right>"
 961        command = "org.item.indent"
 962        when = "item"
 963        [[bind]]
 964        keys = "M-S-<left>"
 965        command = "org.item.outdent-tree"
 966        when = "item"
 967        [[bind]]
 968        keys = "M-S-<right>"
 969        command = "org.item.indent-tree"
 970        when = "item"
 971        [[bind]]
 972        keys = "M-<up>"
 973        command = "org.item.up"
 974        when = "item"
 975        [[bind]]
 976        keys = "M-<down>"
 977        command = "org.item.down"
 978        when = "item"
 979        [[bind]]
 980        keys = "C-c C-c"
 981        command = "org.ctrl-c-ctrl-c"
 982        when = "item"
 983        [[bind]]
 984        keys = "C-c C-x C-b"
 985        command = "org.checkbox.toggle"
 986        [[bind]]
 987        keys = "C-c C-w"
 988        command = "app.refile"
 989        [[bind]]
 990        keys = "C-c C-x C-s"
 991        command = "app.archive"
 992        [[bind]]
 993        keys = "C-c $"
 994        command = "app.archive"
 995        [[bind]]
 996        keys = "C-c ."
 997        command = "org.timestamp.active"
 998        [[bind]]
 999        keys = "C-c !"
1000        command = "org.timestamp.inactive"
1001        [[bind]]
1002        keys = "C-c C-s"
1003        command = "org.schedule"
1004        [[bind]]
1005        keys = "C-c C-d"
1006        command = "org.deadline"
1007        [[bind]]
1008        keys = "M-q"
1009        command = "org.fill-paragraph"
1010        [[bind]]
1011        keys = "C-c C-c"
1012        command = "org.ctrl-c-ctrl-c"
1013        when = "table"
1014        [[bind]]
1015        keys = "C-c C-c"
1016        command = "org.table.recalc-all"
1017        when = "tblfm"
1018        [[bind]]
1019        keys = "C-c *"
1020        command = "org.table.recalc"
1021        when = "table"
1022        [[bind]]
1023        keys = "C-c C-c"
1024        command = "org.babel.execute"
1025        when = "src"
1026        [[bind]]
1027        keys = "M-<up>"
1028        command = "org.table.row-up"
1029        when = "table"
1030        [[bind]]
1031        keys = "M-<down>"
1032        command = "org.table.row-down"
1033        when = "table"
1034        [[bind]]
1035        keys = "M-<left>"
1036        command = "org.table.column-left"
1037        when = "table"
1038        [[bind]]
1039        keys = "M-<right>"
1040        command = "org.table.column-right"
1041        when = "table"
1042        [[bind]]
1043        keys = "M-S-<right>"
1044        command = "org.table.insert-column"
1045        when = "table"
1046        [[bind]]
1047        keys = "M-S-<left>"
1048        command = "org.table.delete-column"
1049        when = "table"
1050        [[bind]]
1051        keys = "M-S-<up>"
1052        command = "org.table.kill-row"
1053        when = "table"
1054        [[bind]]
1055        keys = "M-S-<down>"
1056        command = "org.table.insert-row"
1057        when = "table"
1058        [[bind]]
1059        keys = "C-c -"
1060        command = "org.table.insert-hline"
1061        when = "table"
1062        [[bind]]
1063        keys = "C-c |"
1064        command = "org.table.create"
1065        [[bind]]
1066        keys = "S-<up>"
1067        command = "org.timestamp.up"
1068        when = "timestamp"
1069        [[bind]]
1070        keys = "S-<down>"
1071        command = "org.timestamp.down"
1072        when = "timestamp"
1073        [[bind]]
1074        keys = "S-<right>"
1075        command = "org.timestamp.day-later"
1076        when = "timestamp"
1077        [[bind]]
1078        keys = "S-<left>"
1079        command = "org.timestamp.day-earlier"
1080        when = "timestamp"
1081
1082        """
1083
1084    /// Standard Mac text keys stay as they are; org commands use Control-Command chords, which
1085    /// macOS text editing leaves free.
1086    static let macBindings = """
1087        [[bind]]
1088        keys = "C-TAB"
1089        command = "app.buffer.next"
1090        [[bind]]
1091        keys = "C-S-TAB"
1092        command = "app.buffer.previous"
1093        [[bind]]
1094        keys = "C-s-t"
1095        command = "org.todo.cycle"
1096        [[bind]]
1097        keys = "C-s-<up>"
1098        command = "org.priority.up"
1099        [[bind]]
1100        keys = "C-s-<down>"
1101        command = "org.priority.down"
1102        [[bind]]
1103        keys = "C-s-<left>"
1104        command = "org.heading.promote"
1105        [[bind]]
1106        keys = "C-s-<right>"
1107        command = "org.heading.demote"
1108        [[bind]]
1109        keys = "C-M-s-<left>"
1110        command = "org.subtree.promote"
1111        [[bind]]
1112        keys = "C-M-s-<right>"
1113        command = "org.subtree.demote"
1114        [[bind]]
1115        keys = "C-M-s-<up>"
1116        command = "org.subtree.up"
1117        [[bind]]
1118        keys = "C-M-s-<down>"
1119        command = "org.subtree.down"
1120        [[bind]]
1121        keys = "s-RET"
1122        command = "org.heading.insert"
1123        [[bind]]
1124        keys = "C-s-RET"
1125        command = "org.heading.insert-after-subtree"
1126        [[bind]]
1127        keys = "s-S-RET"
1128        command = "org.heading.insert-todo"
1129        [[bind]]
1130        keys = "M-s-<down>"
1131        command = "org.heading.next"
1132        [[bind]]
1133        keys = "M-s-<up>"
1134        command = "org.heading.previous"
1135        [[bind]]
1136        keys = "C-s-g"
1137        command = "org.tags.set"
1138        [[bind]]
1139        keys = "s-RET"
1140        command = "org.item.insert"
1141        when = "item"
1142        [[bind]]
1143        keys = "s-S-RET"
1144        command = "org.item.insert-checkbox"
1145        when = "item"
1146        [[bind]]
1147        keys = "C-s-<left>"
1148        command = "org.item.outdent"
1149        when = "item"
1150        [[bind]]
1151        keys = "C-s-<right>"
1152        command = "org.item.indent"
1153        when = "item"
1154        [[bind]]
1155        keys = "C-M-s-<left>"
1156        command = "org.item.outdent-tree"
1157        when = "item"
1158        [[bind]]
1159        keys = "C-M-s-<right>"
1160        command = "org.item.indent-tree"
1161        when = "item"
1162        [[bind]]
1163        keys = "C-M-s-<up>"
1164        command = "org.item.up"
1165        when = "item"
1166        [[bind]]
1167        keys = "C-M-s-<down>"
1168        command = "org.item.down"
1169        when = "item"
1170        [[bind]]
1171        keys = "C-s-c"
1172        command = "org.checkbox.toggle"
1173        [[bind]]
1174        keys = "C-s-w"
1175        command = "app.refile"
1176        [[bind]]
1177        keys = "C-s-a"
1178        command = "app.archive"
1179        [[bind]]
1180        keys = "C-s-."
1181        command = "org.timestamp.active"
1182        [[bind]]
1183        keys = "C-M-s-."
1184        command = "org.timestamp.inactive"
1185        [[bind]]
1186        keys = "C-s-s"
1187        command = "org.schedule"
1188        [[bind]]
1189        keys = "C-s-e"
1190        command = "org.deadline"
1191        [[bind]]
1192        keys = "C-s-p"
1193        command = "org.fill-paragraph"
1194        [[bind]]
1195        keys = "C-s-<up>"
1196        command = "org.table.row-up"
1197        when = "table"
1198        [[bind]]
1199        keys = "C-s-<down>"
1200        command = "org.table.row-down"
1201        when = "table"
1202        [[bind]]
1203        keys = "C-s-<left>"
1204        command = "org.table.column-left"
1205        when = "table"
1206        [[bind]]
1207        keys = "C-s-<right>"
1208        command = "org.table.column-right"
1209        when = "table"
1210        [[bind]]
1211        keys = "C-M-s-<right>"
1212        command = "org.table.insert-column"
1213        when = "table"
1214        [[bind]]
1215        keys = "C-M-s-<left>"
1216        command = "org.table.delete-column"
1217        when = "table"
1218        [[bind]]
1219        keys = "C-M-s-<up>"
1220        command = "org.table.kill-row"
1221        when = "table"
1222        [[bind]]
1223        keys = "C-M-s-<down>"
1224        command = "org.table.insert-row"
1225        when = "table"
1226        [[bind]]
1227        keys = "C-s--"
1228        command = "org.table.insert-hline"
1229        when = "table"
1230        [[bind]]
1231        keys = "C-s-\\\\"
1232        command = "org.table.create"
1233        [[bind]]
1234        keys = "C-s-<up>"
1235        command = "org.timestamp.up"
1236        when = "timestamp"
1237        [[bind]]
1238        keys = "C-s-<down>"
1239        command = "org.timestamp.down"
1240        when = "timestamp"
1241        [[bind]]
1242        keys = "C-s-<right>"
1243        command = "org.timestamp.day-later"
1244        when = "timestamp"
1245        [[bind]]
1246        keys = "C-s-<left>"
1247        command = "org.timestamp.day-earlier"
1248        when = "timestamp"
1249
1250        # Act at point, links, clocking, export and the rest of C-c.
1251        [[bind]]
1252        keys = "C-s-x"
1253        command = "org.ctrl-c-ctrl-c"
1254        [[bind]]
1255        keys = "C-s-x"
1256        command = "org.dblock.update"
1257        when = "dblock"
1258        [[bind]]
1259        keys = "C-s-x"
1260        command = "org.table.recalc-all"
1261        when = "tblfm"
1262        [[bind]]
1263        keys = "C-s-x"
1264        command = "org.babel.execute"
1265        when = "src"
1266        [[bind]]
1267        keys = "s-k"
1268        command = "org.link.insert"
1269        [[bind]]
1270        keys = "C-s-o"
1271        command = "org.link.open"
1272        [[bind]]
1273        keys = "C-s-l"
1274        command = "org.link.store"
1275        [[bind]]
1276        keys = "C-s-i"
1277        command = "app.clock.in"
1278        [[bind]]
1279        keys = "C-S-s-i"
1280        command = "app.clock.out"
1281        [[bind]]
1282        keys = "C-s-j"
1283        command = "app.clock.goto"
1284        [[bind]]
1285        keys = "C-M-s-i"
1286        command = "app.clock.in-recent"
1287        [[bind]]
1288        keys = "C-M-s-j"
1289        command = "app.clock.goto-recent"
1290        [[bind]]
1291        keys = "s-S-e"
1292        command = "app.export-dialog"
1293        [[bind]]
1294        keys = "C-s-n"
1295        command = "org.narrow.toggle"
1296        [[bind]]
1297        keys = "C-S-s-s"
1298        command = "org.sort"
1299        [[bind]]
1300        keys = "C-S-s-p"
1301        command = "org.property.read-and-set"
1302        [[bind]]
1303        keys = "C-S-s-f"
1304        command = "org.footnote.action"
1305        [[bind]]
1306        keys = "C-s-'"
1307        command = "org.edit-special"
1308        [[bind]]
1309        keys = "C-S-s-<right>"
1310        command = "org.todo.next"
1311        when = "heading"
1312        [[bind]]
1313        keys = "C-S-s-<left>"
1314        command = "org.todo.previous"
1315        when = "heading"
1316        [[bind]]
1317        keys = "C-S-s-<right>"
1318        command = "org.property.next-value"
1319        when = "property"
1320        [[bind]]
1321        keys = "C-S-s-<left>"
1322        command = "org.property.previous-value"
1323        when = "property"
1324        [[bind]]
1325        keys = "M-S-s-<down>"
1326        command = "org.heading.forward-same-level"
1327        [[bind]]
1328        keys = "M-S-s-<up>"
1329        command = "org.heading.backward-same-level"
1330        [[bind]]
1331        keys = "C-S-s-e"
1332        command = "org.effort.set"
1333        [[bind]]
1334        keys = "C-s-,"
1335        command = "org.priority.set"
1336        [[bind]]
1337        keys = "C-s-v"
1338        command = "org.babel.tangle"
1339
1340        """
1341}