[Home] [Up] [Previous]

radq.ca


My .emacs

December 24th, 2024

I often work on different machines but still like using emacs wherever I can. Here is my (unorganized nicely at this point) .emacs for ease of use, and just to share. It is definitely mac specific fyi.

    

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Keyboard shortcuts
;;
;; f1                                   menubar activate
;; f2                                   jump to header or implementation
;; f3                                   display line numbers toggle
;; f4                                   open .emacs
;; f5                                   list-libraries
;; f8                                   treemacs
;; f10                                  new frame
;; f11                                  cycle left frame
;; f12                                  cycle right frame
;; C-:                                  avy jump mode
;; M-;                                  comment region
;; M-:                                  eval expression in minibuffer

;; M-: and type major-mode to get the major mode, listed here as I always forget
;; M-. to go to a symbol definition when programming

;;; Multiple Cursors
;; "C-S-" This adds a cursor for editing
;; "C-S-SPC" This also adds a cursor for editing
;; "C->" This marks the next one like this
;; "C-<" This marks the previous one like this


;; How to inform Emacs.app and other Mac applications of the command line PATH

;; Update Mac OS X's notion of PATH.
;; $ defaults write ~/.MacOSX/environment PATH "`echo $PATH`"
;; $ echo "setenv PATH $PATH" | sudo tee /etc/launchd.conf
;; Restart Mac OS X.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(add-to-list 'display-buffer-alist
             '("\\`\\*\\(Warnings\\|Compile-Log\\)\\*\\'"
               (display-buffer-no-window)
               (allow-no-window . t)))

; Set our theme immediately
(use-package spacemacs-common
  :ensure spacemacs-theme
  :config (load-theme 'spacemacs-dark t))

(setq inhibit-splash-screen t)

;; If windowed, maximize and hide the toolbar
(if window-system
    (progn
      ;(setq initial-frame-alist '((width . 120) (height . 50)))
      ;(add-to-list 'default-frame-alist '(fullscreen . maximized))
      (tool-bar-mode -1)
      (scroll-bar-mode -1)
      (x-focus-frame nil)))

(setq package-archives
      '(("GNU ELPA"     . "https://elpa.gnu.org/packages/")
        ("MELPA Stable" . "https://stable.melpa.org/packages/")
        ("MELPA"        . "https://melpa.org/packages/"))
      package-archive-priorities
      '(("MELPA Stable" . 10)
        ("GNU ELPA"     . 5)
        ("MELPA"        . 0)))

(require 'package)
(package-initialize)

;;;;; Now configure the rest of our packages
(use-package yasnippet
  :ensure t
  :config
  (yas-global-mode 1))

(use-package yasnippet-snippets
  :ensure t)

(use-package projectile
  :ensure t
  :config
  (projectile-mode 1)
  (global-unset-key (kbd "M-H"))
  (global-set-key (kbd "M-H") 'projectile-find-other-file)
  (global-unset-key (kbd "M-F"))
  (global-set-key (kbd "M-F") 'projectile-grep)
  (global-unset-key (kbd "C-c C-c"))
  (global-set-key (kbd "C-c C-c") 'comment-or-uncomment-region)
  (add-to-list 'projectile-globally-ignored-directories "node_modules")
  (add-to-list 'projectile-globally-ignored-directories "dist")
  (add-to-list 'projectile-globally-ignored-directories ".git"))


(use-package markdown-mode
  :ensure t
  :defer t)

;; https://github.com/abo-abo/avy
(use-package avy
  :ensure t
  :config
  (avy-setup-default)
  (global-set-key (kbd "C-:") 'avy-goto-char)
  (global-set-key (kbd "C-'") 'avy-goto-char-2)
  (global-set-key (kbd "M-g f") 'avy-goto-line)
  (global-set-key (kbd "M-g w") 'avy-goto-word-1)
  (global-set-key (kbd "M-g e") 'avy-goto-word-0)
  (global-set-key (kbd "C-c C-j") 'avy-resume))

(use-package helm
  :ensure t
  :config
  (helm-mode 1)
  (global-set-key (kbd "M-x") 'helm-M-x)
  (global-set-key (kbd "C-x C-f") 'helm-find-files)
  (setq helm-display-function 'helm-default-display-buffer)
  (setq helm-split-window-inside-p t)
;; (setq helm-display-function 'helm-display-buffer-in-own-frame
;;         helm-display-buffer-reuse-frame nil
;;         helm-use-undecorated-frame-option t)
)

(use-package flymake
  :ensure t)

(use-package company
  :ensure t
  :config
  (global-company-mode))


(use-package treemacs
  :ensure t
  :config
  (treemacs-resize-icons 16)
  (treemacs-project-follow-mode t)
  (setq treemacs-width-is-initially-locked t)
  (setq treemacs-width 50)
  (with-eval-after-load 'treemacs
    (define-key treemacs-mode-map [mouse-1] #'treemacs-single-click-expand-action))
  (global-unset-key [f8])
  (global-set-key [f8] 'treemacs)
  )

(use-package dash
  :ensure t)

(use-package s
  :ensure t)

(use-package editorconfig
  :ensure t)

(use-package gptel
  :ensure t)

(gptel-make-openai "local-llm"
  :stream t                             ;Stream responses
  :protocol "http"
  :host "localhost:8080"                ;Llama.cpp server location
  :models '(local-llm))                    ;Any names, doesn't matter for Llama

(setq
 gptel-model   'local-llm
 gptel-backend (gptel-make-openai "llama-cpp"
                 :stream t
                 :protocol "http"
                 :host "localhost:8080"
                 :models '(local-llm)))

;(add-hook 'gptel-post-response-functions 'gptel-end-of-response)
;(add-hook 'gptel-post-stream-hook 'gptel-auto-scroll)

(use-package multiple-cursors
  :ensure t
  :config
  (global-set-key (kbd "C-S-") 'mc/add-cursor-on-click)
  (global-set-key (kbd "C-S-SPC") 'mc/edit-lines)
  (global-set-key (kbd "C->") 'mc/mark-next-like-this)
  (global-set-key (kbd "C-<") 'mc/mark-previous-like-this))



;; Let emacs know of the location of some external tools
(setq exec-path (append exec-path '("/opt/local/bin")))
(setq exec-path (append exec-path '("/Users/nzec/bin")))

(use-package slime
  :config (setq inferior-lisp-program "sbcl")
  :ensure t)

(use-package helm-slime
  :ensure t)

(use-package ac-slime
  :ensure t)

(use-package elisp-slime-nav
  :ensure t)

(use-package slime-repl-ansi-color
  :ensure t)

(use-package delsel
  :ensure nil ; no need to install it as it is built-in
  :hook (after-init . delete-selection-mode))

(use-package vertico
  :ensure t
  :hook (after-init . vertico-mode))

(use-package marginalia
  :ensure t
  :hook (after-init . marginalia-mode))

(use-package orderless
  :ensure t
  :config
  (setq completion-styles '(orderless basic))
  (setq completion-category-defaults nil)
  (setq completion-category-overrride nil))

(use-package savehist
  :ensure nil ; it is built-in
  :hook (after-init . savehist-mode))

(use-package corfu
  :ensure t
  :hook (after-init . global-corfu-mode)
  :bind (:map corfu-map ("" . corfu-complete))
  :config
  (setq tab-always-indent 'complete)
  (setq corfu-preview-current nil)
  (setq corfu-min-width 20)

  (setq corfu-popupinfo-delay '(1.25 . 0.5))
  (corfu-popupinfo-mode 1) ; shows documentation after `corfu-popupinfo-delay'

  ;; Sort by input history (no need to modify `corfu-sort-function').
  (with-eval-after-load 'savehist
    (corfu-history-mode 1)
    (add-to-list 'savehist-additional-variables 'corfu-history)))

(defun prot/keyboard-quit-dwim ()
  "Do-What-I-Mean behaviour for a general `keyboard-quit'.

The generic `keyboard-quit' does not do the expected thing when
the minibuffer is open.  Whereas we want it to close the
minibuffer, even without explicitly focusing it.

The DWIM behaviour of this command is as follows:

- When the region is active, disable it.
- When a minibuffer is open, but not focused, close the minibuffer.
- When the Completions buffer is selected, close it.
- In every other case use the regular `keyboard-quit'."
  (interactive)
  (cond
   ((region-active-p)
    (keyboard-quit))
   ((derived-mode-p 'completion-list-mode)
    (delete-completion-window))
   ((> (minibuffer-depth) 0)
    (abort-recursive-edit))
   (t
    (keyboard-quit))))


;; (let ((mono-spaced-font "Monospace")
;;       (proportionately-spaced-font "Sans"))
;;   (set-face-attribute 'default nil :family mono-spaced-font :height 100)
;;   (set-face-attribute 'fixed-pitch nil :family mono-spaced-font :height 1.0)
;;   (set-face-attribute 'variable-pitch nil :family proportionately-spaced-font :height 1.0))

(define-key global-map (kbd "C-g") #'prot/keyboard-quit-dwim)

(global-unset-key [f2])
(global-set-key [f2] 'ff-find-other-file)


(global-unset-key [f3])
(global-set-key [f3] 'display-line-numbers-mode)

(global-unset-key [f4])
(global-set-key [f4] (lambda ()
                       (interactive)
                       (find-file "~/.emacs")))

(defun get-all-subdirectories(dir-list)
  "Returns a list of all recursive subdirectories of dir-list,
   ignoring directories with names that start with . (dot)"
  (split-string
   (shell-command-to-string
     (concat "find "
             (mapconcat 'identity dir-list " ")
             " -type d -not -regex \".*/\\\..*\""))))

(setq last-visited-buffer nil)

(defun custom-post-command-func ()
  (setq ff-search-directories nil)

  (when (not (eq (current-buffer) last-visited-buffer))
    (setq last-visited-buffer (current-buffer))

    (let ((existing-vc-root-dir (vc-root-dir)))
      (when existing-vc-root-dir
        (setq ff-search-directories (get-all-subdirectories (list existing-vc-root-dir)))))))

(setq post-command-hook 'custom-post-command-func)

(setq cc-other-file-alist
        '(("\\.cc$"  ff-cc-hh-converter)
          ("\\.hh$"  ff-cc-hh-converter)
          ("\\.c$"   (".h"))
          ("\\.m$"   (".h"))
          ("\\.h$"   (".c" ".cc" ".C" ".CC" ".cxx" ".cpp" ".m" ".mm"))))
(setq ff-always-try-to-create nil)

(global-unset-key [f5])
(global-set-key [f5] 'find-library)

(display-line-numbers-mode 1)


(global-tab-line-mode 1)
(tab-bar-mode 1)

(global-unset-key [f10])
(global-unset-key [f11])
(global-unset-key [f12])

(global-set-key [f10] 'tab-bar-new-tab)
(global-set-key [f11] 'tab-bar-switch-to-prev-tab)
(global-set-key [f12] 'tab-bar-switch-to-next-tab)

(setq display-fill-column-indicator-column 80)
(display-fill-column-indicator-mode 1)

(global-unset-key [f1])
(global-set-key [f1] 'menu-bar-open)

(global-unset-key (kbd "C-t"))
(global-set-key (kbd "C-t") 'org-todo)

(global-visual-line-mode 1)

;; ye olde mouse config (disabled scrolling, but other stuff works)
(xterm-mouse-mode 1)

(unless window-system
    (global-set-key [mouse-4] 'scroll-down-line)
    (global-set-key [mouse-5] 'scroll-up-line))

;; eglot
(add-hook 'ts-mode-hook 'eglot-ensure)
(add-hook 'js-mode-hook 'eglot-ensure)
(add-hook 'html-mode-hook 'eglot-ensure)
(add-hook 'c-mode 'eglot-ensure)
(add-hook 'c-ts-mode 'eglot-ensure)
(add-hook 'c++-mode 'eglot-ensure)
(add-hook 'c++-ts-mode 'eglot-ensure)

;; Theme customization
;;; Some light customizations for our tab bars
(defun theme-loaded-hook ()
  "Perform actions when a theme is loaded."
  (interactive)
  (message "Theme loaded: %s" (car custom-enabled-themes))
  ;; Add your custom code here based on the theme name
  (when (string= (car custom-enabled-themes) "spacemacs-dark")
    (set-face-attribute 'tab-bar nil :height 1.3 :background "#303030")
    (set-face-attribute 'tab-bar-tab nil :background "#303030")
    (set-face-attribute 'tab-line nil ;; background behind tabs
      :background "#303030"
      :foreground "gray60" :distant-foreground "gray50"
      :height 1.1 :box nil)
    (set-face-attribute 'tab-line-tab nil ;; active tab in another window
      :inherit 'tab-line
      :foreground "gray70" :background "gray90" :box nil)
    (set-face-attribute 'tab-line-tab-current nil ;; active tab in current window
      :background "black" :foreground "white" :box nil)
    (set-face-attribute 'tab-line-tab-inactive nil ;; inactive tab
      :background "gray60" :foreground "black" :box nil)
    (set-face-attribute 'tab-line-highlight nil ;; mouseover
      :background "white" :foreground 'unspecified))
  (when (string= (car custom-enabled-themes) "spacemacs-light")
    (set-face-attribute 'tab-bar nil :height 1.3 :background "#f0f0f0")
    (set-face-attribute 'tab-bar-tab nil :background "#f0f0f0")
    (set-face-attribute 'tab-line nil ;; background behind tabs
      :background "#f0f0f0"
      :foreground "black" :distant-foreground "gray30"
      :height 1.1 :box nil)
    (set-face-attribute 'tab-line-tab nil ;; active tab in another window
      :inherit 'tab-line
      :foreground "black" :background "#e0e0e0" :box nil)
    (set-face-attribute 'tab-line-tab-current nil ;; active tab in current window
      :background "white" :foreground "black" :box nil)
    (set-face-attribute 'tab-line-tab-inactive nil ;; inactive tab
      :background "#e0e0e0" :foreground "black" :box nil)
    (set-face-attribute 'tab-line-highlight nil ;; mouseover
      :background "lightblue" :foreground 'unspecified)))

(add-hook 'change-major-mode-hook 'theme-loaded-hook)

;; Compilation output
(require 'compile)
(setq compilation-scroll-output t)

;; Show line-number in the mode line
(line-number-mode 1)

;; Show column-number in the mode line
(column-number-mode 1)

;; I like it this way.
(transient-mark-mode)

;; Lisp stuff
(show-paren-mode 1)

;; Keep buffers synced with files on disk
(global-auto-revert-mode t)

;; clean up whitespace on save
(add-hook 'before-save-hook 'whitespace-cleanup)

;; tab spacing
(setq tab-width 2)

;; Only spaces
(setq-default indent-tabs-mode nil)

;; Close braces automatically
;;(electric-pair-mode 1)

;; Don't fat finger a quit
(setq confirm-kill-emacs 'y-or-n-p)

(setq next-screen-context-lines 8) ;; our paging up and paging down overlap
(setq term-buffer-maximum-size 0) ;; Sets this to infinite

;; Window handling
(winner-mode 1)

(global-set-key (kbd "") 'enlarge-window)
(global-set-key (kbd "") 'shrink-window)
(global-set-key (kbd "") 'shrink-window-horizontally)
(global-set-key (kbd "") 'enlarge-window-horizontally)
(global-set-key (kbd "") 'balance-windows)

(global-set-key (kbd "") 'beginning-of-buffer)
(global-set-key (kbd "") 'end-of-buffer)

;; You can shift up, down, left, and right to move
(when (fboundp 'windmove-default-keybindings)
  (windmove-default-keybindings))

;; You can edit how terminal sends these characters to enable up and down with shift, else it will not work
;; In Terminal: Menu -> Preferences -> Profiles -> (your selected theme unfortunately) -> Keyboard
(define-key input-decode-map "\e[1;2A" [S-up])
(define-key input-decode-map "\e[1;2B" [S-down])
(windmove-default-keybindings)

;; sticky window
(defun toggle-window-dedicated ()
  "Control whether or not Emacs is allowed to display another
buffer in current window."
  (interactive)
  (message
   (if (let (window (get-buffer-window (current-buffer)))
         (set-window-dedicated-p window (not (window-dedicated-p window))))
       "%s: Can't touch this!"
     "%s is up for grabs.")
   (current-buffer)))

(global-set-key (kbd "C-c t") 'toggle-window-dedicated)


;; Put autosave files (ie #foo#) and backup files (ie foo~) in their place
;; store all backup and autosave files in the tmp dir
(setq backup-directory-alist
      `((".*" . ,temporary-file-directory)))
(setq auto-save-file-name-transforms
      `((".*" ,temporary-file-directory t)))


(defun pbcopy ()
  "Copy region to mac os x clipboard"
  (interactive)
  (shell-command-on-region
   (region-beginning)
   (region-end)
   "pbcopy"))

(defun pbpaste ()
  "Inserts whatever is on the mac os x clipboard at the current
position in the buffer."
  (interactive)
  (insert (shell-command-to-string "pbpaste")))


;; OPTIONAL: ADD IT ONLY IF YOU USE C/C++.
(semantic-mode 1) ;; -> this is optional for Lisp

;; Our modes we set per file, if they do not already set their mode
(add-to-list 'auto-mode-alist '("\\.ts\\'" . typescript-ts-mode))
(add-to-list 'auto-mode-alist '("\\.ejs\\'" . html-mode))

;; Often while moving around in a file I'll accidentally do a C-[ three times
;; which nukes my window config, this disables that]
(defadvice keyboard-escape-quit (around my-keyboard-escape-quit activate)
  (let (orig-one-window-p)
    (fset 'orig-one-window-p (symbol-function 'one-window-p))
    (fset 'one-window-p (lambda (&optional nomini all-frames) t))
    (unwind-protect
        ad-do-it
      (fset 'one-window-p (symbol-function 'orig-one-window-p)))))


;; These are from my old emacs
;; My own emacs functions
(defun wrap-text (b e txt)
  "simple wrapper"
  (interactive "r\nMEnter text to wrap with: ")
  (save-restriction
    (narrow-to-region b e)
    (goto-char (point-min))
    (insert txt)
    (insert "(")
    (goto-char (point-max))
    (insert ")")))

(global-set-key (kbd "C-x M-w") 'wrap-text)


(defun underline (underchar)
  "Underlines the current line with a specified character"
  (interactive "cEnter the character to underline with: ")
  (save-excursion
    (let (right-column-pos)
      (end-of-line)
      (setq right-column-pos (current-column))
      (insert (princ "\n"))
      (dotimes (number right-column-pos)
        (insert (format "%c" underchar))))))


(defun what-hexadecimal-value ()
  "Prints the decimal value of a hexadecimal string under cursor.
Samples of valid input:

  ffff
  0xffff
  #xffff
  FFFF
  0xFFFF
  #xFFFF

Test cases
  64*0xc8+#x12c 190*0x1f4+#x258
  100 200 300   400 500 600"
  (interactive )

  (let (inputStr tempStr p1 p2 )
    (save-excursion
      (search-backward-regexp "[^0-9A-Fa-fx#]" nil t)
      (forward-char)
      (setq p1 (point) )
      (search-forward-regexp "[^0-9A-Fa-fx#]" nil t)
      (backward-char)
      (setq p2 (point) ) )

    (setq inputStr (buffer-substring-no-properties p1 p2) )

    (let ((case-fold-search nil) )
      (setq tempStr (replace-regexp-in-string "^0x" "" inputStr )) ; C, Perl, ���
      (setq tempStr (replace-regexp-in-string "^#x" "" tempStr )) ; elisp ���
      (setq tempStr (replace-regexp-in-string "^#" "" tempStr ))  ; CSS ���
      )

    (message "Hex %s is %d" tempStr (string-to-number tempStr 16 ) )
    ))


(defun insert-current-date () (interactive)
  (insert (shell-command-to-string "echo -n $(date)")))

(defun insert-date-with-header ()
  "Inserts the current date with a * before. Used in org mode
quite a but for a running log."
  (interactive)
  (insert (princ "* "))
  (insert (shell-command-to-string "echo -n $(date)"))
  (insert (princ "\n\t")))


(defun insert-date-with-underline () (interactive)
  (insert (shell-command-to-string "echo -n $(date)"))
  (let (right-column-pos)
    (end-of-line)
    (setq right-column-pos (current-column))
    (insert (princ "\n"))
    (dotimes (number right-column-pos)
      (insert (format "-")))
    (insert (princ "\n"))
    (insert (princ "\n"))))

(defun iwb ()
  "indent whole buffer"
  (interactive)
  (save-excursion
    (delete-trailing-whitespace)
    (indent-region (point-min) (point-max) nil)
    (untabify (point-min) (point-max))))

(global-set-key (kbd "C-c i") 'iwb)

(defun eval-and-replace (value)
  "Evaluate the sexp at point and replace it with its value"
  (interactive (list (eval-last-sexp nil)))
  (kill-sexp -1)
  (insert (format "%S" value)))

;;; Kill duplicate lines
(defun kill-duplicate-lines (beg end)
  "Unique lines in region.
Called from a program, there are two arguments:
BEG and END (region to sort)."
  (interactive "r")
  (save-excursion
    (save-restriction
      (narrow-to-region beg end)
      (goto-char (point-min))
      (while (not (eobp))
        (kill-line 1)
        (yank)
        (let ((next-line (point)))
          (while
              (re-search-forward
               (format "^%s" (regexp-quote (car kill-ring))) nil t)
            (replace-match "" nil nil))
          (goto-char next-line))))))


(require 'org-crypt)
(org-crypt-use-before-save-magic)
(setq org-tags-exclude-from-inheritance (quote ("crypt")))
;; GPG key to use for encryption
;; Either the Key ID or set to nil to use symmetric encryption.
(setq org-crypt-key nil)

;; Don't ask when we eval a code block C-c C-c
(setq org-confirm-babel-evaluate nil)

(defun frame-exists (name)
  (let* ((frames (frame-list))
         (frame-names (mapcar (lambda (frame) (frame-parameter frame 'name)) frames)))
    (member name frame-names)))

(defun buffer-exists (bufname)
  (not
   (eq nil (get-buffer bufname))))


;;; Keyboard macros

;; How to add keyboard macros?
;; 1) First make your macro
;; 2) C-x C-k n
;; Give a command name (for the duration of the Emacs session) to the most recently defined keyboard macro (kmacro-name-last-macro).
;; 3) M-x insert-kbd-macro
;; This will allow you to insert the keyboard macro as lisp code
;;; For use with github branch names
(fset 'insert-task-id
      (lambda (&optional arg) "Keyboard macro." (interactive "p") (kmacro-exec-ring-item (quote ("On branchOCfw<[#] " 0 "%d")) arg)))

(fset 'insert-msa-id
      (lambda (&optional arg)
        "Keyboard macro."
        (interactive "p")
        (kmacro-exec-ring-item
         (quote ("MSAbffw<<[]" 0 "%d"))
         arg)
        (insert " ")))

(org-babel-do-load-languages
    'org-babel-load-languages
        '(
            (shell . t)
            ;; Other languages...
        )
    )

;; Keep our custom vars outside of our .emacs
(setq custom-file "~/.emacs-custom")
(load custom-file :no-error-if-file-is-missing)


    
  

© 2024 radq.ca