diff --git a/modules/shared/config/emacs/.gitignore b/hosts/config/emacs/.gitignore similarity index 100% rename from modules/shared/config/emacs/.gitignore rename to hosts/config/emacs/.gitignore diff --git a/hosts/config/emacs/emacs.el b/hosts/config/emacs/emacs.el new file mode 100644 index 0000000..002b47f --- /dev/null +++ b/hosts/config/emacs/emacs.el @@ -0,0 +1,56 @@ + (eval-when-compile + (require 'use-package)) + + ;; load some packages + + (use-package company + :bind ("" . company-complete) + :diminish company-mode + :commands (company-mode global-company-mode) + :defer 1 + :config + (global-company-mode)) + + (use-package counsel + :commands (counsel-descbinds) + :bind (([remap execute-extended-command] . counsel-M-x) + ("C-x C-f" . counsel-find-file) + ("C-c g" . counsel-git) + ("C-c j" . counsel-git-grep) + ("C-c k" . counsel-ag) + ("C-x l" . counsel-locate) + ("M-y" . counsel-yank-pop))) + + (use-package flycheck + :defer 2 + :config (global-flycheck-mode)) + + (use-package ivy + :defer 1 + :bind (("C-c C-r" . ivy-resume) + ("C-x C-b" . ivy-switch-buffer) + :map ivy-minibuffer-map + ("C-j" . ivy-call)) + :diminish ivy-mode + :commands ivy-mode + :config + (ivy-mode 1)) + + (use-package magit + :defer + :if (executable-find "git") + :bind (("C-x g" . magit-status) + ("C-x G" . magit-dispatch-popup)) + :init + (setq magit-completing-read-function 'ivy-completing-read)) + + (use-package projectile + :commands projectile-mode + :bind-keymap ("C-c p" . projectile-command-map) + :defer 5 + :config + (projectile-global-mode)) + + + +(global-set-key (kbd "C-.") 'set-mark-command) \ No newline at end of file diff --git a/hosts/darwin/default.nix b/hosts/darwin/default.nix index e22105b..7ec5b5b 100644 --- a/hosts/darwin/default.nix +++ b/hosts/darwin/default.nix @@ -75,7 +75,19 @@ in environment.systemPackages = with pkgs; [ - emacs-unstable + # Emacs with automatic package management from overlay + (emacsWithPackagesFromUsePackage { + config = ../config/emacs/emacs.el; + defaultInitFile = true; + package = emacs-unstable; + alwaysEnsure = true; + extraEmacsPackages = epkgs: with epkgs; [ + magit + company + nix-mode + use-package + ]; + }) ] ++ (import ../../modules/shared/packages.nix { inherit pkgs; }) diff --git a/hosts/nixos/default.nix b/hosts/nixos/default.nix index a907a7a..5cd91fb 100644 --- a/hosts/nixos/default.nix +++ b/hosts/nixos/default.nix @@ -334,6 +334,20 @@ in ]; environment.systemPackages = with pkgs; [ + # Emacs with automatic package management from overlay + (emacsWithPackagesFromUsePackage { + config = ../config/emacs/emacs.el; + defaultInitFile = true; + package = emacs-unstable; + alwaysEnsure = true; + extraEmacsPackages = + epkgs: with epkgs; [ + magit + company + nix-mode + use-package + ]; + }) gitAndTools.gitFull inetutils ]; diff --git a/modules/shared/config/emacs/config.org b/modules/shared/config/emacs/config.org deleted file mode 100644 index fcbdf46..0000000 --- a/modules/shared/config/emacs/config.org +++ /dev/null @@ -1,1477 +0,0 @@ -#+TITLE: Emacs -#+STARTUP: content - -* Configuration :emacs: -** About my Emacs -This is my detailed Emacs configuration. It's an ~org~ file that is transpiled to ~emacs-lisp~ as part of the Nix build process. - -Why an org file? My Emacs config is large, and this enables me to greatly improve readability of its documentation. I edit this file the same way you're reading it (nicely formatted) as I use Emacs and Emacs speaks org. Sounds complicated, but it's really not; [[https://github.com/dustinlyons/nixos-config/blob/main/nixos/default.nix#L215][just a few lines]] in my Nix config. [[https://github.com/dustinlyons/nixos-config/blob/main/darwin/default.nix#L28][MacOS too.]] - -This is the main configuration, but there also exists one more init file, ~init.el~ , that bootstraps ~org-mode~ before this file is interpreted. That's defined [[https://github.com/dustinlyons/nixos-config/blob/main/shared/files.nix#L5][here]]. - -/Each block of code below is the actual Emacs configuration./ Formally, this style of configuration is named [[https://en.wikipedia.org/wiki/Literate_programming]["literate programming"]]. - -** Personal Information -Just me! - -#+NAME: personal-info -#+BEGIN_SRC emacs-lisp - (setq user-full-name "Olaf Kolkman" - user-mail-address "olaf@xolx.nl") -#+END_SRC - -** Initialization -*** Booting up -Mainly splash screen settings. In the future we may look to optimize performance here. - -#+NAME: startup -#+BEGIN_SRC emacs-lisp - ;; Turn off the splash screen - (setq inhibit-startup-screen t) - ;; Turn off the splash screen - (setq initial-scratch-message nil) - ;; Confirm before exiting Emacs - (setq confirm-kill-emacs #'yes-or-no-p) - ;; Set default frame size and position - - (defun adjust-frame-size-and-position (&optional frame) - "Adjust size and position of FRAME based on its type." - (if (display-graphic-p frame) - (let* ((w 150) ; Set to desired width in characters - (h 50) ; Set to desired height in lines - (width (* w (frame-char-width frame))) - (height (* h (frame-char-height frame))) - (left (max 0 (floor (/ (- (x-display-pixel-width) width) 2)))) - (top (max 0 (floor (/ (- (x-display-pixel-height) height) 2))))) - - (set-frame-size frame w h) - (set-frame-position frame left top)) - ;; Ensure the menu bar is off in terminal mode - (when (and (not (display-graphic-p frame)) - (menu-bar-mode 1)) - (menu-bar-mode -1)))) - - (if (daemonp) - (add-hook 'after-make-frame-functions - (lambda (frame) - (select-frame frame) - (when (system-is-mac) (adjust-frame-size-and-position frame))) - (adjust-frame-size-and-position))) - #+END_SRC - -*** Add package sources -This associates our package manager with the right source (MELPA). - -#+NAME: package-sources -#+BEGIN_SRC emacs-lisp - (unless (assoc-default "melpa" package-archives) - (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)) - (unless (assoc-default "nongnu" package-archives) - (add-to-list 'package-archives '("nongnu" . "https://elpa.nongnu.org/nongnu/") t)) -#+END_SRC - -*** System Definitions -**** Conditionals - -#+BEGIN_SRC emacs-lisp - (defun system-is-mac () - "Return true if system is darwin-based (Mac OS X)" - (string-equal system-type "darwin")) - - (defun system-is-linux () - "Return true if system is GNU/Linux-based" - (string-equal system-type "gnu/linux")) - - ;; Set path for darwin - (when (system-is-mac) - (setenv "PATH" (concat (getenv "PATH") ":/Users/%USER%/.nix-profile/bin:/usr/bin")) - (setq exec-path (append '("/Users/%USER%/bin" "/profile/bin" "/Users/%USER%/.npm-packages/bin" "/Users/%USER%/.nix-profile/bin" "/nix/var/nix/profiles/default/bin" "/usr/local/bin" "/usr/bin") exec-path))) -#+END_SRC - -*** Counsel/Ivy framework -Ivy and associated helpers that uses the minibuffer. Ivy describes itself as "a generic completion mechanism for Emacs." Basically, it's a prettier popup window to input Emacs commands. I've defined this to show at the bottom of the screen, which is conveniently also the default. - -#+NAME: ivy-framework -#+BEGIN_SRC emacs-lisp - (use-package counsel - :demand t - :bind (("M-x" . counsel-M-x) - ("C-x b" . counsel-ibuffer) - ("C-x C-f" . counsel-find-file) - ("C-M-j" . counsel-switch-buffer) - :map minibuffer-local-map - ("C-r" . 'counsel-minibuffer-history)) - :custom - (counsel-linux-app-format-function #'counsel-linux-app-format-function-name-only) - :config - (setq ivy-initial-inputs-alist nil)) ;; Don't start searches with ^ - - (use-package prescient - :config - (prescient-persist-mode 1)) - - (use-package ivy - :bind (("C-s" . swiper-all) - :map ivy-minibuffer-map - ("TAB" . ivy-partial-or-done) - ("C-f" . ivy-alt-done) - ("C-l" . ivy-alt-done) - ("C-j" . ivy-next-line) - ("C-k" . ivy-previous-line) - :map ivy-switch-buffer-map - ("C-k" . ivy-previous-line) - ("C-l" . ivy-done) - ("C-d" . ivy-switch-buffer-kill) - :map ivy-reverse-i-search-map - ("C-k" . ivy-previous-line) - ("C-d" . ivy-reverse-i-search-kill)) - :init - (ivy-mode 1) - :config - (setq ivy-use-virtual-buffers t) - (setq ivy-wrap t) - (setq ivy-count-format "(%d/%d) ") - (setq enable-recursive-minibuffers t)) - - (use-package ivy-rich - :init (ivy-rich-mode 1)) - - (use-package ivy-prescient - :after ivy - :custom - (prescient-save-file "~/.emacs.d/prescient-data") - (prescient-filter-method 'fuzzy) - :config - (ivy-prescient-mode t)) - - (use-package all-the-icons-ivy - :init (add-hook 'after-init-hook 'all-the-icons-ivy-setup)) -#+END_SRC - -*** Leader keys -I use ~general.el~ to define groups of keybindings under my 'leader' definition. You will see these definitions sprinkled throughout this file; they are just quick shortcuts. For more info, [[https://medium.com/usevim/vim-101-what-is-the-leader-key-f2f5c1fa610f][here]] is a good explanation on leader keys. - -#+NAME: keybindings -#+BEGIN_SRC emacs-lisp - ;; ESC will also cancel/quit/etc. - (global-set-key (kbd "") 'keyboard-escape-quit) - (use-package general - :init - (setq evil-want-keybinding nil) - :config - (general-evil-setup t) - (general-create-definer dl/leader-keys - :keymaps '(normal visual emacs) - :prefix ",")) -#+END_SRC - -**** Emacs cleanup -Helpful keybindings to help keep Emacs sane. - -#+NAME: emacs-cleanup -#+BEGIN_SRC emacs-lisp - (dl/leader-keys - "k" '(:ignore k :which-key "cleanup") - "ko" '(kill-buffer-and-window :which-key "kill buffer and window") - "kk" '(kill-some-buffers :which-key "cleanup buffers")) - (global-set-key (kbd "C-x -") 'kill-buffer-and-window) -#+END_SRC - -**** -#+NAME: treemacs -#+BEGIN_SRC emacs-lisp - (dl/leader-keys - "t" '(:ignore t :which-key "treemacs") - "tt" '(treemacs :which-key "toggle treemacs") - "tx" '(treemacs-collapse-all-projects :which-key "collapse projects") - "to" '(treemacs-select-window :which-key "select treemacs") - "tw" '(treemacs-toggle-fixed-width :which-key "size treemacs")) -#+END_SRC - -**** Toggles -Various UI related toggles. -#+NAME: toggles-ui -#+BEGIN_SRC emacs-lisp - (dl/leader-keys - "h" '(counsel-load-theme :which-key "choose theme")) -#+END_SRC - -***** Rotate windows -Various helpers and packages I find useful for window management. - -#+BEGIN_SRC emacs-lisp - ;; Rotates windows and layouts - (use-package rotate - :config) - - (dl/leader-keys - "r" '(:ignore t :which-key "rotate") - "rw" '(rotate-window :which-key "rotate window") - "rl" '(rotate-layout :which-key "rotate layout")) -#+END_SRC - -*** Gutter -**** Line numbers -These functions define vim-style relative line numbers. This means my line numbers look like -1, -2, 0, 1, 2... - -*** Modes -**** Window minor modes -I like these window related minor modes. - -#+NAME: windows-ui-settings -#+BEGIN_SRC emacs-lisp - ;; Turn off UI junk - ;; Note to future self: If you have problems with these later, - ;; move these into custom file and set variable custom-file - (column-number-mode) - (scroll-bar-mode 0) - (menu-bar-mode -1) - (tool-bar-mode 0) - (winner-mode 1) ;; ctrl-c left, ctrl-c right for window undo/redo -#+END_SRC - -**** Set mode margins -This is used primarily to center org mode text. - -#+NAME: mode-margins -#+BEGIN_SRC emacs-lisp - (defun dl/org-mode-visual-fill () - (setq visual-fill-column-width 110 - visual-fill-column-center-text t)) - - (use-package visual-fill-column - :defer t - :hook (org-mode . dl/org-mode-visual-fill)) -#+END_SRC - -**** Don't blink the cursor -#+NAME: cursor-mode -#+BEGIN_SRC emacs-lisp - (blink-cursor-mode -1) -#+END_SRC - -**** Colors -***** Rainbow delimiters -Makes my lisp parens pretty, and easy to spot. - -#+NAME: rainbow-delmiters -#+BEGIN_SRC emacs-lisp - (use-package rainbow-delimiters - :hook (prog-mode . rainbow-delimiters-mode)) -#+END_SRC - -***** Color definitions -Define a global set of colors to be used everywhere in Emacs. - -#+NAME: color-definitions -#+BEGIN_SRC emacs-lisp - (defvar dl/black-color "#1F2528") - (defvar dl/red-color "#EC5F67") - (defvar dl/yellow-color "#FAC863") - (defvar dl/blue-color "#6699CC") - (defvar dl/green-color "#99C794") - (defvar dl/purple-color "#C594C5") - (defvar dl/teal-color "#5FB3B3") - (defvar dl/light-grey-color "#C0C5CE") - (defvar dl/dark-grey-color "#65737E") -#+END_SRC - -**** Addons -***** "Powerline" -Keeps info at my fingertips. Modeline is much better than Vim's Powerline (sorry Vim). - -#+NAME: modeline -#+BEGIN_SRC emacs-lisp - ;; Run M-x all-the-icons-install-fonts to install - (use-package all-the-icons) - (use-package doom-modeline - :ensure t - :init (doom-modeline-mode 1)) -#+END_SRC - -***** Treemacs -Although I'm primarily a keyboard user and use Projectile for quickly finding files, I still find the need to browse through files in a more visual way. Treemacs does the job, and beautifully might I add. - -#+NAME: treemacs -#+BEGIN_SRC emacs-lisp - (use-package treemacs - :config - (setq treemacs-is-never-other-window 1) - :bind - ("C-c t" . treemacs-find-file) - ("C-c b" . treemacs-bookmark)) - - (use-package treemacs-icons-dired) - (use-package treemacs-all-the-icons) - (use-package treemacs-projectile) - (use-package treemacs-magit) - (use-package treemacs-evil) -#+END_SRC - -**** Easy window motions with ace-window -Predefine windows with hotkeys and jump to them. - -#+NAME: easy-window-motions -#+BEGIN_SRC emacs-lisp -;; Remove binding for facemap-menu, use for ace-window instead -(global-unset-key (kbd "M-o")) - -(use-package ace-window - :bind (("M-o" . ace-window)) - :custom - (aw-scope 'frame) - (aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l)) - (aw-minibuffer-flag t) - :config - (ace-window-display-mode 1)) -#+END_SRC - -*** Package managers -Using ~straight.el~ under the hood of ~use-package~ enables us to download packages using ~git~. This is preferred for easier hacking; I maintain my own ~org-roam~ fork, for example, and it's just another directory where I organize code. I configure ~straight.el~ with one line to use it. - -*** Windows -**** Fonts -#+NAME: fonts -#+BEGIN_SRC emacs-lisp - ;; Set the default pitch face - (when (system-is-linux) - (set-face-attribute 'default nil :font "JetBrainsMono" :height 100)) - (when (system-is-mac) - (set-face-attribute 'default nil :font "JetBrains Mono" :height 140)) - - ;; Set the fixed pitch face - (when (system-is-linux) - (set-face-attribute 'fixed-pitch nil :font "JetBrainsMono" :weight 'normal :height 100)) - (when (system-is-mac) - (set-face-attribute 'fixed-pitch nil :font "JetBrains Mono" :weight 'normal :height 150)) - - ;; Set the variable pitch face - (when (system-is-linux) - (set-face-attribute 'variable-pitch nil :font "Helvetica LT Std Condensed" :weight 'normal :height 140)) - (when (system-is-mac) - (set-face-attribute 'variable-pitch nil :font "Helvetica" :weight 'normal :height 170)) - -#+END_SRC - -*** Dashboard -#+NAME: dashboard-settings -#+BEGIN_SRC emacs-lisp -(use-package dashboard - :ensure t - :config - (dashboard-setup-startup-hook) - (setq dashboard-startup-banner 'ascii - dashboard-center-content t - dashboard-items '((projects . 5) - (recents . 5))) - (setq dashboard-set-footer nil)) - - (setq dashboard-banner-logo-title "Welcome to your life") - (setq dashboard-set-file-icons t) - (setq dashboard-projects-backend 'projectile) - - (setq initial-buffer-choice (lambda () - (get-buffer-create "*dashboard*") - (dashboard-refresh-buffer))) - (setq dashboard-projects-switch-function 'counsel-projectile-switch-project-by-name) -#+END_SRC - -** Keybindings -*** Spaces over tabs -We use two spaces in place of tabs. I don't even want to hear it. - -#+NAME: next-buffer -#+BEGIN_SRC emacs-lisp - (setq-default indent-tabs-mode nil - js-indent-level 2 - tab-width 2) - (setq-default evil-shift-width 2) -#+END_SRC - -*** Buffers -#+NAME: next-buffer -#+BEGIN_SRC emacs-lisp - (global-set-key (kbd "") 'next-buffer) -#+END_SRC - -** Display options -*** Themes -**** Doom Emacs -#+NAME: themes-autothemer -#+BEGIN_SRC emacs-lisp -(use-package doom-themes - :ensure t - :config - (setq doom-themes-enable-bold t - doom-themes-enable-italic t) - (load-theme 'doom-one t) - (doom-themes-visual-bell-config) - (doom-themes-org-config)) -#+END_SRC - -** Global Settings -*** Global Modes -I like these modes, what can I say. They're good to me. - -#+NAME: global-modes -#+BEGIN_SRC emacs-lisp - (defalias 'yes-or-no-p 'y-or-n-p) ;; Use Y or N in prompts, instead of full Yes or No - - (global-visual-line-mode t) ;; Wraps lines everywhere - (global-auto-revert-mode t) ;; Auto refresh buffers from disk - (line-number-mode t) ;; Line numbers in the gutter - (show-paren-mode t) ;; Highlights parans for me - - (setq warning-minimum-level :error) -#+END_SRC - -** Org mode -*** Agenda -Initialize org-agenda file and set some key bindings to create tasks. -#+NAME::org-mode-agenda -#+BEGIN_SRC emacs-lisp - (setq org-agenda-files "~/.emacs.d/agenda.txt" ) - - (defun my-org-insert-subheading (heading-type) - "Inserts a new org heading with unique ID and creation date. - The type of heading (TODO, PROJECT, etc.) is specified by HEADING-TYPE." - (let ((uuid (org-id-uuid)) - (date (format-time-string "[%Y-%m-%d %a %H:%M]"))) - (org-end-of-line) ;; Make sure we are at the end of the line - (unless (looking-at-p "\n") (insert "\n")) ;; Insert newline if next character is not a newline - (org-insert-subheading t) ;; Insert a subheading instead of a heading - (insert (concat heading-type " ")) - (save-excursion - (org-set-property "ID" uuid) - (org-set-property "CREATED" date)))) - - (defun my-org-insert-todo () - "Inserts a new TODO heading with unique ID and creation date." - (interactive) - (my-org-insert-subheading "TODO")) - - (defun my-org-insert-project () - "Inserts a new PROJECT heading with unique ID and creation date." - (interactive) - (my-org-insert-subheading "PROJECT")) - - (defun my-org-copy-link-from-id () - "Copies a link to the current Org mode item by its ID to clipboard" - (interactive) - (when (org-at-heading-p) - (let* ((element (org-element-at-point)) - (title (org-element-property :title element)) - (id (org-entry-get nil "ID")) - (link (format "[[id:%s][%s]]" id title))) - (when id - (kill-new link) - (message "Link saved to clipboard"))))) - - (define-prefix-command 'my-org-todo-prefix) - - (global-set-key (kbd "C-c c") 'org-capture) - (global-set-key (kbd "C-c t") 'my-org-todo-prefix) - - (define-key 'my-org-todo-prefix (kbd "t") 'my-org-insert-todo) - (define-key 'my-org-todo-prefix (kbd "p") 'my-org-insert-project) - - (define-key org-mode-map (kbd "C-c l") 'my-org-copy-link-from-id) -#+END_SRC - -**** Set org faces -Set various types and colors for ~org-mode~. - -#+NAME::org-mode-faces -#+BEGIN_SRC emacs-lisp - ;; Fast access to tag common contexts I use - (setq org-todo-keywords - '((sequence "TODO(t)" "STARTED(s)" "WAITING(w@/!)" - "DELEGATED(g@/!)" "DEFERRED(r)" "SOMEDAY(y)" - "|" "DONE(d@)" "CANCELED(x@)") - (sequence "PROJECT(p)" "|" "DONE(d@)" "CANCELED(x@)") - (sequence "APPT(a)" "|" "DONE(d@)" "CANCELED(x@)"))) - - (setq org-todo-keyword-faces - `(("TODO" . ,dl/green-color) - ("STARTED" . ,dl/yellow-color) - ("WAITING" . ,dl/light-grey-color) - ("DELEGATED" . ,dl/teal-color) - ("DEFERRED" . ,dl/dark-grey-color) - ("SOMEDAY" . ,dl/purple-color) - ("DONE" . ,dl/dark-grey-color) - ("CANCELED" . ,dl/dark-grey-color) - ("PROJECT" . ,dl/blue-color) - ("APPT" . ,dl/green-color))) - - (defface my-org-agenda-face-1-2 - '((t (:inherit default :height 1.2))) - "Face for org-agenda mode.") - - (defun my-set-org-agenda-font () - "Set the font for `org-agenda-mode'." - (buffer-face-set 'my-org-agenda-face-1-2)) - - (add-hook 'org-agenda-mode-hook 'my-set-org-agenda-font) - - (setq display-buffer-alist - `((".*Org Agenda.*" - (display-buffer-below-selected) - (inhibit-same-window . t) - (window-height . 0.5)))) - -#+END_SRC - -**** Format org-agenda views -This block sets the ~org-agenda-prefix-format~ in an friendly way for ~org-roam~ (credit to [[https://d12frosted.io/posts/2020-06-24-task-management-with-roam-vol2.html][this post)]]. It truncates long filenames and removes the ~org-roam~ timestamp slug. - -#+NAME::org-agenda-prefixes -#+BEGIN_SRC emacs-lisp - (defun dl/buffer-prop-get (name) - "Get a buffer property called NAME as a string." - (org-with-point-at 1 - (when (re-search-forward (concat "^#\\+" name ": \\(.*\\)") - (point-max) t) - (buffer-substring-no-properties - (match-beginning 1) - (match-end 1))))) - - (defun dl/agenda-category (&optional len) - "Get category of item at point for agenda." - (let* ((file-name (when buffer-file-name - (file-name-sans-extension - (file-name-nondirectory buffer-file-name)))) - (title (dl/buffer-prop-get "title")) - (category (org-get-category)) - (result (or (if (and title (string-equal category file-name)) - title - category)))) - (if (numberp len) - (s-truncate len (s-pad-right len " " result)) - result))) - - (evil-set-initial-state 'org-agenda-mode 'normal) - (with-eval-after-load 'org-agenda - (define-key org-agenda-mode-map (kbd "j") 'org-agenda-next-line) - (define-key org-agenda-mode-map (kbd "k") 'org-agenda-previous-line)) - - (setq org-agenda-todo-ignore-keywords '("PROJECT")) -#+END_SRC - -**** org-super-agenda views -Setup for ~org-super-agenda~ and ~org-ql~. - -#+NAME::org-super-agenda -#+BEGIN_SRC emacs-lisp - (use-package org-super-agenda - :after org-agenda - :init - (setq org-agenda-dim-blocked-tasks nil)) - - ;; Define custom faces for group highlighting - (defface org-super-agenda-header - '((t (:inherit org-agenda-structure :height 1.1 :foreground "#7cc3f3" :background "#282c34"))) - "Face for highlighting org-super-agenda groups.") - - (defface org-super-agenda-subheader - '((t (:inherit org-agenda-structure :height 1.0 :foreground "light slate gray" :background "black"))) - "Face for highlighting org-super-agenda subgroups.") - - ;; Apply the custom faces to org-super-agenda - (custom-set-faces - '(org-super-agenda-header ((t (:inherit org-agenda-structure :height 1.1 :foreground "#7cc3f3" :background "#282c34")))) - '(org-super-agenda-subheader ((t (:inherit org-agenda-structure :height 1.0 :foreground "light slate gray" :background "black"))))) - - (setq org-super-agenda-groups - '((:name "Priority A" - :priority "A") - (:name "Priority B" - :priority "B") - (:name "Priority C" - :priority "C") - (:name "Started" - :todo "STARTED") - (:name "Waiting" - :todo "WAITING") - (:name "Tasks" - :todo "TODO") - (:name "Someday" - :todo "SOMEDAY") - (:name "Projects" - :tag "PROJECT"))) - - (org-super-agenda-mode) -#+END_SRC - -**** org-transclusion -Let's us move text but still see it in another file. I primarily use this to move text around in my journal. - -#+NAME::org-transclusion -#+BEGIN_SRC emacs-lisp - (use-package org-transclusion - :after org - :hook (org-mode . org-transclusion-mode)) - - (defun org-global-props (&optional property buffer) - "Helper function to grab org properties" - (unless property (setq property "PROPERTY")) - (with-current-buffer (or buffer (current-buffer)) - (org-element-map (org-element-parse-buffer) 'keyword - (lambda (el) (when (string-match property (org-element-property :key el)) el))))) - -#+END_SRC - -*** Install package -If you haven't heard of org mode, go watch [[https://www.youtube.com/watch?v=SzA2YODtgK4][this]] talk and come back when you are finished. - -**** Leader key shortcuts -#+NAME::org-mode-quick-entry -#+BEGIN_SRC emacs-lisp - (defvar current-time-format "%H:%M:%S" - "Format of date to insert with `insert-current-time' func. - Note the weekly scope of the command's precision.") - - (defun dl/find-file (path) - "Helper function to open a file in a buffer" - (interactive) - (find-file path)) - - (defun dl/reload-emacs () - "Reload the emacs configuration" - (interactive) - (load "~/.emacs.d/init.el")) - - (defun dl/insert-header () - "Insert a header indented one level from the current header, unless the current header is a timestamp." - (interactive) - (let* ((level (org-current-level)) - (headline (org-get-heading t t t t)) - (next-level (if (string-match "^\\([0-9]\\{2\\}:[0-9]\\{2\\}:[0-9]\\{2\\}\\)" headline) - (1+ level) - level))) - (end-of-line) - (newline) - (insert (make-string next-level ?*)) - (insert " "))) - - (defun dl/insert-current-time () - "Insert the current time into the current buffer, at a level one deeper than the current heading." - (interactive) - (let* ((level (org-current-level)) - (next-level (1+ level))) - (end-of-line) - (newline) - (insert (make-string next-level ?*)) - (insert " " (format-time-string "%H:%M:%S" (current-time)) "\n"))) - - "Emacs relates shortcuts" - (dl/leader-keys - "e" '(:ignore t :which-key "emacs") - "ee" '(dl/load-buffer-with-emacs-config :which-key "open emacs config") - "er" '(dl/reload-emacs :which-key "reload emacs")) - - "A few of my own personal shortcuts" - (dl/leader-keys - "," '(dl/insert-header :which-key "insert header") - "<" '(dl/insert-current-time :which-key "insert header with current time")) - #+END_SRC - -***** Roam capture templates -These are templates used to create new notes. - -#+NAME::roam-templates -#+BEGIN_SRC emacs-lisp - (setq org-roam-capture-templates - '(("d" "default" plain - "%?" - :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n\n") - :unnarrowed t))) -#+END_SRC - -**** Org Roam -***** Install package -#+NAME::org-roam-package -#+BEGIN_SRC emacs-lisp - (require 'ucs-normalize) - (use-package org-roam - :straight (:host github :repo "org-roam/org-roam" - :branch "main" - :files (:defaults "extensions/*") - :build (:not compile)) - :init - (setq org-roam-v2-ack t) ;; Turn off v2 warning - (setq org-roam-mode-section-functions - (list #'org-roam-backlinks-section - #'org-roam-reflinks-section - #'org-roam-unlinked-references-section)) - (add-to-list 'display-buffer-alist - '("\\*org-roam\\*" - (display-buffer-in-direction) - (direction . right) - (window-width . 0.33) - (window-height . fit-window-to-buffer))) - :custom - (org-roam-directory (file-truename "~/.local/share/org-roam")) - (org-roam-dailies-directory "daily/") - (org-roam-completion-everywhere t) - :bind - (("C-c r b" . org-roam-buffer-toggle) - ("C-c r t" . org-roam-dailies-goto-today) - ("C-c r y" . org-roam-dailies-goto-yesterday) - ("C-M-n" . org-roam-node-insert) - :map org-mode-map - ("C-M-i" . completion-at-point) - ("C-M-f" . org-roam-node-find) - ("C-M-c" . dl/org-roam-create-id) - ("C-" . org-roam-dailies-goto-previous-note) - ("C-`" . org-roam-buffer-toggle) - ("C-" . org-roam-dailies-goto-next-note))) - (org-roam-db-autosync-mode) -#+END_SRC - -***** Configure templates -#+NAME::org-roam-templates -#+BEGIN_SRC emacs-lisp -(setq org-roam-dailies-capture-templates - '(("d" "default" entry - "* %?" - :if-new (file+head "%<%Y-%m-%d>.org" - (lambda () (concat ":PROPERTIES:\n:ID: " (org-id-new) "\n:END:\n" - "#+TITLE: %<%Y-%m-%d>\n#+filetags: Daily \n" ; Added space here - "* Log\n")))))) -#+END_SRC - -***** Extending Roam -Here we add additional function to ~org-roam~ to either do something specific for more workflow, or otherwise make ~org-roam~ more full featured. - -****** Set CREATED and LAST_MODIFIED filetags on save -Sets timestamps in the Properties drawer of files. I intend to use this one day when rendering these notes as HTML, to quickly see files last touched. - -#+NAME::org-roam-set-timestamps-on-save -#+BEGIN_SRC emacs-lisp - (defvar dl/org-created-property-name "CREATED") - - (defun dl/org-set-created-property (&optional active name) - (interactive) - (let* ((created (or name dl/org-created-property-name)) - (fmt (if active "<%s>" "[%s]")) - (now (format fmt (format-time-string "%Y-%m-%d %a %H:%M")))) - (unless (org-entry-get (point) created nil) - (org-set-property created now) - now))) - - (defun dl/org-find-time-file-property (property &optional anywhere) - (save-excursion - (goto-char (point-min)) - (let ((first-heading - (save-excursion - (re-search-forward org-outline-regexp-bol nil t)))) - (when (re-search-forward (format "^#\\+%s:" property) - (if anywhere nil first-heading) t) - (point))))) - - (defun dl/org-has-time-file-property-p (property &optional anywhere) - (when-let ((pos (dl/org-find-time-file-property property anywhere))) - (save-excursion - (goto-char pos) - (if (and (looking-at-p " ") - (progn (forward-char) - (org-at-timestamp-p 'lax))) - pos -1)))) - - (defun dl/org-set-time-file-property (property &optional anywhere pos) - (when-let ((pos (or pos - (dl/org-find-time-file-property property)))) - (save-excursion - (goto-char pos) - (if (looking-at-p " ") - (forward-char) - (insert " ")) - (delete-region (point) (line-end-position)) - (let* ((now (format-time-string "[%Y-%m-%d %a %H:%M]"))) - (insert now))))) - - (defun dl/org-set-last-modified () - "Update the LAST_MODIFIED file property in the preamble." - (when (derived-mode-p 'org-mode) - (dl/org-set-time-file-property "LAST_MODIFIED"))) -#+END_SRC - -****** Set CREATED on node creation -#+NAME::org-roam-set-timestamps-on-save -#+BEGIN_SRC emacs-lisp - (defun dl/org-roam-create-id () - "Add created date to org-roam node." - (interactive) - (org-id-get-create) - (dl/org-set-created-property)) -#+END_SRC - -*** UI improvements -Anything related to improving org mode's appearance. - -**** Change color of ivy window selection -#+NAME::ivy-window-selection -#+BEGIN_SRC emacs-lisp -(set-face-attribute 'ivy-current-match nil :foreground "#3d434d" :background "#ffcc66") -#+END_SRC - -**** Change default bullets to be pretty -Replaces the standard org-mode header asterisks with dots. -#+NAME::org-mode-visuals -#+BEGIN_SRC emacs-lisp - (use-package org-superstar - :after org - :hook (org-mode . org-superstar-mode) - :custom - (org-superstar-remove-leading-stars t) - (org-superstar-headline-bullets-list '("•" "•" "•" "◦" "◦" "◦" "◦"))) -#+END_SRC - -**** Fonts -#+NAME::org-mode-variable-width-fonts -#+BEGIN_SRC emacs-lisp - (add-hook 'org-mode-hook 'variable-pitch-mode) - (require 'org-indent) - (set-face-attribute 'org-block nil :foreground nil :inherit 'fixed-pitch) - (set-face-attribute 'org-table nil :inherit 'fixed-pitch) - (set-face-attribute 'org-formula nil :inherit 'fixed-pitch) - (set-face-attribute 'org-code nil :inherit '(shadow fixed-pitch)) - (set-face-attribute 'org-indent nil :inherit '(org-hide fixed-pitch)) - (set-face-attribute 'org-verbatim nil :inherit '(shadow fixed-pitch)) - (set-face-attribute 'org-special-keyword nil :inherit '(font-lock-comment-face fixed-pitch)) - (set-face-attribute 'org-meta-line nil :inherit '(font-lock-comment-face fixed-pitch)) - (set-face-attribute 'org-checkbox nil :inherit 'fixed-pitch) - (when (system-is-linux) - (set-face-attribute 'org-document-title nil :font "Helvetica LT Std Condensed" :weight 'bold :height 1.2)) - (when (system-is-mac) - (set-face-attribute 'variable-pitch nil :font "Helvetica" :height 120)) - (dolist (face '((org-level-1 . 1.2) - (org-level-2 . 1.15) - (org-level-3 . 1.1) - (org-level-4 . 1.05) - (org-level-5 . 1.05) - (org-level-6 . 1.0) - (org-level-7 . 1.0) - (org-level-8 . 1.0))) - (when (system-is-linux) - (set-face-attribute (car face) nil :font "Helvetica LT Std Condensed" :weight 'medium :height (cdr face))) - (when (system-is-mac) - (set-face-attribute 'variable-pitch nil :font "Helvetica" :weight 'medium :height 170))) -#+END_SRC - -** Evil mode (aka Vim mode) -*** Install package -This is what makes emacs possible for me. All evil mode packages and related configuration. - -#+NAME: evil-packages -#+BEGIN_SRC emacs-lisp -(defun dl/evil-hook () - (dolist (mode '(eshell-mode - git-rebase-mode - term-mode)) - (add-to-list 'evil-emacs-state-modes mode))) ;; no evil mode for these modes - -(use-package evil - :init - (setq evil-want-integration t) ;; TODO: research what this does - (setq evil-want-fine-undo 'fine) ;; undo/redo each motion - (setq evil-want-Y-yank-to-eol t) ;; Y copies to end of line like vim - (setq evil-want-C-u-scroll t) ;; vim like scroll up - (evil-mode 1) - :hook (evil-mode . dl/evil-hook) - :config - ;; Emacs "cancel" == vim "cancel" - (define-key evil-insert-state-map (kbd "C-g") 'evil-normal-state) - - ;; Ctrl-h deletes in vim insert mode - (define-key evil-insert-state-map (kbd "C-h") - 'evil-delete-backward-char-and-join) - - ;; When we wrap lines, jump visually, not to the "actual" next line - (evil-global-set-key 'motion "j" 'evil-next-visual-line) - (evil-global-set-key 'motion "k" 'evil-previous-visual-line) - - (evil-set-initial-state 'message-buffer-mode 'normal) - (evil-set-initial-state 'dashboard-mode 'normal)) - - ;; Gives me vim bindings elsewhere in emacs - (use-package evil-collection - :after evil - :config - (evil-collection-init)) - - ;; Keybindings in org mode - (use-package evil-org - :after evil - :hook - (org-mode . (lambda () evil-org-mode)) - :config - (require 'evil-org-agenda) - (evil-org-agenda-set-keys)) - - ;; Branching undo system - (use-package undo-tree - :after evil - :diminish - :config - (evil-set-undo-system 'undo-tree) - (global-undo-tree-mode 1)) - - (use-package evil-commentary - :after evil - :config - (evil-commentary-mode)) - - ;; Keep undo files from littering directories - (setq undo-tree-history-directory-alist '(("." . "~/.local/state/emacs/undo"))) -#+END_SRC - -** Terminal -#+NAME: vterm -#+BEGIN_SRC emacs-lisp - (use-package vterm - :commands vterm - :config - (setq term-prompt-regexp "^[^#$%>\n]*[#$%>] *") - (setq vterm-shell "zsh") - (setq vterm-max-scrollback 10000)) -#+END_SRC - -** Managing files -Configuration related to filesystem, either basic IO and interaction from emacs or directly moving files around where it makes sense. -*** File browser -~dired~ provides a more visual interface to browsing files; similar to terminal programs like ~ranger~. - -#+BEGIN_SRC emacs-lisp - (use-package all-the-icons-dired) - - (use-package dired - :ensure nil - :straight nil - :defer 1 - :commands (dired dired-jump) - :config - (setq dired-listing-switches "-agho --group-directories-first") - (setq dired-omit-files "^\\.[^.].*") - (setq dired-omit-verbose nil) - (setq dired-hide-details-hide-symlink-targets nil) - (put 'dired-find-alternate-file 'disabled nil) - (setq delete-by-moving-to-trash t) - (autoload 'dired-omit-mode "dired-x") - (add-hook 'dired-load-hook - (lambda () - (interactive) - (dired-collapse))) - (add-hook 'dired-mode-hook - (lambda () - (interactive) - (dired-omit-mode 1) - (dired-hide-details-mode 1) - (all-the-icons-dired-mode 1)) - (hl-line-mode 1))) - - (use-package dired-single) - (use-package dired-ranger) - (use-package dired-collapse) - - (evil-collection-define-key 'normal 'dired-mode-map - "h" 'dired-single-up-directory - "c" 'find-file - "H" 'dired-omit-mode - "l" 'dired-single-buffer - "y" 'dired-ranger-copy - "X" 'dired-ranger-move - "p" 'dired-ranger-paste) - - ;; Darwin needs ls from coreutils for dired to work - (when (system-is-mac) - (setq insert-directory-program - (expand-file-name ".nix-profile/bin/ls" (getenv "HOME")))) -#+END_SRC - -**** Quick shortcuts for common file tasks -#+NAME::buffer-and-file-movement -#+BEGIN_SRC emacs-lisp - (defun my-org-archive-done-tasks () - "Archive all DONE tasks in the current buffer." - (interactive) - (org-map-entries - (lambda () - (org-archive-subtree) - (setq org-map-continue-from (outline-previous-heading))) - "/DONE" 'tree)) - - (defun er-delete-file-and-buffer () - "Kill the current buffer and deletes the file it is visiting." - (interactive) - (let ((filename (buffer-file-name))) - (when filename - (if (yes-or-no-p (concat "Do you really want to delete file: " filename "? ")) ; Ask for confirmation - (if (vc-backend filename) - (vc-delete-file filename) - (progn - (delete-file filename) - (message "Deleted file %s" filename) - (kill-buffer))) - (message "Aborted"))))) ; Abort message - - (define-key org-mode-map (kbd "C-c D") 'my-org-archive-done-tasks) - (define-key org-mode-map (kbd "C-c d") 'org-archive-subtree) - (global-set-key (kbd "C-c x") #'er-delete-file-and-buffer) -#+END_SRC - -*** Images -Quickly work with images over drag-and-drop or the clipboard. [[https://github.com/abo-abo/org-download][Link to Project README]]. -#+NAME: org-download-copy -#+BEGIN_SRC emacs-lisp - (use-package org-download) - ;; Drag-and-drop to `dired` - (add-hook 'dired-mode-hook 'org-download-enable) -#+END_SRC - -*** Backups and auto-save -These settings keep emacs from littering the filesystem with buffer backups. These files look like ~#yourfilename.txt#~ and would otherwise be dropped in your working directory. - -#+NAME: backup-files -#+BEGIN_SRC emacs-lisp -(setq backup-directory-alist - `((".*" . "~/.local/state/emacs/backup")) - backup-by-copying t ; Don't delink hardlinks - version-control t ; Use version numbers on backups - delete-old-versions t) ; Automatically delete excess backups -#+END_SRC - -#+NAME: local-file-transforms -#+BEGIN_SRC emacs-lisp -(setq auto-save-file-name-transforms - `((".*" "~/.local/state/emacs/" t))) -(setq lock-file-name-transforms - `((".*" "~/.local/state/emacs/lock-files/" t))) -#+END_SRC - -** Managing projects -*** Projectile -Projectile enables me to organize projects with a killer grep interface. - -#+NAME: projectile -#+BEGIN_SRC emacs-lisp - (use-package ripgrep) - (use-package projectile - :diminish projectile-mode - :config (projectile-mode) - :custom - ((projectile-completion-system 'ivy)) - :bind-keymap - ("C-c p" . projectile-command-map) - :init - (setq projectile-enable-caching t) - (setq projectile-sort-order 'recently-active) - (setq projectile-switch-project-action #'projectile-dired)) - - (setq projectile-project-root-files-bottom-up '("package.json" ".projectile" ".project" ".git")) - (setq projectile-ignored-projects '("~/.emacs.d/")) - (setq projectile-globally-ignored-directories '("dist" "node_modules" ".log" ".git")) - - ;; Gives me Ivy options in the Projectile menus - (use-package counsel-projectile :after projectile) -#+END_SRC - -** Writing -*** Modes -Experimenting with different distraction free writing modes. - -#+BEGIN_SRC emacs-lisp -(defun enter-writing-mode () - (load-theme 'doom-one-light t) - (when (bound-and-true-p treemacs-mode) (treemacs)) - (add-hook 'window-buffer-change-functions 'check-leaving-buffer nil t)) - -(defun exit-writing-mode () - (load-theme 'doom-one t) - (when (bound-and-true-p treemacs-mode) (treemacs)) - (remove-hook 'window-buffer-change-functions 'check-leaving-buffer t)) - -(add-hook 'writeroom-mode-hook - (lambda () - (if writeroom-mode - (enter-writing-mode) - (exit-writing-mode)))) - -(use-package writeroom-mode - :ensure t) - -(global-set-key (kbd "C-c w") 'writeroom-mode) -#+END_SRC - -*** Spell Check / Flycheck Mode -Everything related to spell and grammar checking. - -#+NAME: spell-check -#+BEGIN_SRC emacs-lisp - (when (system-is-mac) - (with-eval-after-load "ispell" - (setq ispell-program-name - (expand-file-name ".nix-profile/bin/hunspell" (getenv "HOME"))) - (setq ispell-dictionary "en_US"))) - - (use-package flyspell-correct - :after flyspell - :bind (:map flyspell-mode-map ("C-;" . flyspell-correct-wrapper))) - - (use-package flyspell-correct-ivy - :after flyspell-correct) - - (add-hook 'git-commit-mode-hook 'turn-on-flyspell) - (add-hook 'text-mode-hook 'flyspell-mode) - ;; Disable this for now, doesn't play well with long literate configuration - ;; (add-hook 'org-mode-hook 'flyspell-mode) - (add-hook 'prog-mode-hook 'flyspell-prog-mode) - - (defun spell() (interactive) (flyspell-mode 1)) -#+END_SRC - -** Coding -*** Compile buffers -Everything related to M-x compile. - -#+NAME: compilation-buffer -#+BEGIN_SRC emacs-lisp -;; Auto scroll the buffer as we compile -(setq compilation-scroll-output t) - -;; By default, eshell doesn't support ANSI colors. Enable them for compilation. -(require 'ansi-color) -(defun colorize-compilation-buffer () - (let ((inhibit-read-only t)) - (ansi-color-apply-on-region (point-min) (point-max)))) -(add-hook 'compilation-filter-hook 'colorize-compilation-buffer) -#+END_SRC -*** Tide -#+NAME: tide-mode -#+BEGIN_SRC emacs-lisp -(use-package tide - :ensure t - :after (typescript-mode company flycheck) - :hook ((typescript-mode . tide-setup) - (typescript-mode . tide-hl-identifier-mode) - (before-save . tide-format-before-save))) - -(setq tide-format-options - '(:insertSpaceAfterFunctionKeywordForAnonymousFunctions t - :placeOpenBraceOnNewLineForFunctions nil)) -#+END_SRC - -*** LSP -This is my IDE. It includes the same engine that powers VS Code, in addition to Github Copilot. - -#+NAME: lsp-mode -#+BEGIN_SRC emacs-lisp - (use-package lsp-mode - :commands lsp lsp-deferred - :init - (setq lsp-keymap-prefix "C-c l") - ;;(setq lsp-keep-workspace-alive nil) - ;;(setq lsp-restart 'ignore) - (setq lsp-headerline-breadcrumb-enable nil) - (setq lsp-auto-guess-root t) - (setq lsp-enable-which-key-integration t)) - - (use-package lsp-ui - :hook (lsp-mode . lsp-ui-mode) - :custom - (lsp-ui-doc-position 'bottom)) - - (use-package lsp-treemacs - :after lsp) - - (use-package company - :after lsp-mode - :hook (lsp-mode . company-mode) - :bind (:map company-active-map - ("" . company-complete-selection)) - (:map lsp-mode-map - ("" . company-indent-or-complete-common)) - :custom - (company-minimum-prefix-length 1) - (company-idle-delay 0.0)) - - (use-package company-box - :hook (company-mode . company-box-mode)) - - (add-hook 'lsp-mode-hook #'lsp-headerline-breadcrumb-mode) -#+END_SRC - -**** Shortcuts -Leader keys for lsp-mode. - -#+NAME: lsp-leader-keys -#+BEGIN_SRC emacs-lisp - (defun dl/lsp-find-references-other-window () - (interactive) - (switch-to-buffer-other-window (current-buffer)) - (lsp-find-references)) - - (defun dl/lsp-find-implementation-other-window () - (interactive) - (switch-to-buffer-other-window (current-buffer)) - (lsp-find-implementation)) - - (defun dl/lsp-find-definition-other-window () - (interactive) - (switch-to-buffer-other-window (current-buffer)) - (lsp-find-definition)) - - (dl/leader-keys - "l" '(:ignore t :which-key "lsp") - "lf" '(dl/lsp-find-references-other-window :which-key "find references") - "lc" '(dl/lsp-find-implementation-other-window :which-key "find implementation") - "ls" '(lsp-treemacs-symbols :which-key "list symbols") - "lt" '(list-flycheck-errors :which-key "list errors") - "lh" '(lsp-treemacs-call-hierarchy :which-key "call hierarchy") - "lF" '(lsp-format-buffer :which-key "format buffer") - "li" '(lsp-organize-imports :which-key "organize imports") - "ll" '(lsp :which-key "enable lsp mode") - "lr" '(lsp-rename :which-key "rename") - "ld" '(dl/lsp-find-definition-other-window :which-key "goto definition")) -#+END_SRC - -*** Languages -**** Python -#+NAME: python -#+BEGIN_SRC emacs-lisp - (use-package lsp-pyright - :ensure t - :hook (python-mode . (lambda () - (require 'lsp-pyright) - (lsp-deferred)))) ; or lsp-deferred -#+END_SRC - -**** Shell scripts -#+NAME: shell-scripts -#+BEGIN_SRC emacs-lisp - (add-to-list 'auto-mode-alist '("\\.env" . shell-script-mode)) -#+END_SRC - -**** YAML -#+NAME: yaml-mode -#+BEGIN_SRC emacs-lisp - (use-package yaml-mode - :commands (markdown-mode gfm-mode) - :mode (("\\.yml\\'" . yaml-mode))) -#+END_SRC - -**** Markdown -#+NAME: markdown-mode -#+BEGIN_SRC emacs-lisp - ;; This uses Github Flavored Markdown for README files - (use-package markdown-mode - :commands (markdown-mode gfm-mode) - :mode (("README\\.md\\'" . gfm-mode) - ("\\.md\\'" . markdown-mode) - ("\\.markdown\\'" . markdown-mode)) - :init (setq markdown-command "pandoc")) -#+END_SRC - -**** HTML -***** Web mode -Emmet mode gives autocompletion for HTML tags using short hand notations, which for I use the TAB key. - -#+NAME: html-auto-completion -#+BEGIN_SRC emacs-lisp - (use-package emmet-mode) - (add-hook 'sgml-mode-hook 'emmet-mode) - (add-hook 'css-mode-hook 'emmet-mode) - (define-key emmet-mode-keymap [tab] 'emmet-expand-line) - (add-to-list 'emmet-jsx-major-modes 'jsx-mode) -#+END_SRC - -***** Rainbow mode -Rainbow mode is an Emacs minor mode to highlight the color shown by a RGB hex triplet (example #FFFFFF). - -#+NAME: rainbow-mode -#+BEGIN_SRC emacs-lisp - (use-package rainbow-mode) -#+END_SRC - -**** golang -#+NAME: golang-config -#+BEGIN_SRC emacs-lisp - (use-package go-mode) - (use-package company-go) - - ;; Set up before-save hooks to format buffer and add/delete imports. - ;; Make sure you don't have other gofmt/goimports hooks enabled. - (defun lsp-go-install-save-hooks () - (add-hook 'before-save-hook #'lsp-format-buffer t t) - (add-hook 'before-save-hook #'lsp-organize-imports t t)) - - (add-hook 'go-mode-hook #'lsp-go-install-save-hooks) - (add-hook 'go-mode-hook #'lsp-deferred) - - (defun dl/go-mode-hook () - ; Call Gofmt before saving - (add-hook 'before-save-hook 'gofmt-before-save) - ; Customize compile command to run go build - (if (not (string-match "go" compile-command)) - (set (make-local-variable 'compile-command) - "go build -v && go test -v && go vet")) - ; Godef jump key binding - (local-set-key (kbd "M-.") 'godef-jump) - ;; pop-tag-mark moves back before jump, to undo M-, - (local-set-key (kbd "M-*") 'pop-tag-mark)) - - (add-hook 'go-mode-hook 'dl/go-mode-hook) -#+END_SRC - -**** Javascript / Typescript -#+NAME: javascript -#+BEGIN_SRC emacs-lisp - (use-package pnpm-mode) - (use-package prisma-mode - :straight (:host github :repo "pimeys/emacs-prisma-mode" - :branch "main")) - - (use-package web-mode - :hook (web-mode . lsp-deferred)) - - (add-to-list 'auto-mode-alist '("\\.jsx?$" . web-mode)) - (add-to-list 'auto-mode-alist '("\\.tsx$" . web-mode)) - (add-to-list 'auto-mode-alist '("\\.ts$" . web-mode)) - (add-to-list 'auto-mode-alist '("\\.js$" . web-mode)) - (add-to-list 'auto-mode-alist '("\\.html$" . web-mode)) - (add-to-list 'auto-mode-alist '("\\.vue\\'" . web-mode)) - - (defun web-mode-init-hook () - "Hooks for Web mode. Adjust indent." - (setq web-mode-markup-indent-offset 2)) - (add-hook 'web-mode-hook 'web-mode-init-hook) - - ;; Vue.js / Nuxt.js Language Server - (straight-use-package - '(lsp-volar :type git :host github :repo "jadestrong/lsp-volar")) - - (add-hook 'typescript-mode-hook #'lsp-deferred) - - ;; Keeps indentation organized across these modes - (use-package prettier-js) - (add-hook 'js2-mode-hook 'prettier-js-mode) - (add-hook 'web-mode-hook 'prettier-js-mode) - (add-hook 'css-mode-hook 'prettier-js-mode) -#+END_SRC - -*** Git -#+NAME: magit-git -#+BEGIN_SRC emacs-lisp - (use-package magit - :commands (magit-status magit-get-current-branch)) - (define-key magit-hunk-section-map (kbd "RET") 'magit-diff-visit-file-other-window) -#+END_SRC - -*** Infrastructure -**** Nix -Nix is my package manager and operating system of choice; this mode enables me to have a better time writing Nix expressions. - -#+NAME: nix-mode -#+begin_src emacs-lisp - (use-package nix-mode - :mode "\\.nix\\'") -#+end_src - -**** Docker mode -#+NAME: dockerfile-mode -#+BEGIN_SRC emacs-lisp - ;; This uses dockerfile-mode for Docker files - (use-package dockerfile-mode) - (put 'dockerfile-image-name 'safe-local-variable #'stringp) - (add-to-list 'auto-mode-alist '("\\Dockerfile?$" . dockerfile-mode)) ;; auto-enable for Dockerfiles -#+END_SRC - -**** Terraform -#+NAME: terraform-mode -#+BEGIN_SRC emacs-lisp - (use-package terraform-mode - :hook ((terraform-mode . lsp-deferred) - (terraform-mode . terraform-format-on-save-mode))) - - (add-to-list 'auto-mode-alist '("\\.tf\\'" . terraform-mode)) -#+END_SRC - -** AI -*** Copilot -#+BEGIN_SRC emacs-lisp - (use-package copilot - :straight (:host github :repo "zerolfx/copilot.el" :files ("dist" "*.el")) - :ensure t) - - (add-hook 'prog-mode-hook 'copilot-mode) - - (define-key copilot-completion-map (kbd "") 'copilot-accept-completion) - (define-key copilot-completion-map (kbd "TAB") 'copilot-accept-completion) -#+END_SRC - -** Learning Emacs -These packages may come and go, but ultimately aid in my understanding of emacs and emacs lisp. - -*** org-babel -**** Load languages to run in org mode code blocks -#+BEGIN_SRC emacs-lisp - (with-eval-after-load 'org - (org-babel-do-load-languages - 'org-babel-load-languages - '( - (emacs-lisp . t) - (python . t) - (sql . t) - (shell . t))) - ) -#+END_SRC - -**** ANSI color codes in org babel shell output -Found [[https://emacs.stackexchange.com/questions/44664/apply-ansi-color-escape-sequences-for-org-babel-results][here]]. -#+BEGIN_SRC emacs-lisp - (defun dl/babel-ansi () - (when-let ((beg (org-babel-where-is-src-block-result nil nil))) - (save-excursion - (goto-char beg) - (when (looking-at org-babel-result-regexp) - (let ((end (org-babel-result-end)) - (ansi-color-context-region nil)) - (ansi-color-apply-on-region beg end)))))) - (add-hook 'org-babel-after-execute-hook 'dl/babel-ansi) -#+END_SRC - -*** Show real-time key bindings in a separate buffer -#+NAME: command-log -#+BEGIN_SRC emacs-lisp - ;; Gives me a fancy list of commands I run - (use-package command-log-mode) - (setq global-command-log-mode t) -#+END_SRC - -*** Panel popup to show key bindings -#+NAME: which-key -#+BEGIN_SRC emacs-lisp - ;; Gives me a fancy list of commands I run - (use-package which-key - :init (which-key-mode) - :diminish which-key-mode - :config - (setq which-key-idle-delay 0.3)) -#+END_SRC - -*** Helpful documentation strings for common functions -#+NAME: helpful -#+BEGIN_SRC emacs-lisp - (use-package helpful - :custom - ;; Remap Counsel help functions - (counsel-describe-function-function #'helpful-callable) - (counsel-describe-variable-function #'helpful-variable) - :bind - ;; Remap default help functions - ([remap describe-function] . helpful-function) - ([remap describe-symbol] . helpful-symbol) - ([remap describe-variable] . helpful-variable) - ([remap describe-command] . helpful-command) - ([remap describe-key] . helpful-key)) -#+END_SRC diff --git a/modules/shared/config/emacs/init.el b/modules/shared/config/emacs/init.el deleted file mode 100644 index 35e9e92..0000000 --- a/modules/shared/config/emacs/init.el +++ /dev/null @@ -1,142 +0,0 @@ -;; ------------------------- -;; Variable Declarations -;; ------------------------- -(defvar org-config-file "~/.local/share/src/nixos-config/modules/shared/config/emacs/config.org") -(defvar default-config-file "~/.emacs.d/default-config.org") -(defvar default-config-url "https://git.kolkman.org/olaf/nixos-config_to_rule_them_all/raw/branch/main/modules/shared/config/emacs/config.org") - -;; ------------------------- -;; Package Manager Setup -;; ------------------------- -(require 'package) -(setq package-archives '(("melpa" . "https://melpa.org/packages/") - ("gnu" . "http://elpa.gnu.org/packages/"))) - -(unless (assoc-default "melpa" package-archives) - (message "Warning: MELPA source not found. Adding MELPA to package-archives.") - (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)) -(unless (assoc-default "org" package-archives) - (message "Warning: Org source not found. Adding Org to package-archives.") - (add-to-list 'package-archives '("org" . "https://orgmode.org/elpa/") t)) - -(setq package-enable-at-startup nil) - -;; ------------------------- -;; Use-Package Setup -;; ------------------------- -(unless (package-installed-p 'use-package) - (package-initialize) - (if (package-install 'use-package) - (message "use-package installed successfully.") - (error "Error: Failed to install use-package.")) - (setq use-package-verbose t) - (setq use-package-always-ensure t) - (require 'use-package)) - -;; ------------------------- -;; Environment Variables Setup -;; ------------------------- -(use-package exec-path-from-shell - :if (memq window-system '(mac ns x)) - :config - (setq exec-path-from-shell-variables '("PATH" "GOPATH" "PNPM_HOME")) - (if (exec-path-from-shell-initialize) - (message "Environment variables initialized successfully.") - (error "Error: Failed to initialize environment variables."))) - -(when (daemonp) - (exec-path-from-shell-initialize)) - -;; ------------------------- -;; Straight.el Setup -;; ------------------------- -(setq straight-repository-branch "develop") -(defvar bootstrap-version) -(let ((bootstrap-file - (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory)) - (bootstrap-version 6)) - (unless (file-exists-p bootstrap-file) - (with-current-buffer - (url-retrieve-synchronously - "https://raw.githubusercontent.com/radian-software/straight.el/develop/install.el" - 'silent 'inhibit-cookies) - (goto-char (point-max)) - (eval-print-last-sexp))) - (if (load bootstrap-file nil 'nomessage) - (message "Straight.el loaded successfully.") - (error "Error: Failed to load Straight.el."))) - -(setq straight-use-package-by-default t) -(package-initialize) - -;; ------------------------- -;; Window and UI Setup -;; ------------------------- -(defun dl/window-setup () - (condition-case nil - (progn - (column-number-mode) - (scroll-bar-mode 0) - (menu-bar-mode -1) - (tool-bar-mode 0) - (winner-mode 1) - (add-to-list 'default-frame-alist '(ns-transparent-titlebar . t)) - (add-to-list 'default-frame-alist '(ns-appearance . dark)) - (setq ns-use-proxy-icon nil) - (setq frame-title-format nil) - (message "Window and UI setup completed successfully.")) - (error (message "Error occurred in Window and UI setup.")))) -(dl/window-setup) - -;; ------------------------- -;; Org Mode Setup -;; ------------------------- -(defun dl/org-mode-setup () - (condition-case nil - (progn - (org-indent-mode) - (variable-pitch-mode 1) - (auto-fill-mode 0) - (visual-line-mode 1) - (setq evil-auto-indent nil) - (message "Org mode setup completed successfully.")) - (error (message "Error occurred in Org mode setup.")))) - -(use-package org - :defer t - :hook (org-mode . dl/org-mode-setup) - :config - (setq org-edit-src-content-indentation 2 - org-ellipsis " ▾" - org-hide-emphasis-markers t - org-hide-block-startup nil) - :bind (("C-c a" . org-agenda))) - -;; ------------------------- -;; Default Config Download -;; ------------------------- -(defun dl/download-default-config () - (condition-case nil - (progn - (unless (file-exists-p default-config-file) - (url-retrieve default-config-url - (lambda (_status) - ;; delete-region removes the HTTP headers from the downloaded content. - (delete-region (point-min) (1+ url-http-end-of-headers)) - ;; save the contents of the buffer to the file. - (write-file default-config-file))) - (message "Default configuration downloaded successfully."))) - (error (message "Error occurred while downloading the default configuration.")))) - -;; ------------------------- -;; Load Org Config or Default -;; ------------------------- -(condition-case nil - (progn - (unless (file-exists-p org-config-file) - (dl/download-default-config)) - (if (file-exists-p org-config-file) - (org-babel-load-file org-config-file) - (org-babel-load-file default-config-file)) - (message "Configuration loaded successfully.")) - (error (message "Error occurred while loading the configuration."))) diff --git a/modules/shared/files.nix b/modules/shared/files.nix index 69ed343..cabee24 100644 --- a/modules/shared/files.nix +++ b/modules/shared/files.nix @@ -9,8 +9,4 @@ # text = githubPublicKey; # }; - # Initializes Emacs with org-mode so we can tangle the main config - ".emacs.d/init.el" = { - text = builtins.readFile ../shared/config/emacs/init.el; - }; }