aboutsummaryrefslogblamecommitdiff
path: root/nix/users/fcuny/configs/emacs/init.el
blob: 36d05be342de4ccdc91c4b5bbcec5e3fe369058b (plain) (tree)
1
2
3
4
5
6
7
8
9





                                                                         


                                                    



















                                                                                                                          
                    
                                   















                                            
         

                             
                       
                                              

                               
 
                 
                         




                                                
                                              
                                  
 






                                                                      





                                                                                              
                   



                                       
 
                    
                             






















                                                                            
 
























                                                                                   










                                                                                              












                                        




                                      






                                             


                                               
               










                                           

                                          
 

                                         
 













































                                                                                  
 














                                                                                         
 






























































































                                                                                          
 

















                                                                                                              
























































































                                                              
 










                                                                                   




                                                                                                                          
 





                                                                

                                                                                            


                                                            
;;; init.el --- This is where all emacs start. -*- lexical-binding: t -*-

;;; Commentary:

;;; Code:

(setq backup-inhibited t)   ;; no backups
(setq create-lockfiles nil) ;; don't use a lock file

(setq auto-save-default nil)                            ;; no auto save
(setq confirm-kill-emacs #'yes-or-no-p)                 ;; ask before killing emacs
(setq cursor-in-non-selected-windows nil)               ;; keep cursors and highlights in current window only
(setq delete-by-moving-to-trash t)                      ;; delete files by moving them to the trash
(setq highlight-nonselected-windows nil)                ;; don't highlight inactive windows
(setq history-delete-duplicates t)                      ;; delete duplicate from history
(setq initial-major-mode 'fundamental-mode)             ;; default mode for the scratch buffer
(setq initial-scratch-message "")                       ;; makes the scratch buffer empty
(setq midnight-period (* 3600 6))                       ;; clear buffer every 6 hours
(setq mode-line-default-help-echo nil)                  ;; don't say anything on mode-line mouseover
(setq require-final-newline t)                          ;; ensure a new line is present at the bottom of files
(setq ring-bell-function 'ignore)                       ;; really no bell
(setq sentence-end-double-space nil)                    ;; it matters for filling
(setq use-short-answers t)                              ;; use y-or-n
(setq visible-bell nil)                                 ;; no bell
(setq bidi-display-reordering nil)                      ;; disable bidirectional text support for slight performance bonus
(setq column-number-mode t)                             ;; show column number in the mode line

(global-set-key (kbd "M-j") 'join-line)

(use-package recentf
  :hook (after-init . recentf-mode)
  :custom
  (recentf-max-saved-items 1000)
  (recentf-max-menu-items 25)
  (recentf-save-file-modes nil)
  (recentf-keep nil)
  (recentf-auto-cleanup nil)
  (recentf-initialize-file-name-history nil)
  (recentf-filename-handlers nil)
  (recentf-show-file-shortcuts-flag nil))

(use-package midnight
  :custom
  ;; every 6 hours
  (midnight-period (* 3600 6)))

(use-package imenu
  :config
  (setq imenu-auto-rescan t))

(use-package autorevert
  :hook (after-init . global-auto-revert-mode)
  :custom
  (auto-revert-use-notify nil))

(use-package time
  :commands (world-clock)
  :hook (after-init . display-time-mode)
  :config
  (setq display-time-format " %a %e %b, %H:%M ")
  (setq display-time-24hr-format t)
  (setq display-time-interval 60)
  (setq display-time-default-load-average nil)
  (setq display-time-world-list t)

  ;; M-x shell RET timedatectl list-timezones
  (setq zoneinfo-style-world-list '(("America/Los_Angeles" "Berkeley")
				    ("America/Chicago" "Chicago")
				    ("UTC" "UTC")
				    ("Europe/Paris" "Paris")))

  ;; M-x world-clock
  (setq world-clock-list t)
  (setq world-clock-time-format "%z %R	%a %d %b (%Z)")
  (setq world-clock-buffer-name "*world-clock*") ; Placement handled by `display-buffer-alist'
  (setq world-clock-timer-enable t)
  (setq world-clock-timer-second 60))

(use-package server
  :config
  (setq server-client-instructions nil)
  (unless (server-running-p)
    (server-start)))

(use-package ibuffer
  :bind ("C-x C-b" . ibuffer)
  :custom
  (ibuffer-expert t)
  (ibuffer-show-empty-filter-groups nil)
  (ibuffer-jump-offer-only-visible-buffers t)
  (ibuffer-never-show-predicates '("^ "))
  (ibuffer-use-other-window t)
  (ibuffer-filter-group-name-face '(:inherit (font-lock-string-face bold))))

(use-package which-key
  :diminish
  :hook (after-init . which-key-mode))

(use-package saveplace
  :config
  (save-place-mode t))

(use-package savehist
  :hook (after-init . savehist-mode)
  :custom
  (savehist-file (locate-user-emacs-file "savehist"))
  (history-length 100)
  (history-delete-duplicates t)
  (savehist-save-minibuffer-history t))

(use-package magit
  :bind ("C-x g" . magit-status)
  :custom
  (magit-diff-refine-hunk t)
  (magit-repository-directories '(("~/workspace" . 1)))
  (magit-repolist-column-flag-alist '((magit-untracked-files . "N")
				      (magit-unstaged-files . "U")
				      (magit-staged-files . "S")))
  (magit-repolist-columns '(("Name" 25 magit-repolist-column-ident nil)
			    ("" 3 magit-repolist-column-flag)
			    ("Version" 25 magit-repolist-column-version
			     ((:sort magit-repolist-version<)))
			    ("B<U" 3 magit-repolist-column-unpulled-from-upstream
			     ((:right-align t)
			      (:sort <)))
			    ("B>U" 3 magit-repolist-column-unpushed-to-upstream
			     ((:right-align t)
			      (:sort <)))
			    ("Path" 99 magit-repolist-column-path nil)))
  (magit-clone-default-directory "~/workspace/")
  :config
  ;; show ANSI colors in the process buffer, so it's easier to read what's going on
  ;; for some reasons if it's in the `:custom' section it does not get set
  (setq magit-process-finish-apply-ansi-colors t))

(use-package git-link
  :defines git-link-remote-alist
  :bind ("C-c Y" . git-link)
  :commands (git-link git-link-commit git-link-homepage)
  :custom
  (git-link-open-in-browser t)
  :config
  ;; sets up roblox git enterprise as a git-link handler
  (add-to-list 'git-link-remote-alist '("github\\.rblx\\.com" git-link-github))
  (add-to-list 'git-link-commit-remote-alist '("github\\.rblx\\.com" git-link-commit-github)))

(use-package eshell
  :commands (eshell eshell-command)
  :bind (("C-r" . consult-history))
  :custom
  (eshell-hist-ignoredups t)
  (eshell-history-size 50000)
  (eshell-ls-dired-initial-args '("-h"))
  (eshell-ls-initial-args "-h")
  (eshell-ls-exclude-regexp "~\\'")
  (eshell-save-history-on-exit t)
  (eshell-stringify-t nil)
  (eshell-term-name "ansi"))

(use-package project
  :bind
  (("C-x p ." . project-dired)
   ("C-x p <return>" . project-dired))
  :custom
  (project-switch-commands
   '(
     (consult-project-buffer "buffer" ?b)
     (project-dired "dired" ?d)
     (magit-project-status "magit status" ?g)
     (project-find-file "find file" ?p)
     (consult-ripgrep "rigprep" ?r)))
  (setq project-mode-line t)
  (setq project-key-prompt-style t)) ; Emacs 30

(use-package rg
  :custom
  (rg-group-result t)
  (rg-show-columns t)
  (rg-align-line-number-field-length 3)
  (rg-align-column-number-field-length 3)
  (rg-align-line-column-separator "#")
  (rg-align-position-content-separator "|")
  (rg-hide-command nil)
  (rg-align-position-numbers t)
  (rg-command-line-flags '("--follow")))

(use-package exec-path-from-shell
  :init (exec-path-from-shell-initialize))

(use-package elec-pair
  :hook (prog-mode . electric-pair-mode))

(use-package eldoc
  :diminish
  :hook ((emacs-lisp-mode) . eldoc-mode)
  :custom
  (eldoc-idle-delay 1)
  (eldoc-documentation-strategy #'eldoc-documentation-default)
  ;; Don't resize the echo area if the documentation is longer. This is very
  ;; distracting when combined with Eglot's highlight functionality.
  (eldoc-echo-area-use-multiline-p nil))

(use-package compile
  :hook (compilation-filter . ansi-color-compilation-filter)
  :custom
  (compilation-always-kill t)
  (compilation-context-lines 10)
  (compilation-disable-input t)
  (compilation-scroll-output 'first-error)
  (compilation-scroll-output t)
  (compilation-skip-threshold 2)
  ;; Save all buffers on M-x `compile'
  (compilation-ask-about-save nil))

(use-package eglot
  :after yasnippet
  :bind (:map eglot-mode-map
              ("C-c l a" . eglot-code-actions)
              ("C-c l r" . eglot-rename)
	      ("C-c l f" . eglot-format-buffer))
  :hook ((go-mode     . eglot-ensure)
	 (python-mode . eglot-ensure)
	 (nix-mode    . eglot-ensure))
  :custom
  (eglot-send-changes-idle-time 0.1)
  :config
  (setq eglot-autoshutdown t
	;; Disable logging of events.
	eglot-events-buffer-size 0)
  (setq-default eglot-workspace-configuration
                '(:pylsp (:plugins (:ruff (:enabled t)))
                  :nil (:formatting (:command ["nixfmt"]))
                  :gopls (:usePlaceholders t
					   :staticcheck t
					   :completeUnimported t
					   :matcher "CaseSensitive")))
  ;; uses https://github.com/nix-community/nixd for the LSP server instead of rnix
  (add-to-list 'eglot-server-programs '(nix-mode . ("nil"))))

(use-package emacs-lisp-mode
  :bind (:map emacs-lisp-mode-map
              ("C-c C-r" . eval-region)
              ("C-c C-d" . eval-defun)
              ("C-c C-b" . eval-buffer))
  :hook ((emacs-lisp-mode . flymake-mode)))

(use-package go-mode
  :hook ((go-mode . (lambda () (setq tab-width 4)))
         (go-mode . (lambda () (add-hook 'before-save-hook 'eglot-format-buffer nil t))))
  :bind (:map go-mode-map
              ("C-c C-c" . compile))
  :config
  (with-eval-after-load 'exec-path-from-shell
    (exec-path-from-shell-copy-envs '("GOPATH" "GOBIN"))))

(use-package gotest
  :after go-mode
  :custom
  (go-test-verbose t))

(use-package nix-mode
  :hook ((nix-mode . (lambda () (add-hook 'before-save-hook 'eglot-format-buffer nil t))))
  :custom
  (nix-indent-function 'nix-indent-line))

(use-package python-mode)

(use-package ruby-mode)

(use-package json-mode)

(use-package json-reformat
  :after json-mode)

(use-package jq-mode
  :mode "\\.jq\\'")

(use-package terraform-mode
  :mode "\.tf\\'")

(use-package hcl-mode
  :mode "\.nomad\\'")

(use-package toml-mode)

(use-package yaml-mode)

(use-package docker
  :bind ("C-c d" . docker)
  :diminish
  :init
  (use-package docker-image   :commands docker-images)
  (use-package docker-volume  :commands docker-volumes)
  (use-package docker-network :commands docker-containers)
  (use-package docker-compose :commands docker-compose)

  (use-package docker-container
    :commands docker-containers
    :custom
    (docker-containers-shell-file-name "/bin/bash")
    (docker-containers-show-all nil)))

(use-package docker-compose-mode
  :mode "docker-compose.*\.yml\\'")

(use-package dockerfile-mode
  :mode "Dockerfile[a-zA-Z.-]*\\'")

(use-package protobuf-mode
  :mode "\\.proto\\'")

(use-package css-mode
  :custom
  (css-indent-offset 2)
  (cssm-indent-level 1))

(use-package fringe
  :custom (fringe-mode '(8 . 0)))

(use-package whitespace
  :init
  (global-whitespace-mode t)
  :custom
  (whitespace-style '(face
		      tabs
		      spaces
		      tab-mark
		      space-mark
		      trailing
		      missing-newline-at-eof
		      space-after-tab::tab
		      space-after-tab::space
		      space-before-tab::tab
		      space-before-tab::space)))

(use-package dired
  :hook (dired-mode . dired-omit-mode)
  :bind (:map dired-mode-map
              ( "."     . dired-omit-mode))
  :custom
  (dired-omit-files (rx (seq bol ".")))
  (dired-use-ls-dired t)
  (dired-clean-up-buffers-too nil)
  (dired-dwim-target t)
  (dired-hide-details-hide-information-lines nil)
  (dired-hide-details-hide-symlink-targets nil)
  (dired-recursive-copies 'always)
  (dired-recursive-deletes 'always)
  (dired-no-confirm
   '(byte-compile chgrp chmod chown copy hardlink symlink touch)))

(defun my/rename-this-buffer-and-file ()
  "Renames current buffer and file it is visiting."
  (interactive)
  (let ((name (buffer-name))
        (filename (buffer-file-name))
        (read-file-name-function 'read-file-name-default))
    (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)))
        (cond ((get-buffer new-name)
               (error "A buffer named '%s' already exists!" new-name))
              (t
               (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))))))))

(use-package direnv
  :custom
  (direnv-always-show-summary nil)
  :config
  (direnv-mode))

(use-package flymake
  :bind (:prefix "C-c !"
		 :prefix-map flymake-prefix-map
		 ("l" . consult-flymake)
		 ("d" . flymake-show-buffer-diagnostics)
		 ("D" . flymake-show-project-diagnostics)
		 ("n" . flymake-goto-next-error)
		 ("p" . flymake-goto-prev-error))
  :hook
  (prog-mode . flymake-mode)
  :custom
  (flymake-start-on-save-buffer t)
  (flymake-fringe-indicator-position 'left-fringe)
  (flymake-suppress-zero-counters t)
  (flymake-proc-compilation-prevents-syntax-check t)
  (flymake-no-changes-timeout 9999)
  (elisp-flymake-byte-compile-load-path load-path))

(use-package consult
  :commands (consult-ripgrep consult-buffer consult-imenu)
  :bind (("C-c m"   . consult-mode-command)
	 ("C-x b"   . consult-buffer)
	 ("C-x r b" . consult-bookmark)
	 ("C-x p b" . consult-project-buffer)
	 ("C-c i"   . consult-imenu)
	 ("M-g e"   . consult-compile-error)
	 ("M-g M-g" . consult-goto-line)
	 ("M-g m"   . consult-mark)
	 ("M-g k"   . consult-global-mark)))

(use-package corfu
  :custom
  (corfu-auto t)
  :bind ("M-/" . completion-at-point)
  :hook ((after-init . global-corfu-mode)
         (global-corfu-mode . corfu-popupinfo-mode)))

(use-package cape)

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

(use-package orderless
  :custom
  (completion-styles '(orderless basic))
  (completion-category-defaults nil))

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

(use-package consult-imenu
  :after (consult))

(use-package corfu-popupinfo
  :after corfu
  :hook (corfu-mode . corfu-popupinfo-mode)
  :custom
  (corfu-popupinfo-delay '(0.25 . 0.1))
  (corfu-popupinfo-hide nil))

(use-package modus-themes
  :custom
  (modus-themes-italic-constructs t)
  (modus-themes-syntax '(alt-syntax green-strings))
  (modus-themes-mode-line '(moody accented borderless))
  (modus-themes-tabs-accented t)

  (modus-themes-completions
      '((matches . (extrabold background))
        (selection . (semibold accented))
        (popup . (accented))))

  (modus-themes-fringe 'subtle)
  (modus-themes-lang-checkers '(text-also straight-underline))
  (modus-themes-hl-line '(accented))
  (modus-themes-subtle-line-numbers t)
  (modus-themes-markup '(bold italic))
  (modus-themes-paren-match '(bold))
  (modus-themes-region '())

  :config
  (load-theme 'modus-operandi)
  (enable-theme 'modus-operandi-tinted))

(defvar fcuny/op-item-cache nil)

(defun fcuny/read-op-item (op-item-path)
  "Read and cache OP-ITEM-PATH item."
  (or (cdr (assoc op-item-path fcuny/op-item-cache))
      (let ((key (string-trim-right
                  (shell-command-to-string (format "op read '%s'" op-item-path)))))
        (unless (string-match-p "\\[ERROR\\]" key)
          (push (cons op-item-path key) fcuny/op-item-cache)
          key))))

(use-package gptel
  :custom
  (gptel-default-mode 'org-mode)
  :config
  (gptel-make-anthropic "Claude" :stream t :key (lambda () (fcuny/read-op-item "op://Private/anthropic llm/credential"))))

(use-package aidermacs
  :bind ("C-c a" . aidermacs-transient-menu)
  :custom
  (aider-args '("--no-check-update" "--no-show-model-warnings"))
  (aidermacs-default-model "claude-3-7-sonnet-latest")
  :config
  (setenv "ANTHROPIC_API_KEY" (fcuny/read-op-item "op://Private/anthropic llm/credential")))

;;; early-init.el ends here
;; byte-compile-warnings: (not docstrings lexical noruntime)
;; End: