keybindings.el Wed, Jul 16, 2025

;;; keybindings.el --- Custom keybindings and functions -*- lexical-binding: t -*-

;;; Commentary:
;; Custom key bindings and utility functions with conflict resolution

;;; Code:

;; Simple aliases
(defalias 'qrr 'query-replace-regexp)
(defalias 'tmm 'tmm-menubar)
(defalias 'qrs 'replace-string)
(defalias 'qfs 'flymake-show-buffer-diagnostics)

;; Utility functions
(defun dws/rename-current-buffer-file ()
  "Renames current buffer and file it is visiting."
  (interactive)
  (let ((name (buffer-name))
        (filename (buffer-file-name)))
    (if (not (and filename (file-exists-p filename)))
        (error "Buffer '%s' is not visiting a file!" name)
      (let ((new-name (read-file-name "New name: " filename)))
        (if (get-buffer new-name)
            (error "A buffer named '%s' already exists!" new-name)
          (rename-file filename new-name 1)
          (rename-buffer new-name)
          (set-visited-file-name new-name)
          (set-buffer-modified-p nil)
          (message "File '%s' successfully renamed to '%s'"
                   name (file-name-nondirectory new-name)))))))

(defun dws/kill-other-buffers ()
  "Kill all other buffers."
  (interactive)
  (mapc 'kill-buffer (delq (current-buffer) (buffer-list))))

(defun dws/revert-all-buffers ()
  "Refreshes all open buffers from their respective files."
  (interactive)
  (dolist (buf (buffer-list))
    (with-current-buffer buf
      (when (and (buffer-file-name)
                 (file-exists-p (buffer-file-name))
                 (not (buffer-modified-p)))
        (revert-buffer t t t))))
  (message "Refreshed open files."))

(defun dws/join-line()
  "Join lines at point."
  (interactive)
  (join-line -1))

(defun dws/set-path ()
  "Set up Emacs exec path and PATH environment variable."
  (interactive)
  (let ((path-from-shell
         (replace-regexp-in-string
          "[ \t\n]*$" ""
          (shell-command-to-string
           "$SHELL --login -i -c 'echo $PATH'"))))
    (setenv "PATH" path-from-shell)
    (setq exec-path (split-string path-from-shell path-separator))))

;; Terminal management
(defun dws/switch-terminal ()
  "Switch between eshell and multi-term based on context."
  (interactive)
  (if (or (eq major-mode 'shell-mode)
          (eq major-mode 'term-mode))
      ;; If we're in a terminal, make a new one
      (multi-term)
    ;; Otherwise switch to most recent terminal or make new
    (if (get-buffer "*shell*")
        (switch-to-buffer "*shell*")
      (shell))))

;; Global keybindings
(bind-keys*
 ;; Basic editing
 ("C--" . undo)
 ("M-j" . dws/join-line)
 ("DEL" . delete-backward-char)  ;; Instead of C-h to preserve help
 ("C-w" . backward-kill-word)
 ("C-x ," . dabbrev-expand)
 ("C-x C-k" . kill-region)
 
 ;; Window management (preserved as they're unique)
 ("M--" . enlarge-window-horizontally)
 ("M-0" . delete-window)
 ("M-1" . delete-other-windows)
 ("M-2" . split-window-below)
 ("M-3" . split-window-right)
 ("M-5" . balance-windows)
 ("M-o" . other-window)  ;; Single definition
 
 ;; Buffer operations with safer bindings
 ("M-k" . kill-buffer)
 ("C-x C-s" . save-buffer)      ;; Standard Emacs binding
 ("M-G" . goto-line)            ;; Changed from M-g to preserve goto prefix
 
 ;; Terminal management (unified)
 ;;  ("M-/" . dws/switch-terminal)  ;; Single smart terminal command
 ;; setting back to eshell for now
 ("M-/" . eshell)
 
 ;; Custom functions
 ("C-c r" . dws/revert-all-buffers)  ;; Simplified from C-c C-M-r
 ("C-c d" . delete-frame)            ;; Simplified from C-c C-d
 ("C-c v" . dws/rotate-windows)      ;; Simplified from C-c C-v
 
 ;; Mac-specific (preserved)
 ("H-8" . toggle-frame-fullscreen))

;; Mode-specific keybindings
(with-eval-after-load 'term
  (bind-keys :map term-mode-map
            ("M-p" . term-send-up)
            ("M-n" . term-send-down)
            ("M-b" . consult-buffer)))

;; Midnight mode for buffer cleanup
(use-package midnight
  :defer 600
  :custom
  (clean-buffer-list-delay-general 3)
  :config
  (midnight-delay-set 'midnight-delay "9:04am")
  (add-to-list 'clean-buffer-list-kill-never-buffer-names "*.org"))

(provide 'keybindings)
;;; keybindings.el ends here