Implement Tier 0 + Tier 1: scaffold and core modules for jemacs
ober
f9d8f465b7ceee29055a7a4efbbd5a9460750e32
new file mode 100644 --- /dev/null +++ b/Makefile @@ -0,0 +1,13 @@ +SCHEME = scheme +LIBDIRS = --libdirs lib:$(HOME)/mine/jerboa/lib:$(HOME)/mine/chez-pcre2 +export LD_LIBRARY_PATH := $(HOME)/mine/chez-pcre2:$(LD_LIBRARY_PATH) + +.PHONY: all test-tier0 clean + +all: test-tier0 + +test-tier0: + $(SCHEME) $(LIBDIRS) --script tests/test-tier0.ss + +clean: + find lib -name '*.so' -delete 2>/dev/null; true new file mode 100644 --- /dev/null +++ b/lib/jerboa-emacs/core.sls @@ -0,0 +1,2013 @@ +#!chezscheme +;;; core.sls — Shared core for jemacs +;;; +;;; Ported from gerbil-emacs/core.ss +;;; Backend-agnostic logic: keymap data structures, command registry, +;;; echo state, buffer metadata, app state, file I/O helpers. +;;; No Scintilla or TUI imports — this module is pure logic. + +(library (jerboa-emacs core) + (export + ;; Quit flag + keyboard-quit-exception? make-keyboard-quit-exception + quit-flag-set! quit-flag-clear! quit-flag? + + ;; Keymap data structures + make-keymap keymap-bind! keymap-lookup keymap-entries + key-state? make-key-state + key-state-keymap key-state-keymap-set! + key-state-prefix-keys key-state-prefix-keys-set! + make-initial-key-state + + ;; Global keymaps + *global-keymap* *ctrl-x-map* *meta-g-map* *help-map* + *ctrl-x-r-map* *ctrl-c-map* *ctrl-c-l-map* *ctrl-c-m-map* + lsp-server-command lsp-server-command-set! + *meta-s-map* *ctrl-x-4-map* *ctrl-x-5-map* *ctrl-x-p-map* + *all-commands* + setup-default-bindings! + + ;; Mode keymaps + *mode-keymaps* *buffer-name-mode-map* + mode-keymap-set! mode-keymap-get mode-keymap-lookup + setup-mode-keymaps! + + ;; Echo state + echo-state? make-echo-state + echo-state-message echo-state-message-set! + echo-state-error? echo-state-error?-set! + make-initial-echo-state + echo-message! echo-error! echo-clear! + notification-push! notification-get-recent + notification-log + + ;; Hooks + *hooks* add-hook! remove-hook! run-hooks! + + ;; Buffer metadata + buffer? make-buffer + buffer-name buffer-name-set! + buffer-file-path buffer-file-path-set! + buffer-doc-pointer buffer-doc-pointer-set! + buffer-mark buffer-mark-set! + buffer-modified buffer-modified-set! + buffer-lexer-lang buffer-lexer-lang-set! + buffer-backup-done? buffer-backup-done?-set! + buffer-list buffer-list-add! buffer-list-remove! + buffer-by-name buffer-scratch-name + + ;; App state + app-state? make-app-state + app-state-frame app-state-frame-set! + app-state-echo app-state-echo-set! + app-state-key-state app-state-key-state-set! + app-state-running app-state-running-set! + app-state-last-search app-state-last-search-set! + app-state-kill-ring app-state-kill-ring-set! + app-state-kill-ring-idx app-state-kill-ring-idx-set! + app-state-last-yank-pos app-state-last-yank-pos-set! + app-state-last-yank-len app-state-last-yank-len-set! + app-state-last-compile app-state-last-compile-set! + app-state-bookmarks app-state-bookmarks-set! + app-state-rect-kill app-state-rect-kill-set! + app-state-dabbrev-state app-state-dabbrev-state-set! + app-state-macro-recording app-state-macro-recording-set! + app-state-macro-last app-state-macro-last-set! + app-state-macro-named app-state-macro-named-set! + app-state-mark-ring app-state-mark-ring-set! + app-state-registers app-state-registers-set! + app-state-last-command app-state-last-command-set! + app-state-prefix-arg app-state-prefix-arg-set! + app-state-prefix-digit-mode? app-state-prefix-digit-mode?-set! + app-state-key-handler app-state-key-handler-set! + app-state-winner-history app-state-winner-history-set! + app-state-winner-history-idx app-state-winner-history-idx-set! + app-state-tabs app-state-tabs-set! + app-state-current-tab-idx app-state-current-tab-idx-set! + app-state-key-lossage app-state-key-lossage-set! + new-app-state get-prefix-arg + + ;; Frame management + frame-list frame-list-set! + current-frame-idx current-frame-idx-set! + frame-count + + ;; Key lossage + key-lossage-record! key-lossage->string + + ;; Command registry + register-command! find-command execute-command! + *command-docs* + register-command-doc! command-doc command-name->description + find-keybinding-for-command setup-command-docs! + + ;; Shared helpers + electric-indent-mode? electric-indent-mode-set! + brace-char? safe-string-trim safe-string-trim-both + + ;; File I/O + read-file-as-string write-string-to-file + + ;; Dired + *dired-entries* + dired-buffer? strip-trailing-slash dired-format-listing + + ;; Logging + init-jemacs-log! jemacs-log! + init-verbose-log! verbose-log! + + ;; Captured output + append-error-log! append-output-log! + get-error-log get-output-log + clear-error-log! clear-output-log! + has-captured-output? + + ;; REPL + repl-buffer? *repl-state* + eval-expression-string + load-user-file! load-user-string! + + ;; Fuzzy matching + fuzzy-match? fuzzy-score fuzzy-filter-sort + + ;; Paredit strict mode + paredit-strict-mode? paredit-strict-mode-set! + + ;; Helm mode + helm-mode? helm-mode-set! + + ;; Key translation + *key-translation-map* + key-translate! key-translate-char + + ;; Key-chord + *chord-map* *chord-first-chars* + chord-timeout chord-timeout-set! + chord-mode? chord-mode-set! + key-chord-define-global chord-lookup chord-start-char? + + ;; Repeat-mode + repeat-mode? repeat-mode-set! + *repeat-maps* + active-repeat-map active-repeat-map-set! + register-repeat-map! register-default-repeat-maps! + repeat-map-for-command repeat-map-lookup repeat-map-hint + clear-repeat-map! + + ;; Image buffer + *editor-window-map* *image-buffer-state* + image-buffer? + find-defun-boundaries + + ;; Re-exports from face + face? make-face face-fg face-bg face-bold face-italic face-underline + new-face define-face! face-get face-ref set-face-attribute! face-clear! + default-font-family default-font-size + set-default-font! get-default-font parse-hex-color rgb->hex + define-standard-faces! set-frame-font + load-theme! current-theme-name + face-fg-rgb face-bg-rgb face-has-bold? face-has-italic? face-has-underline? + + ;; Re-exports from themes + register-theme! theme-get theme-names + theme-dark theme-light theme-solarized-dark theme-solarized-light + theme-monokai theme-gruvbox-dark theme-gruvbox-light + theme-dracula theme-nord theme-zenburn + + ;; Re-exports from customize + defvar! custom-get custom-set! custom-reset! + custom-describe custom-list-group custom-list-all + custom-groups custom-registered? *custom-registry* + defhook! hook-doc hook-list-all) + + (import (except (chezscheme) + make-hash-table hash-table? iota 1+ 1- sort sort!) + (jerboa core) + (jerboa runtime) + (std sugar) + (std sort) + (std string) + (only (std srfi srfi-19) current-date date->string) + (std misc rwlock) + (jerboa-emacs customize) + (jerboa-emacs face) + (jerboa-emacs themes)) + + ;;;============================================================================ + ;;; Quit flag (C-g subprocess interruption) + ;;;============================================================================ + + (defstruct keyboard-quit-exception ()) + + (def *quit-flag* #f) + + (def (quit-flag-set!) (set! *quit-flag* #t)) + (def (quit-flag-clear!) (set! *quit-flag* #f)) + (def (quit-flag?) *quit-flag*) + + ;;;============================================================================ + ;;; Keymap data structure + ;;;============================================================================ + + (def (make-keymap) (make-hash-table)) + + (def (keymap-bind! km key-str value) + (hash-put! km key-str value)) + + (def (keymap-lookup km key-str) + (hash-get km key-str)) + + (def (keymap-entries km) + (hash->list km)) + + ;;;============================================================================ + ;;; Key state machine for multi-key sequences + ;;;============================================================================ + + (defstruct key-state (keymap prefix-keys)) + + ;;; Global keymaps + (def *global-keymap* (make-keymap)) + (def *ctrl-x-map* (make-keymap)) + (def *ctrl-x-r-map* (make-keymap)) + (def *ctrl-c-map* (make-keymap)) + (def *ctrl-c-l-map* (make-keymap)) + (def *ctrl-c-m-map* (make-keymap)) + (def *lsp-server-command* "chez-lsp") + (def (lsp-server-command) *lsp-server-command*) + (def (lsp-server-command-set! v) (set! *lsp-server-command* v)) + (def *meta-g-map* (make-keymap)) + (def *help-map* (make-keymap)) + (def *meta-s-map* (make-keymap)) + (def *ctrl-x-4-map* (make-keymap)) + (def *ctrl-x-5-map* (make-keymap)) + (def *ctrl-x-p-map* (make-keymap)) + + ;;;============================================================================ + ;;; Mode keymaps — per-mode key bindings + ;;;============================================================================ + + (def *mode-keymaps* (make-hash-table)) + (def *buffer-name-mode-map* (make-hash-table)) + + (def (mode-keymap-set! mode-sym km) + (hash-put! *mode-keymaps* mode-sym km)) + + (def (mode-keymap-get mode-sym) + (hash-get *mode-keymaps* mode-sym)) + + (def (mode-keymap-lookup buf key-str) + (let* ((lang (buffer-lexer-lang buf)) + (km (or (hash-get *mode-keymaps* lang) + (hash-get *buffer-name-mode-map* (buffer-name buf))))) + (and km (keymap-lookup km key-str)))) + + (def (setup-mode-keymaps!) + ;; Buffer name -> mode mapping for special buffers + (for-each + (lambda (pair) + (hash-put! *buffer-name-mode-map* (car pair) (cdr pair))) + '(("*compilation*" . compilation) ("*Grep*" . grep) ("*Occur*" . occur) + ("*calendar*" . calendar) ("*eww*" . eww) ("*Magit*" . magit) + ("*Magit: Commit*" . magit-commit) ("*Magit Log*" . magit-log) + ("*Magit Commit*" . magit-commit-view) ("*Magit Stash*" . magit-stash) + ("*Magit Stash Diff*" . magit-stash-diff) ("*Org Capture*" . org-capture) + ("*IBBuffer*" . ibuffer))) + + ;; Dired mode + (let ((km (make-keymap))) + (for-each (lambda (p) (keymap-bind! km (car p) (cdr p))) + '(("n" . next-line) ("p" . previous-line) ("g" . revert-buffer) + ("d" . dired-do-delete) ("R" . dired-do-rename) ("C" . dired-do-copy) + ("+" . dired-create-directory) ("q" . kill-buffer-cmd) ("^" . dired) + ("m" . dired-mark) ("u" . dired-unmark) ("U" . dired-unmark-all) + ("t" . dired-toggle-marks) ("D" . dired-do-delete-marked) ("x" . dired-do-delete-marked))) + (mode-keymap-set! 'dired km)) + + ;; Compilation mode + (let ((km (make-keymap))) + (for-each (lambda (p) (keymap-bind! km (car p) (cdr p))) + '(("n" . next-error) ("p" . previous-error) ("g" . recompile) ("q" . kill-buffer-cmd))) + (mode-keymap-set! 'compilation km)) + + ;; Grep results mode + (let ((km (make-keymap))) + (for-each (lambda (p) (keymap-bind! km (car p) (cdr p))) + '(("n" . next-grep-result) ("p" . previous-grep-result) ("q" . kill-buffer-cmd))) + (mode-keymap-set! 'grep km)) + + ;; Buffer list mode + (let ((km (make-keymap))) + (for-each (lambda (p) (keymap-bind! km (car p) (cdr p))) + '(("n" . next-line) ("p" . previous-line) ("q" . kill-buffer-cmd))) + (mode-keymap-set! 'buffer-list km)) + + ;; IBBuffer mode + (let ((km (make-keymap))) + (for-each (lambda (p) (keymap-bind! km (car p) (cdr p))) + '(("d" . ibuffer-mark-delete) ("s" . ibuffer-mark-save) + ("u" . ibuffer-unmark) ("x" . ibuffer-execute) ("RET" . ibuffer-goto-buffer) + ("/" . ibuffer-filter-name) ("S" . ibuffer-sort-name) ("z" . ibuffer-sort-size) + ("t" . ibuffer-toggle-marks) ("g" . ibuffer-refresh) + ("n" . next-line) ("p" . previous-line) ("q" . kill-buffer-cmd))) + (mode-keymap-set! 'ibuffer km)) + + ;; Occur mode + (let ((km (make-keymap))) + (for-each (lambda (p) (keymap-bind! km (car p) (cdr p))) + '(("n" . next-line) ("p" . previous-line) ("q" . kill-buffer-cmd))) + (mode-keymap-set! 'occur km)) + + ;; Calendar mode + (let ((km (make-keymap))) + (for-each (lambda (p) (keymap-bind! km (car p) (cdr p))) + '(("p" . calendar-prev-month) ("n" . calendar-next-month) + ("<" . calendar-prev-year) (">" . calendar-next-year) + ("." . calendar-today) ("q" . kill-buffer-cmd))) + (mode-keymap-set! 'calendar km)) + + ;; EWW browser mode + (let ((km (make-keymap))) + (for-each (lambda (p) (keymap-bind! km (car p) (cdr p))) + '(("g" . eww) ("l" . eww-back) ("r" . eww-reload) ("q" . kill-buffer-cmd))) + (mode-keymap-set! 'eww km)) + + ;; Magit mode + (let ((km (make-keymap))) + (for-each (lambda (p) (keymap-bind! km (car p) (cdr p))) + '(("s" . magit-stage) ("S" . magit-stage-all) ("u" . magit-unstage) + ("c" . magit-commit) ("a" . magit-amend) ("d" . magit-diff) + ("l" . magit-log) ("b" . magit-branch) ("B" . magit-blame) + ("f" . magit-fetch) ("F" . magit-pull) ("P" . magit-push) + ("r" . magit-rebase) ("m" . magit-merge) ("z" . magit-stash) + ("Z" . magit-stash-pop) ("x" . magit-cherry-pick) ("X" . magit-revert-commit) + ("w" . magit-worktree) ("k" . magit-checkout) ("g" . magit-status) + ("n" . next-line) ("p" . previous-line) ("q" . kill-buffer-cmd))) + (mode-keymap-set! 'magit km)) + + ;; Magit commit mode + (let ((km (make-keymap))) + (keymap-bind! km "C-c C-c" 'magit-commit-finalize) + (keymap-bind! km "C-c C-k" 'magit-commit-abort) + (mode-keymap-set! 'magit-commit km)) + + ;; Magit log mode + (let ((km (make-keymap))) + (for-each (lambda (p) (keymap-bind! km (car p) (cdr p))) + '(("RET" . magit-log-show-commit) ("n" . next-line) ("p" . previous-line) ("q" . kill-buffer-cmd))) + (mode-keymap-set! 'magit-log km)) + + ;; Magit commit/diff view (shared by stash-diff) + (let ((km (make-keymap))) + (for-each (lambda (p) (keymap-bind! km (car p) (cdr p))) + '(("n" . next-line) ("p" . previous-line) ("q" . kill-buffer-cmd))) + (mode-keymap-set! 'magit-commit-view km) + (mode-keymap-set! 'magit-stash-diff km)) + + ;; Magit stash list + (let ((km (make-keymap))) + (for-each (lambda (p) (keymap-bind! km (car p) (cdr p))) + '(("RET" . magit-stash-show) ("n" . next-line) ("p" . previous-line) ("q" . kill-buffer-cmd))) + (mode-keymap-set! 'magit-stash km)) + + ;; Image mode + (let ((km (make-keymap))) + (for-each (lambda (p) (keymap-bind! km (car p) (cdr p))) + '(("+" . image-zoom-in) ("=" . image-zoom-in) ("-" . image-zoom-out) + ("0" . image-zoom-fit) ("1" . image-zoom-reset) ("q" . kill-buffer-cmd))) + (mode-keymap-set! 'image km)) + + ;; Org capture mode + (let ((km (make-keymap))) + (keymap-bind! km "C-c C-c" 'org-capture-finalize) + (keymap-bind! km "C-c C-k" 'org-capture-abort) + (mode-keymap-set! 'org-capture km))) + + (def (make-initial-key-state) + (make-key-state *global-keymap* '())) + + ;;;============================================================================ + ;;; Default Emacs-like keybindings + ;;;============================================================================ + + (def (setup-default-bindings!) + ;; C-x prefix + (keymap-bind! *global-keymap* "C-x" *ctrl-x-map*) + + ;; Navigation + (keymap-bind! *global-keymap* "C-f" 'forward-char) + (keymap-bind! *global-keymap* "C-b" 'backward-char) + (keymap-bind! *global-keymap* "C-n" 'next-line) + (keymap-bind! *global-keymap* "C-p" 'previous-line) + (keymap-bind! *global-keymap* "C-a" 'beginning-of-line) + (keymap-bind! *global-keymap* "C-e" 'end-of-line) + (keymap-bind! *global-keymap* "C-v" 'scroll-down) + (keymap-bind! *global-keymap* "C-l" 'recenter-top-bottom) + + ;; Arrow keys and navigation + (keymap-bind! *global-keymap* "<up>" 'previous-line) + (keymap-bind! *global-keymap* "<down>" 'next-line) + (keymap-bind! *global-keymap* "<left>" 'backward-char) + (keymap-bind! *global-keymap* "<right>" 'forward-char) + (keymap-bind! *global-keymap* "<home>" 'beginning-of-line) + (keymap-bind! *global-keymap* "<end>" 'end-of-line) + (keymap-bind! *global-keymap* "<prior>" 'scroll-up) + (keymap-bind! *global-keymap* "<next>" 'scroll-down) + (keymap-bind! *global-keymap* "<delete>" 'delete-char) + + ;; Alt/Meta navigation + (keymap-bind! *global-keymap* "M-f" 'forward-word) + (keymap-bind! *global-keymap* "M-b" 'backward-word) + (keymap-bind! *global-keymap* "M-v" 'scroll-up) + (keymap-bind! *global-keymap* "M-<" 'beginning-of-buffer) + (keymap-bind! *global-keymap* "M->" 'end-of-buffer) + + ;; Editing + (keymap-bind! *global-keymap* "C-d" 'delete-char) + (keymap-bind! *global-keymap* "DEL" 'backward-delete-char) + (keymap-bind! *global-keymap* "C-h" 'backward-delete-char) + (keymap-bind! *global-keymap* "C-k" 'kill-line) + (keymap-bind! *global-keymap* "C-y" 'yank) + (keymap-bind! *global-keymap* "C-w" 'kill-region) + (keymap-bind! *global-keymap* "M-w" 'copy-region) + (keymap-bind! *global-keymap* "C-_" 'undo) + (keymap-bind! *global-keymap* "C-/" 'undo) + (keymap-bind! *global-keymap* "C-m" 'newline) + (keymap-bind! *global-keymap* "C-j" 'newline) + (keymap-bind! *global-keymap* "C-o" 'open-line) + + ;; Mark + (keymap-bind! *global-keymap* "C-@" 'set-mark) + + ;; Search + (keymap-bind! *global-keymap* "C-s" 'search-forward) + (keymap-bind! *global-keymap* "C-r" 'search-backward) + + ;; Function keys + (keymap-bind! *global-keymap* "<f11>" 'uncomment-region) + (keymap-bind! *global-keymap* "<f12>" 'comment-region) + + ;; Universal argument + (keymap-bind! *global-keymap* "C-u" 'universal-argument) + + ;; Digit arguments + (keymap-bind! *global-keymap* "M-0" 'digit-argument-0) + (keymap-bind! *global-keymap* "M-1" 'digit-argument-1) + (keymap-bind! *global-keymap* "M-2" 'digit-argument-2) + (keymap-bind! *global-keymap* "M-3" 'digit-argument-3) + (keymap-bind! *global-keymap* "M-4" 'digit-argument-4) + (keymap-bind! *global-keymap* "M-5" 'digit-argument-5) + (keymap-bind! *global-keymap* "M-6" 'digit-argument-6) + (keymap-bind! *global-keymap* "M-7" 'digit-argument-7) + (keymap-bind! *global-keymap* "M-8" 'digit-argument-8) + (keymap-bind! *global-keymap* "M-9" 'digit-argument-9) + (keymap-bind! *global-keymap* "M--" 'negative-argument) + + ;; Misc + (keymap-bind! *global-keymap* "C-g" 'keyboard-quit) + + ;; C-x commands + (keymap-bind! *ctrl-x-map* "C-s" 'save-buffer) + (keymap-bind! *ctrl-x-map* "C-f" 'find-file) + (keymap-bind! *ctrl-x-map* "C-r" 'recentf-open) + (keymap-bind! *ctrl-x-map* "C-c" 'quit) + (keymap-bind! *ctrl-x-map* "b" 'switch-buffer) + (keymap-bind! *ctrl-x-map* "k" 'kill-buffer-cmd) + (keymap-bind! *ctrl-x-map* "2" 'split-window) + (keymap-bind! *ctrl-x-map* "o" 'other-window) + (keymap-bind! *ctrl-x-map* "0" 'delete-window) + (keymap-bind! *ctrl-x-map* "1" 'delete-other-windows) + (keymap-bind! *ctrl-x-map* "3" 'split-window-right) + + ;; REPL + (keymap-bind! *global-keymap* "M-:" 'eval-expression) + ;; C-c prefix + (keymap-bind! *global-keymap* "C-c" *ctrl-c-map*) + (keymap-bind! *ctrl-c-map* "z" 'repl) + + ;; C-x r prefix (registers/bookmarks/rectangles) + (keymap-bind! *ctrl-x-map* "r" *ctrl-x-r-map*) + (keymap-bind! *ctrl-x-r-map* "m" 'bookmark-set) + (keymap-bind! *ctrl-x-r-map* "b" 'bookmark-jump) + (keymap-bind! *ctrl-x-r-map* "l" 'bookmark-list) + (keymap-bind! *ctrl-x-r-map* "k" 'kill-rectangle) + (keymap-bind! *ctrl-x-r-map* "d" 'delete-rectangle) + (keymap-bind! *ctrl-x-r-map* "y" 'yank-rectangle) + + ;; M-x + (keymap-bind! *global-keymap* "M-x" 'execute-extended-command) + + ;; Goto line (M-g prefix map) + (keymap-bind! *global-keymap* "M-g" *meta-g-map*) + (keymap-bind! *meta-g-map* "g" 'goto-line) + (keymap-bind! *meta-g-map* "M-g" 'goto-line) + + ;; Help (C-h prefix map) + (keymap-bind! *global-keymap* "C-h" *help-map*) + (keymap-bind! *help-map* "k" 'describe-key) + (keymap-bind! *help-map* "b" 'list-bindings) + (keymap-bind! *help-map* "f" 'describe-command) + + ;; Buffer list + (keymap-bind! *ctrl-x-map* "C-b" 'list-buffers) + + ;; Query replace + (keymap-bind! *global-keymap* "M-%" 'query-replace) + + ;; Regex search and replace + (keymap-bind! *global-keymap* "C-M-s" 'isearch-forward-regexp) + (keymap-bind! *global-keymap* "C-M-%" 'query-replace-regexp) + (keymap-bind! *global-keymap* "C-M-i" 'complete-at-point) + + ;; Tab + (keymap-bind! *global-keymap* "TAB" 'indent-or-complete) + + ;; Eshell, Shell + (keymap-bind! *ctrl-c-map* "e" 'eshell) + (keymap-bind! *ctrl-c-map* "$" 'shell) + + ;; Redo + (keymap-bind! *global-keymap* "M-_" 'redo) + + ;; Toggles + (keymap-bind! *ctrl-x-map* "l" 'toggle-line-numbers) + (keymap-bind! *ctrl-x-map* "w" 'toggle-word-wrap) + (keymap-bind! *ctrl-x-map* "t" 'toggle-whitespace) + + ;; Zoom + (keymap-bind! *global-keymap* "C-=" 'zoom-in) + (keymap-bind! *global-keymap* "C--" 'zoom-out) + (keymap-bind! *ctrl-x-map* "C-0" 'zoom-reset) + + ;; Select all + (keymap-bind! *ctrl-x-map* "h" 'select-all) + + ;; Duplicate line + (keymap-bind! *ctrl-x-map* "d" 'dired) + + ;; Comment toggle + (keymap-bind! *global-keymap* "M-;" 'toggle-comment) + + ;; Transpose chars + (keymap-bind! *global-keymap* "C-t" 'transpose-chars) + + ;; Case + (keymap-bind! *global-keymap* "M-u" 'upcase-word) + (keymap-bind! *global-keymap* "M-l" 'downcase-word) + (keymap-bind! *global-keymap* "M-c" 'capitalize-word) + + ;; Kill word + (keymap-bind! *global-keymap* "M-d" 'kill-word) + + ;; What line + (keymap-bind! *meta-g-map* "l" 'what-line) + + ;; Write file (save as) + (keymap-bind! *ctrl-x-map* "C-w" 'write-file) + + ;; Beginning/end of defun + (keymap-bind! *global-keymap* "M-a" 'backward-sentence) + (keymap-bind! *global-keymap* "M-e" 'forward-sentence) + + ;; Count words + (keymap-bind! *global-keymap* "M-=" 'count-words) + + ;; Yank-pop + (keymap-bind! *global-keymap* "M-y" 'yank-pop) + + ;; Occur (search prefix M-s) + (keymap-bind! *global-keymap* "M-s" *meta-s-map*) + (keymap-bind! *meta-s-map* "o" 'occur) + + ;; Compile + (keymap-bind! *ctrl-x-map* "c" 'compile) + + ;; Pipe region to shell + (keymap-bind! *global-keymap* "M-|" 'shell-command-on-region) + + ;; Sort lines + (keymap-bind! *ctrl-c-map* "^" 'sort-lines) + + ;; Go to matching paren + (keymap-bind! *ctrl-c-map* "p" 'goto-matching-paren) + + ;; Join lines + (keymap-bind! *global-keymap* "M-j" 'join-line) + + ;; Delete blank lines + (keymap-bind! *ctrl-x-map* "C-o" 'delete-blank-lines) + + ;; Indent region + (keymap-bind! *ctrl-c-map* "TAB" 'indent-region) + + ;; Case region + (keymap-bind! *ctrl-x-map* "C-l" 'downcase-region) + (keymap-bind! *ctrl-x-map* "C-u" 'upcase-region) + + ;; Shell command + (keymap-bind! *global-keymap* "M-!" 'shell-command) + + ;; Fill paragraph + (keymap-bind! *global-keymap* "M-q" 'fill-paragraph) + + ;; Insert file + (keymap-bind! *ctrl-x-map* "i" 'insert-file) + + ;; Dynamic abbreviation / hippie expand + (keymap-bind! *global-keymap* "M-/" 'hippie-expand) + + ;; Xref + (keymap-bind! *global-keymap* "M-." 'goto-definition) + (keymap-bind! *global-keymap* "M-," 'xref-back) + + ;; What cursor position + (keymap-bind! *ctrl-x-map* "=" 'what-cursor-position) + + ;; Keyboard macros + (keymap-bind! *ctrl-x-map* "(" 'start-kbd-macro) + (keymap-bind! *ctrl-x-map* ")" 'end-kbd-macro) + (keymap-bind! *ctrl-x-map* "e" 'call-last-kbd-macro) + + ;; Mark ring + (keymap-bind! *ctrl-c-map* "SPC" 'pop-mark) + + ;; Registers + (keymap-bind! *ctrl-x-r-map* "s" 'copy-to-register) + (keymap-bind! *ctrl-x-r-map* "i" 'insert-register) + (keymap-bind! *ctrl-x-r-map* "SPC" 'point-to-register) + (keymap-bind! *ctrl-x-r-map* "j" 'jump-to-register) + (keymap-bind! *ctrl-x-r-map* "w" 'window-configuration-to-register) + (keymap-bind! *ctrl-x-r-map* "f" 'file-to-register) + + ;; Backward kill word + (keymap-bind! *global-keymap* "M-DEL" 'backward-kill-word) + + ;; Zap to char + (keymap-bind! *global-keymap* "M-z" 'zap-to-char) + + ;; Go to char position + (keymap-bind! *meta-g-map* "c" 'goto-char) + + ;; Transpose + (keymap-bind! *global-keymap* "M-t" 'transpose-words) + (keymap-bind! *ctrl-x-map* "C-t" 'transpose-lines) + + ;; Repeat + (keymap-bind! *ctrl-x-map* "z" 'repeat) + + ;; Just one space + (keymap-bind! *global-keymap* "M-SPC" 'just-one-space) + + ;; Next/previous error + (keymap-bind! *meta-g-map* "n" 'next-error) + (keymap-bind! *meta-g-map* "p" 'previous-error) + (keymap-bind! *meta-g-map* "M-n" 'next-error) + (keymap-bind! *meta-g-map* "M-p" 'previous-error) + + ;; Kill whole line + (keymap-bind! *ctrl-c-map* "k" 'kill-whole-line) + + ;; Move line up/down + (keymap-bind! *global-keymap* "M-<up>" 'move-line-up) + (keymap-bind! *global-keymap* "M-<down>" 'move-line-down) + + ;; Pipe buffer + (keymap-bind! *ctrl-c-map* "!" 'pipe-buffer) + + ;; Narrow/widen + (keymap-bind! *ctrl-c-map* "n" 'narrow-to-region) + (keymap-bind! *ctrl-c-map* "w" 'widen) + + ;; String insert + (keymap-bind! *ctrl-c-map* "i" 'string-insert-file) + + ;; Rectangle + (keymap-bind! *ctrl-x-r-map* "t" 'string-rectangle) + (keymap-bind! *ctrl-x-r-map* "o" 'open-rectangle) + + ;; Number lines, reverse region + (keymap-bind! *ctrl-c-map* "#" 'number-lines) + (keymap-bind! *ctrl-c-map* "r" 'reverse-region) + + ;; Flush/keep lines + (keymap-bind! *meta-s-map* "f" 'flush-lines) + (keymap-bind! *meta-s-map* "k" 'keep-lines) + + ;; Align regexp + (keymap-bind! *ctrl-c-map* "a" 'align-regexp) + + ;; Sort fields + (keymap-bind! *ctrl-c-map* "s" 'sort-fields) + + ;; Mark word, mark paragraph, paragraph navigation + (keymap-bind! *global-keymap* "M-@" 'mark-word) + (keymap-bind! *global-keymap* "M-h" 'mark-paragraph) + (keymap-bind! *global-keymap* "M-}" 'forward-paragraph) + (keymap-bind! *global-keymap* "M-{" 'backward-paragraph) + + ;; Back to indentation, delete indentation + (keymap-bind! *global-keymap* "M-m" 'back-to-indentation) + (keymap-bind! *global-keymap* "M-^" 'delete-indentation) + + ;; Exchange point and mark + (keymap-bind! *ctrl-x-map* "C-x" 'exchange-point-and-mark) + + ;; C-c l → LSP prefix map + (keymap-bind! *ctrl-c-map* "l" *ctrl-c-l-map*) + + ;; Copy line + (keymap-bind! *ctrl-c-map* "c" 'copy-line) + + ;; Help extras + (keymap-bind! *help-map* "w" 'where-is) + (keymap-bind! *help-map* "a" 'apropos-command) + (keymap-bind! *ctrl-x-map* "C-q" 'toggle-read-only) + (keymap-bind! *ctrl-x-r-map* "n" 'rename-buffer) + + ;; Other-window commands (C-x 4 prefix) + (keymap-bind! *ctrl-x-map* "4" *ctrl-x-4-map*) + (keymap-bind! *ctrl-x-4-map* "b" 'switch-buffer-other-window) + (keymap-bind! *ctrl-x-4-map* "f" 'find-file-other-window) + + ;; Frame commands (C-x 5 prefix) + (keymap-bind! *ctrl-x-map* "5" *ctrl-x-5-map*) + (keymap-bind! *ctrl-x-5-map* "2" 'make-frame-command) + (keymap-bind! *ctrl-x-5-map* "0" 'delete-frame) + (keymap-bind! *ctrl-x-5-map* "o" 'other-frame) + (keymap-bind! *ctrl-x-5-map* "f" 'find-file-other-frame) + (keymap-bind! *ctrl-x-5-map* "b" 'switch-to-buffer-other-frame) + + ;; Text transforms + (keymap-bind! *ctrl-c-map* "t" 'tabify) + (keymap-bind! *ctrl-c-map* "3" 'rot13-region) + (keymap-bind! *ctrl-c-map* "x" 'hexl-mode) + + ;; Count matches, dedup + (keymap-bind! *meta-s-map* "c" 'count-matches) + (keymap-bind! *ctrl-c-map* "u" 'delete-duplicate-lines) + + ;; Diff, checksum + (keymap-bind! *ctrl-c-map* "d" 'diff-buffer-with-file) + (keymap-bind! *ctrl-c-map* "5" 'checksum) + + ;; Async shell command + (keymap-bind! *global-keymap* "M-&" 'async-shell-command) + + ;; Selective display + (keymap-bind! *ctrl-x-map* "$" 'set-selective-display) + + ;; Grep buffer + (keymap-bind! *meta-s-map* "g" 'grep-buffer) + (keymap-bind! *meta-s-map* "r" 'consult-ripgrep) + + ;; Insert date, insert char + (keymap-bind! *ctrl-c-map* "D" 'insert-date) + (keymap-bind! *ctrl-c-map* "8" 'insert-char) + + ;; Eval + (keymap-bind! *ctrl-c-map* "E" 'eval-buffer) + (keymap-bind! *ctrl-c-map* "v" 'eval-region) + (keymap-bind! *ctrl-x-map* "C-e" 'eval-last-sexp) + (keymap-bind! *ctrl-c-map* "C-e" 'eval-last-sexp) + (keymap-bind! *ctrl-c-map* "C-d" 'eval-defun) + + ;; Org-mode + (keymap-bind! *ctrl-c-map* "C-n" 'org-next-heading) + (keymap-bind! *ctrl-c-map* "C-p" 'org-prev-heading) + (keymap-bind! *ctrl-c-map* "C-t" 'org-todo) + (keymap-bind! *ctrl-c-map* "C-l" 'org-link) + (keymap-bind! *ctrl-c-map* "C-o" 'org-open-at-point) + (keymap-bind! *ctrl-c-map* "C-s" 'org-schedule) + (keymap-bind! *ctrl-c-map* "C-q" 'org-set-tags) + (keymap-bind! *ctrl-c-map* "," 'org-priority) + + ;; Clone buffer, scratch + (keymap-bind! *ctrl-c-map* "b" 'clone-buffer) + (keymap-bind! *ctrl-c-map* "S" 'scratch-buffer) + + ;; Save some buffers + (keymap-bind! *ctrl-x-map* "s" 'save-some-buffers) + + ;; Revert quick + (keymap-bind! *ctrl-c-map* "R" 'revert-buffer-quick) + + ;; Toggle highlighting + (keymap-bind! *ctrl-c-map* "f" 'toggle-highlighting) + + ;; Display time + (keymap-bind! *ctrl-c-map* "T" 'display-time) + + ;; Calculator + (keymap-bind! *ctrl-c-map* "=" 'calc) + + ;; Case fold search toggle + (keymap-bind! *ctrl-c-map* "C" 'toggle-case-fold-search) + + ;; Describe bindings + (keymap-bind! *help-map* "B" 'describe-bindings) + + ;; Center line + (keymap-bind! *global-keymap* "M-o" 'center-line) + + ;; What face + (keymap-bind! *ctrl-c-map* "F" 'what-face) + + ;; List processes + (keymap-bind! *ctrl-c-map* "P" 'list-processes) + + ;; View messages + (keymap-bind! *ctrl-c-map* "m" 'view-messages) + + ;; Auto fill toggle + (keymap-bind! *ctrl-c-map* "q" 'toggle-auto-fill) + + ;; Delete trailing whitespace + (keymap-bind! *ctrl-c-map* "W" 'delete-trailing-whitespace) + + ;; Ediff buffers + (keymap-bind! *ctrl-c-map* "B" 'ediff-buffers) + + ;; Rename/delete file + (keymap-bind! *ctrl-c-map* "M" 'rename-file-and-buffer) + + ;; Sudo write + (keymap-bind! *ctrl-c-map* "X" 'sudo-write) + + ;; Sort numeric + (keymap-bind! *ctrl-c-map* "N" 'sort-numeric) + + ;; Count words region + (keymap-bind! *ctrl-c-map* "L" 'count-words-region) + + ;; Overwrite mode + (keymap-bind! *global-keymap* "<insert>" 'toggle-overwrite-mode) + + ;; Visual line mode + (keymap-bind! *ctrl-c-map* "V" 'toggle-visual-line-mode) + + ;; Fill column + (keymap-bind! *ctrl-c-map* "." 'set-fill-column) + (keymap-bind! *ctrl-c-map* "|" 'toggle-fill-column-indicator) + + ;; Repeat complex command + (keymap-bind! *ctrl-c-map* "Z" 'repeat-complex-command) + + ;; Eldoc + (keymap-bind! *ctrl-c-map* "I" 'eldoc) + + ;; Highlight symbol + (keymap-bind! *ctrl-c-map* "h" 'highlight-symbol) + (keymap-bind! *ctrl-c-map* "H" 'clear-highlight) + + ;; Indent rigidly + (keymap-bind! *ctrl-c-map* ">" 'indent-rigidly-right) + (keymap-bind! *ctrl-c-map* "<" 'indent-rigidly-left) + + ;; Buffer stats + (keymap-bind! *ctrl-c-map* "?" 'buffer-stats) + + ;; Show tabs/eol + (keymap-bind! *ctrl-c-map* "4" 'toggle-show-tabs) + (keymap-bind! *ctrl-c-map* "6" 'toggle-show-eol) + + ;; Copy from above + (keymap-bind! *ctrl-c-map* "A" 'copy-from-above) + + ;; Open line above + (keymap-bind! *ctrl-c-map* "O" 'open-line-above) + + ;; Select line + (keymap-bind! *ctrl-c-map* "G" 'select-line) + + ;; Split line + (keymap-bind! *ctrl-c-map* "J" 'split-line) + + ;; Hippie expand + (keymap-bind! *global-keymap* "M-TAB" 'hippie-expand) + + ;; Swap buffers + (keymap-bind! *ctrl-c-map* "9" 'swap-buffers) + + ;; Tab width cycle + (keymap-bind! *ctrl-c-map* "7" 'cycle-tab-width) + + ;; Indent tabs mode + (keymap-bind! *ctrl-c-map* "0" 'toggle-indent-tabs-mode) + + ;; Buffer info + (keymap-bind! *ctrl-c-map* "j" 'buffer-info) + + ;; Window resize + (keymap-bind! *ctrl-x-map* "^" 'enlarge-window) + (keymap-bind! *ctrl-x-map* "-" 'shrink-window) + (keymap-bind! *ctrl-x-map* "{" 'shrink-window-horizontally) + (keymap-bind! *ctrl-x-map* "}" 'enlarge-window-horizontally) + + ;; Whitespace cleanup + (keymap-bind! *ctrl-c-map* "c" 'whitespace-cleanup) + + ;; Toggle electric pair + (keymap-bind! *ctrl-c-map* "Q" 'toggle-electric-pair) + + ;; Previous/next buffer + (keymap-bind! *ctrl-x-map* "<left>" 'previous-buffer) + (keymap-bind! *ctrl-x-map* "<right>" 'next-buffer) + + ;; Balance windows + (keymap-bind! *ctrl-x-map* "+" 'balance-windows) + + ;; Move to window line + (keymap-bind! *global-keymap* "M-r" 'move-to-window-line) + + ;; Kill buffer and window + (keymap-bind! *ctrl-x-4-map* "0" 'kill-buffer-and-window) + + ;; Flush undo + (keymap-bind! *ctrl-c-map* "/" 'flush-undo) + + ;; Upcase initials region + (keymap-bind! *ctrl-c-map* "U" 'upcase-initials-region) + + ;; Untabify buffer + (keymap-bind! *ctrl-c-map* "_" 'untabify-buffer) + + ;; Insert buffer name + (keymap-bind! *ctrl-c-map* "%" 'insert-buffer-name) + + ;; Mark defun + (keymap-bind! *ctrl-c-map* "y" 'mark-defun) + + ;; Insert pairs + (keymap-bind! *ctrl-c-map* "(" 'insert-parentheses) + (keymap-bind! *ctrl-c-map* "[" 'insert-pair-brackets) + + ;; Describe char + (keymap-bind! *ctrl-c-map* "," 'describe-char) + + ;; Find file at point + (keymap-bind! *ctrl-c-map* "o" 'find-file-at-point) + + ;; Count chars region + (keymap-bind! *ctrl-c-map* "K" 'count-chars-region) + + ;; Count words buffer + (keymap-bind! *ctrl-c-map* "+" 'count-words-buffer) + + ;; Unfill paragraph + (keymap-bind! *ctrl-c-map* ";" 'unfill-paragraph) + + ;; List registers + (keymap-bind! *ctrl-c-map* "@" 'list-registers) + + ;; Show kill ring + (keymap-bind! *ctrl-c-map* "Y" 'show-kill-ring) + + ;; Smart beginning of line + (keymap-bind! *ctrl-c-map* "`" 'smart-beginning-of-line) + + ;; What buffer + (keymap-bind! *ctrl-c-map* "~" 'what-buffer) + + ;; Narrowing indicator + (keymap-bind! *ctrl-c-map* ":" 'toggle-narrowing-indicator) + + ;; Insert file name + (keymap-bind! *ctrl-c-map* "&" 'insert-file-name) + + ;; S-expression navigation + (keymap-bind! *meta-g-map* "u" 'backward-up-list) + (keymap-bind! *meta-g-map* "d" 'forward-up-list) + (keymap-bind! *meta-g-map* "k" 'kill-sexp) + (keymap-bind! *meta-g-map* "f" 'forward-sexp) + (keymap-bind! *meta-g-map* "b" 'backward-sexp)