diff --git a/README.org b/README.org index 990aea0..fac1055 100644 --- a/README.org +++ b/README.org @@ -22,23 +22,21 @@ Immutable GNU Emacs dotfiles, inspired by Doom, built for Liberty. + 100% Immutable + 100% Reproducible -#+begin_src emacs-lisp +#+begin_src emacs-lisp :tangle ~/.local/source/dotfiles/init.el +;; NOTE: This file is tangled from README.org (defconst IS-LINUX (eq system-type 'gnu/linux)) (defconst IS-WINDOWS (memq system-type '(cygwin ms-dos windows-nt))) -#+end_src -#+begin_src emacs-lisp -(defun dotfiles/tangle (dir) - "Recursively tangle the Org files within a directory." - (interactive) - (let ((org-files (directory-files-recursively dir "org"))) - (dolist (f org-files) - (org-babel-tangle-file f)))) +(load-file "~/.local/source/dotfiles/modules/core.el") +(load-file "~/.local/source/dotfiles/modules/desktop.el") +(load-file "~/.local/source/dotfiles/modules/writing.el") +(load-file "~/.local/source/dotfiles/modules/projects.el") +(load-file "~/.local/source/dotfiles/modules/interface.el") #+end_src * Core :PROPERTIES: -:header-args: :tangle ~/.local/source/dotfiles/init.el :results silent +:header-args: :tangle ~/.local/source/dotfiles/modules/core.el :results silent :END: Emacs creates a lot of files relative to ~user-emacs-directory~, these files are not part of this immutable configuration and do not belong in the emacs directory. @@ -163,6 +161,15 @@ Emacs' default user interface is horrendous, but with less than 10 lines of code (add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp"))) #+end_src +#+begin_src emacs-lisp +(defun core/tangle (dir) + "Recursively tangle the Org files within a directory." + (interactive) + (let ((org-files (directory-files-recursively dir "org"))) + (dolist (f org-files) + (org-babel-tangle-file f)))) +#+end_src + ** Custom keybindings Make the =ESC= key quit (most) prompts, instead of the default =C-g=. @@ -396,7 +403,10 @@ Open a dired buffer with =SPC d=. "d" '(dired-jump :which-key "Dired")) #+end_src -** Desktop environment +* Desktop +:PROPERTIES: +:header-args: :tangle ~/.local/source/dotfiles/modules/desktop.el :results silent +:END: I use Emacs as a Desktop Environment with the [[https://github.com/ch11ng/exwm][exwm]] package. It allows Emacs to function as a complete tiling window manager for =X11=. @@ -485,7 +495,7 @@ Connect our custom hooks and configure the input keys, a custom layer for defini * Writing :PROPERTIES: -:header-args: :tangle ~/.local/source/dotfiles/init.el :results silent +:header-args: :tangle ~/.local/source/dotfiles/modules/writing.el :results silent :END: I am using [[https://orgmode.org][Org-mode]] extensively for writing projects for different purposes. Improvements beyond what are required for my Literate Programming platform include: @@ -795,7 +805,7 @@ Create a capture template for presentations stored in the =slides= sub directory * Projects :PROPERTIES: -:header-args: :tangle ~/.local/source/dotfiles/init.el :results silent +:header-args: :tangle ~/.local/source/dotfiles/modules/projects.el :results silent :END: An IDE like experience (or better) can be achieved in Emacs using two *Microsoft* open source initiatives. @@ -958,7 +968,7 @@ Apply some custom behaviour before saving: * Interface :PROPERTIES: -:header-args: :tangle ~/.local/source/dotfiles/init.el :results silent +:header-args: :tangle ~/.local/source/dotfiles/modules/interface.el :results silent :END: *Bring Emacs out of the eighties* diff --git a/init.el b/init.el index b4bd506..ce24063 100644 --- a/init.el +++ b/init.el @@ -1,505 +1,9 @@ -(defvar dotfiles/home user-emacs-directory) - -(defvar dotfiles/cache "~/.cache/emacs") - -(setq user-emacs-directory dotfiles/cache) - -(setq create-lockfiles nil - make-backup-files nil) - -(setq straight-repository-branch "develop" - straight-use-package-by-default t) - -(defvar bootstrap-version) -(let ((bootstrap-file - (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory)) - (bootstrap-version 5)) - (unless (file-exists-p bootstrap-file) - (with-current-buffer - (url-retrieve-synchronously - "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el" - 'silent 'inhibit-cookies) - (goto-char (point-max)) - (eval-print-last-sexp))) - (load bootstrap-file nil 'nomessage)) - -(straight-use-package 'use-package) - -(use-package no-littering) - -(setq inhibit-startup-message t) -(global-prettify-symbols-mode) -(scroll-bar-mode -1) -(menu-bar-mode -1) -(tool-bar-mode -1) -(tooltip-mode -1) - -(use-package org - :hook - (org-mode . (lambda () - (org-indent-mode) - (visual-line-mode 1) - (variable-pitch-mode 1))) - :config - (setq org-ellipsis " ▾" - org-log-done 'time - org-log-into-drawer t - org-src-preserve-indentation t) - - (org-babel-do-load-languages - 'org-babel-load-languages - '((shell . t) - (python . t) - (emacs-lisp . t))) - - (require 'org-tempo) - (add-to-list 'org-structure-template-alist '("s" . "src")) - (add-to-list 'org-structure-template-alist '("q" . "quote")) - (add-to-list 'org-structure-template-alist '("e" . "example")) - (add-to-list 'org-structure-template-alist '("sh" . "src shell")) - (add-to-list 'org-structure-template-alist '("py" . "src python")) - (add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp"))) - -(global-set-key (kbd "") 'keyboard-escape-quit) - -(defvar dotfiles/idle 0.0) - -(use-package which-key - :diminish which-key-mode - :init (which-key-mode) - :config (setq which-key-idle-delay dotfiles/idle)) - -(defvar dotfiles/leader-key "SPC") -(defvar dotfiles/leader-key-global "C-SPC") - -(use-package general - :config - (general-create-definer dotfiles/leader - :states '(normal motion) - :keymaps 'override - :prefix dotfiles/leader-key - :global-prefix dotfiles/leader-key-global)) - -(use-package hydra) - -(use-package evil - :init (setq evil-want-integration t - evil-want-keybinding nil) - :config (evil-mode 1)) - -(use-package evil-collection - :after evil - :config (evil-collection-init)) - -(use-package evil-nerd-commenter - :bind ("M-;" . evilnc-comment-or-uncomment-lines)) - -(dotfiles/leader - "." '(find-file :which-key "Files") - "," '(switch-to-buffer :which-key "Buffers") - "c" '(kill-buffer-and-window :which-key "Close")) - -(dotfiles/leader - "h" '(:ignore t :which-key "Help") - "hp" '(describe-package :which-key "Package") - "hv" '(describe-variable :which-key "Variable") - "hf" '(describe-function :which-key "Function")) - -(dotfiles/leader - "q" '(:ignore t :which-key "Quit") - "qq" '(save-buffers-kill-emacs :which-key "Save") - "qw" '(kill-emacs :which-key "Now") - "qf" '(delete-frame :which-key "Frame")) - -(dotfiles/leader - "w" '(:ignore t :which-key "Window") - "ww" '(window-swap-states :which-key "Swap") - "wc" '(delete-window :which-key "Close") - "wh" '(windmove-left :which-key "Left") - "wj" '(windmove-down :which-key "Down") - "wk" '(windmove-up :which-key "Up") - "wl" '(windmove-right :which-key "Right") - "ws" '(:ignore t :which-key "Split") - "wsj" '(split-window-below :which-key "Down") - "wsl" '(split-window-right :which-key "Right")) - -(dotfiles/leader - "t" '(:ignore t :which-key "Tweaks")) - -(use-package magit - :custom (magit-display-buffer-function - #'magit-display-buffer-same-window-except-diff-v1)) - -(use-package forge) - -(dotfiles/leader - "g" '(magit-status :which-key "Magit")) - -(use-package eshell-prompt-extras - :config (setq eshell-highlight-prompt nil - eshell-prompt-function 'epe-theme-lambda)) - -(dotfiles/leader - "e" '(eshell :which-key "Shell")) - -(use-package all-the-icons) - -(use-package all-the-icons-dired - :hook (dired-mode . all-the-icons-dired-mode)) - -(require 'dired-x) - -(use-package dired-single - :config - (evil-collection-define-key 'normal 'dired-mode-map - "h" 'dired-single-up-directory - "l" 'dired-single-buffer)) - -(dotfiles/leader - "d" '(dired-jump :which-key "Dired")) - -(defun dotfiles/run (command) - "Run an external process." - (interactive (list (read-shell-command "λ "))) - (start-process-shell-command command nil command)) - -(defun dotfiles/run-in-background (command) - (let ((command-parts (split-string command "[ ]+"))) - (apply #'call-process `(,(car command-parts) nil 0 nil ,@(cdr command-parts))))) - -(dotfiles/leader - "x" '(dotfiles/run :which-key "Execute") - "z" '(async-shell-command :which-key "Async")) - -(defun dotfiles/init-hook () - (exwm-workspace-switch-create 1) - (setq display-time-and-date t) - (display-battery-mode 1) - (display-time-mode 1)) - -(defun dotfiles/update-display () - (dotfiles/run-in-background "autorandr --change --force")) - -(use-package exwm - :config - (require 'exwm-randr) - (exwm-randr-enable) - (add-hook 'exwm-init-hook #'dotfiles/init-hook) - (add-hook 'exwm-randr-screen-change-hook #'dotfiles/update-display) - (dotfiles/update-display) - (setq exwm-input-prefix-keys - '(?\M-x - ?\C-g - ?\C-\ ) - exwm-input-global-keys - `(([?\s-r] . exwm-reset) - ([?\s-&] . dotfiles/run) - ,@(mapcar (lambda (i) - `(,(kbd (format "s-%d" i)) . - (lambda () - (interactive) - (exwm-workspace-switch-create ,i)))) - (number-sequence 1 9)))) - (exwm-enable)) - -(use-package org-superstar - :hook (org-mode . org-superstar-mode)) - -;; (add-to-list 'load-path "/usr/share/emacs/site-lisp/mu4e") - -(use-package mu4e - :load-path "/usr/share/emacs/site-lisp/mu4e" - :config - (setq mu4e-change-filenames-when-moving t - mu4e-update-interval (* 5 60) ;; Every 5 minutes. - mu4e-get-mail-command "mbsync -a" - mu4e-maildir "~/.cache/mail" - mu4e-compose-signature - (concat "Chris Hayward\n" - "https://chrishayward.xyz\n")) - - ;; Ensure plain text scales for all devices. - (setq mu4e-compose-format-flowed t) - - ;; GPG signing key for outbound mail. - (setq mml-secure-openpgp-signers '("37AB1CB72B741E478CA026D43025DCBD46F81C0F")) - (add-hook 'message-send-hook 'mml-secure-message-sign-pgpmime) - - (setq message-send-mail-function 'smtpmail-send-it) - - ;; Configure mail account(s). - (setq mu4e-contexts - (list - ;; Main - ;; chris@chrishayward.xyz - (make-mu4e-context - :name "Main" - :match-func - (lambda (msg) - (when msg - (string-prefix-p "/Main" (mu4e-message-field msg :maildir)))) - :vars - '((user-full-name . "Christopher James Hayward") - (user-mail-address . "chris@chrishayward.xyz") - (smtpmail-smtp-server . "mail.chrishayward.xyz") - (smtpmail-smtp-service . 587) - (smtpmail-stream-type . starttls)))))) - -(dotfiles/leader - "m" '(mu4e :which-key "Mail")) - -(use-package org-roam - :hook (after-init . org-roam-mode) - :custom (org-roam-directory "~/.local/source/brain")) - -(use-package org-roam-server - :hook (org-roam-mode . org-roam-server-mode)) - -(dotfiles/leader - "r" '(:ignore t :which-key "Roam") - "rf" '(org-roam-find-file :which-key "Find") - "rb" '(org-roam-buffer-toggle-display :which-key "Buffer") - "rc" '(org-roam-capture :which-key "Capture") - "rd" '(:ignore t :which-key "Dailies") - "rdd" '(org-roam-dailies-find-date :which-key "Date") - "rdt" '(org-roam-dailies-find-today :which-key "Today") - "rdm" '(org-roam-dailies-find-tomorrow :which-key "Tomorrow") - "rdy" '(org-roam-dailies-find-yesterday :which-key "Yesterday")) - -(setq org-roam-capture-templates - '(("d" "Default" plain (function org-roam-capture--get-point) - "%?" - :file-name "${slug}" - :head "#+TITLE: ${title}\n" - :unnarrowed t))) - -(setq org-roam-dailies-capture-templates - '(("d" "Default" entry (function org-roam-capture--get-point) - "* %?" - :file-name "daily/%<%Y-%m-%d>" - :head "#+TITLE: %<%Y-%m-%d>\n"))) - -(defvar dotfiles/bib "~/.local/source/brain/resources.bib") -(defvar dotfiles/notes "~/.local/source/brain/notes/") - -(use-package org-noter - :after org - :config - (setq org-noter-always-create-frame nil - org-noter-notes-search-path dotfiles/notes)) - -(use-package org-pdftools - :hook (org-mode . org-pdftools-setup-link)) - -(use-package org-noter-pdftools - :after org-noter - :config - (with-eval-after-load 'pdf-annot - (add-hook 'pdf-annot-active-handler-functions #'org-noter-pdftools-jump-to-note))) - -(setq bibtex-completion-notes-path dotfiles/notes - bibtex-completion-bibliography dotfiles/bib - bibtex-completion-pdf-field "file" - bibtex-completion-notes-template-multiple-files - (concat - "#+TITLE: ${title}\n" - "#+ROAM_KEY: cite:${=key=}\n" - "#* TODO Notes\n" - ":PROPERTIES:\n" - ":CUSTOM_ID: ${=key}\n" - ":NOTER_DOCUMENT: %(orb-process-file-field \"${=key=}\")\n" - ":AUTHOR: ${author-abbrev}\n" - ":JOURNAL: ${journaltitle}\n" - ":DATE: ${date}\n" - ":YEAR: ${year}\n" - ":DOI: ${doi}\n" - ":URL: ${url}\n" - ":END:\n\n")) - -(use-package org-ref - :config - (setq org-ref-completion-library 'org-ref-helm-cite - org-ref-get-pdf-filename-function 'org-ref-get-pdf-filename-helm-bibtex - org-ref-default-bibliography dotfiles/bib - org-ref-bibliography-notes dotfiles/notes - org-ref-notes-directory dotfiles/notes - org-ref-notes-function 'orb-edit-notes - org-ref-note-title-format "* TODO %y - %t\n -:PROPERTIES:\n -:CUSTOM_ID: %k\n -:NOTER_DOCUMENT: %F\n -:ROAM_KEY: cite:%k\n -:AUTHOR: %9a\n -:JOURNAL: %j\n -:YEAR: %y\n -:VOLUME: %v\n -:PAGES: %p\n -:DOI: %D\n -:URL: %U\n -:END:\n\n")) - -(use-package org-roam-bibtex - :after (org-roam) - :hook (org-roam-mode . org-roam-bibtex-mode) - :config - (setq orb-preformat-keywords - '("=key=" "title" "url" "file" "author-or-editor" "keywords"))) - -(add-to-list 'org-roam-capture-templates - '("n" "Notes" plain (function org-roam-capture--get-point) - "" - :file-name "notes/${slug}" - :head "#+TITLE: ${=key=}: ${title}\n\n -#+ROAM_KEY:${ref}\n\n* ${title}\n -:PROPERTIES:\n -:CUSTOM_ID: ${=key=}\n -:URL: ${url}\n -:AUTHOR: ${author-or-editor}\n -:NOTER_DOCUMENT:%(orb-process-file-field \"${=key=}\")\n -:NOTER_PAGE:\n -:END:\n\n")) - -(setq org-agenda-files '("~/.local/source/brain/daily/" - "~/.local/source/secrets/org/")) - -(dotfiles/leader - "a" '(org-agenda :which-key "Agenda")) - -(use-package ox-hugo - :after ox) - -(add-to-list 'org-roam-capture-templates - '("b" "Blogging" plain (function org-roam-capture--get-point) - "%?" - :file-name "posts/${slug}" - :head "#+TITLE: ${title}\n -#+HUGO_BASE_DIR: ~/.local/source/website\n -#+HUGO_SECTION: posts\n")) - -(use-package gif-screencast - :custom - (gif-screencast-output-directory "~/.local/source/brain/screen/")) - -(dotfiles/leader - "s" '(:ignore t :which-key "Screencast") - "ss" '(gif-screencast-start-or-stop :which-key "Start / Stop") - "sp" '(gif-screencast-toggle-pause :which-key "Pause")) - -(use-package ox-reveal - :after ox - :custom (org-reveal-root "https://cdn.jsdelivr.net/reveal.js/3.9.2/")) - -(add-to-list 'org-roam-capture-templates - '("p" "Presentation" plain (function org-roam-capture--get-point) - "%?" - :file-name "slides/${slug}" - :head "#+TITLE: ${title}\n")) - -(use-package lsp-mode - :custom (gc-cons-threshold 1000000000) - (lsp-idle-delay 0.500)) - -(use-package lsp-ui - :custom (lsp-ui-doc-position 'at-point) - (lsp-ui-doc-delay 0.500)) - -(use-package projectile - :config - (setq projectile-project-search-path '("~/.local/source")) - (projectile-mode)) - -(use-package password-store - :custom (password-store-dir "~/.local/source/passwords")) - -(dotfiles/leader - "p" '(:ignore t :which-key "Passwords") - "pp" '(password-store-copy :which-key "Copy") - "pr" '(password-store-rename :which-key "Rename") - "pg" '(password-store-generate :which-key "Generate")) - -(use-package dap-mode) - -(use-package company) -(use-package company-lsp) - -(use-package ccls - :hook ((c-mode c++-mode objc-mode cuda-mode) . - (lambda () (require 'ccls) (lsp)))) - -(use-package python-mode - :hook (python-mode . lsp) - :config (require 'dap-python) - :custom (python-shell-interpreter "python3") ;; Required if "python" is not python 3. - (dap-python-executable "python3") ;; Same as above. - (dap-python-debugger 'debugpy)) - -(setenv "GOPATH" (concat (getenv "HOME") "/.go/")) - -(use-package go-mode - :hook (go-mode . lsp)) - -(defun dotfiles/go-hook () - (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 #'dotfiles/go-hook) - -(defvar dotfiles/font "Fira Code") -(defvar dotfiles/font-size 96) - -(set-face-attribute 'default nil :font dotfiles/font :height dotfiles/font-size) -(set-face-attribute 'fixed-pitch nil :font dotfiles/font :height dotfiles/font-size) -(set-face-attribute 'variable-pitch nil :font dotfiles/font :height dotfiles/font-size) - -(defhydra hydra-text-scale (:timeout 4) - "Scale" - ("j" text-scale-increase "Increase") - ("k" text-scale-decrease "Decrease") - ("f" nil "Finished" :exit t)) - -(dotfiles/leader - "tf" '(hydra-text-scale/body :which-key "Font")) - -(use-package linum-relative - :init (setq linum-relative-backend - 'display-line-numbers-mode) - :config (linum-relative-global-mode)) - -(use-package rainbow-delimiters - :hook (prog-mode . rainbow-delimiters-mode)) - -(use-package doom-themes - :init (load-theme 'doom-moonlight t)) - -(use-package doom-modeline - :init (doom-modeline-mode 1) - :custom ((doom-modeline-height 16))) - -(dotfiles/leader - "tt" '(load-theme t t :which-key "Theme")) - -(setenv "BROWSER" "flatpak run org.mozilla.firefox") - -;; (use-package fira-code-mode -;; :config -;; (global-fira-code-mode)) - -(use-package fira-code-mode - :hook prog-mode) - -(use-package dashboard - :config - (setq dashboard-center-content t - dashboard-set-init-info t - dashboard-set-file-icons t - dashboard-set-heading-icons t - dashboard-startup-banner 'logo - dashboard-projects-backend 'projectile - dashboard-items '((projects . 5) - (recents . 5) - (agenda . 5 ))) - (dashboard-setup-startup-hook)) - -(setq initial-buffer-choice - (lambda () - (get-buffer "*dashboard*"))) +;; NOTE: This file is tangled from README.org +(defconst IS-LINUX (eq system-type 'gnu/linux)) +(defconst IS-WINDOWS (memq system-type '(cygwin ms-dos windows-nt))) + +(load-file "~/.local/source/dotfiles/modules/core.el") +(load-file "~/.local/source/dotfiles/modules/desktop.el") +(load-file "~/.local/source/dotfiles/modules/writing.el") +(load-file "~/.local/source/dotfiles/modules/projects.el") +(load-file "~/.local/source/dotfiles/modules/interface.el") diff --git a/modules/core.el b/modules/core.el new file mode 100644 index 0000000..734bd9c --- /dev/null +++ b/modules/core.el @@ -0,0 +1,166 @@ +(defvar dotfiles/home user-emacs-directory) + +(defvar dotfiles/cache "~/.cache/emacs") + +(setq user-emacs-directory dotfiles/cache) + +(setq create-lockfiles nil + make-backup-files nil) + +(setq straight-repository-branch "develop" + straight-use-package-by-default t) + +(defvar bootstrap-version) +(let ((bootstrap-file + (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory)) + (bootstrap-version 5)) + (unless (file-exists-p bootstrap-file) + (with-current-buffer + (url-retrieve-synchronously + "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el" + 'silent 'inhibit-cookies) + (goto-char (point-max)) + (eval-print-last-sexp))) + (load bootstrap-file nil 'nomessage)) + +(straight-use-package 'use-package) + +(use-package no-littering) + +(setq inhibit-startup-message t) +(global-prettify-symbols-mode) +(scroll-bar-mode -1) +(menu-bar-mode -1) +(tool-bar-mode -1) +(tooltip-mode -1) + +(use-package org + :hook + (org-mode . (lambda () + (org-indent-mode) + (visual-line-mode 1) + (variable-pitch-mode 1))) + :config + (setq org-ellipsis " ▾" + org-log-done 'time + org-log-into-drawer t + org-src-preserve-indentation t) + + (org-babel-do-load-languages + 'org-babel-load-languages + '((shell . t) + (python . t) + (emacs-lisp . t))) + + (require 'org-tempo) + (add-to-list 'org-structure-template-alist '("s" . "src")) + (add-to-list 'org-structure-template-alist '("q" . "quote")) + (add-to-list 'org-structure-template-alist '("e" . "example")) + (add-to-list 'org-structure-template-alist '("sh" . "src shell")) + (add-to-list 'org-structure-template-alist '("py" . "src python")) + (add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp"))) + +(defun core/tangle (dir) + "Recursively tangle the Org files within a directory." + (interactive) + (let ((org-files (directory-files-recursively dir "org"))) + (dolist (f org-files) + (org-babel-tangle-file f)))) + +(global-set-key (kbd "") 'keyboard-escape-quit) + +(defvar dotfiles/idle 0.0) + +(use-package which-key + :diminish which-key-mode + :init (which-key-mode) + :config (setq which-key-idle-delay dotfiles/idle)) + +(defvar dotfiles/leader-key "SPC") +(defvar dotfiles/leader-key-global "C-SPC") + +(use-package general + :config + (general-create-definer dotfiles/leader + :states '(normal motion) + :keymaps 'override + :prefix dotfiles/leader-key + :global-prefix dotfiles/leader-key-global)) + +(use-package hydra) + +(use-package evil + :init (setq evil-want-integration t + evil-want-keybinding nil) + :config (evil-mode 1)) + +(use-package evil-collection + :after evil + :config (evil-collection-init)) + +(use-package evil-nerd-commenter + :bind ("M-;" . evilnc-comment-or-uncomment-lines)) + +(dotfiles/leader + "." '(find-file :which-key "Files") + "," '(switch-to-buffer :which-key "Buffers") + "c" '(kill-buffer-and-window :which-key "Close")) + +(dotfiles/leader + "h" '(:ignore t :which-key "Help") + "hp" '(describe-package :which-key "Package") + "hv" '(describe-variable :which-key "Variable") + "hf" '(describe-function :which-key "Function")) + +(dotfiles/leader + "q" '(:ignore t :which-key "Quit") + "qq" '(save-buffers-kill-emacs :which-key "Save") + "qw" '(kill-emacs :which-key "Now") + "qf" '(delete-frame :which-key "Frame")) + +(dotfiles/leader + "w" '(:ignore t :which-key "Window") + "ww" '(window-swap-states :which-key "Swap") + "wc" '(delete-window :which-key "Close") + "wh" '(windmove-left :which-key "Left") + "wj" '(windmove-down :which-key "Down") + "wk" '(windmove-up :which-key "Up") + "wl" '(windmove-right :which-key "Right") + "ws" '(:ignore t :which-key "Split") + "wsj" '(split-window-below :which-key "Down") + "wsl" '(split-window-right :which-key "Right")) + +(dotfiles/leader + "t" '(:ignore t :which-key "Tweaks")) + +(use-package magit + :custom (magit-display-buffer-function + #'magit-display-buffer-same-window-except-diff-v1)) + +(use-package forge) + +(dotfiles/leader + "g" '(magit-status :which-key "Magit")) + +(use-package eshell-prompt-extras + :config (setq eshell-highlight-prompt nil + eshell-prompt-function 'epe-theme-lambda)) + +(dotfiles/leader + "e" '(eshell :which-key "Shell")) + +(use-package all-the-icons) + +(use-package all-the-icons-dired + :hook (dired-mode . all-the-icons-dired-mode)) + +(require 'dired-x) + +(use-package dired-single + :config + (evil-collection-define-key 'normal 'dired-mode-map + "h" 'dired-single-up-directory + "l" 'dired-single-buffer)) + +(dotfiles/leader + "d" '(dired-jump :which-key "Dired")) diff --git a/modules/desktop.el b/modules/desktop.el new file mode 100644 index 0000000..e06066c --- /dev/null +++ b/modules/desktop.el @@ -0,0 +1,43 @@ +(defun dotfiles/run (command) + "Run an external process." + (interactive (list (read-shell-command "λ "))) + (start-process-shell-command command nil command)) + +(defun dotfiles/run-in-background (command) + (let ((command-parts (split-string command "[ ]+"))) + (apply #'call-process `(,(car command-parts) nil 0 nil ,@(cdr command-parts))))) + +(dotfiles/leader + "x" '(dotfiles/run :which-key "Execute") + "z" '(async-shell-command :which-key "Async")) + +(defun dotfiles/init-hook () + (exwm-workspace-switch-create 1) + (setq display-time-and-date t) + (display-battery-mode 1) + (display-time-mode 1)) + +(defun dotfiles/update-display () + (dotfiles/run-in-background "autorandr --change --force")) + +(use-package exwm + :config + (require 'exwm-randr) + (exwm-randr-enable) + (add-hook 'exwm-init-hook #'dotfiles/init-hook) + (add-hook 'exwm-randr-screen-change-hook #'dotfiles/update-display) + (dotfiles/update-display) + (setq exwm-input-prefix-keys + '(?\M-x + ?\C-g + ?\C-\ ) + exwm-input-global-keys + `(([?\s-r] . exwm-reset) + ([?\s-&] . dotfiles/run) + ,@(mapcar (lambda (i) + `(,(kbd (format "s-%d" i)) . + (lambda () + (interactive) + (exwm-workspace-switch-create ,i)))) + (number-sequence 1 9)))) + (exwm-enable)) diff --git a/modules/interface.el b/modules/interface.el new file mode 100644 index 0000000..09ff115 --- /dev/null +++ b/modules/interface.el @@ -0,0 +1,59 @@ +(defvar dotfiles/font "Fira Code") +(defvar dotfiles/font-size 96) + +(set-face-attribute 'default nil :font dotfiles/font :height dotfiles/font-size) +(set-face-attribute 'fixed-pitch nil :font dotfiles/font :height dotfiles/font-size) +(set-face-attribute 'variable-pitch nil :font dotfiles/font :height dotfiles/font-size) + +(defhydra hydra-text-scale (:timeout 4) + "Scale" + ("j" text-scale-increase "Increase") + ("k" text-scale-decrease "Decrease") + ("f" nil "Finished" :exit t)) + +(dotfiles/leader + "tf" '(hydra-text-scale/body :which-key "Font")) + +(use-package linum-relative + :init (setq linum-relative-backend + 'display-line-numbers-mode) + :config (linum-relative-global-mode)) + +(use-package rainbow-delimiters + :hook (prog-mode . rainbow-delimiters-mode)) + +(use-package doom-themes + :init (load-theme 'doom-moonlight t)) + +(use-package doom-modeline + :init (doom-modeline-mode 1) + :custom ((doom-modeline-height 16))) + +(dotfiles/leader + "tt" '(load-theme t t :which-key "Theme")) + +(setenv "BROWSER" "flatpak run org.mozilla.firefox") + +;; (use-package fira-code-mode +;; :config +;; (global-fira-code-mode)) + +(use-package fira-code-mode + :hook prog-mode) + +(use-package dashboard + :config + (setq dashboard-center-content t + dashboard-set-init-info t + dashboard-set-file-icons t + dashboard-set-heading-icons t + dashboard-startup-banner 'logo + dashboard-projects-backend 'projectile + dashboard-items '((projects . 5) + (recents . 5) + (agenda . 5 ))) + (dashboard-setup-startup-hook)) + +(setq initial-buffer-choice + (lambda () + (get-buffer "*dashboard*"))) diff --git a/modules/projects.el b/modules/projects.el new file mode 100644 index 0000000..9aca881 --- /dev/null +++ b/modules/projects.el @@ -0,0 +1,48 @@ +(use-package lsp-mode + :custom (gc-cons-threshold 1000000000) + (lsp-idle-delay 0.500)) + +(use-package lsp-ui + :custom (lsp-ui-doc-position 'at-point) + (lsp-ui-doc-delay 0.500)) + +(use-package projectile + :config + (setq projectile-project-search-path '("~/.local/source")) + (projectile-mode)) + +(use-package password-store + :custom (password-store-dir "~/.local/source/passwords")) + +(dotfiles/leader + "p" '(:ignore t :which-key "Passwords") + "pp" '(password-store-copy :which-key "Copy") + "pr" '(password-store-rename :which-key "Rename") + "pg" '(password-store-generate :which-key "Generate")) + +(use-package dap-mode) + +(use-package company) +(use-package company-lsp) + +(use-package ccls + :hook ((c-mode c++-mode objc-mode cuda-mode) . + (lambda () (require 'ccls) (lsp)))) + +(use-package python-mode + :hook (python-mode . lsp) + :config (require 'dap-python) + :custom (python-shell-interpreter "python3") ;; Required if "python" is not python 3. + (dap-python-executable "python3") ;; Same as above. + (dap-python-debugger 'debugpy)) + +(setenv "GOPATH" (concat (getenv "HOME") "/.go/")) + +(use-package go-mode + :hook (go-mode . lsp)) + +(defun dotfiles/go-hook () + (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 #'dotfiles/go-hook) diff --git a/modules/writing.el b/modules/writing.el new file mode 100644 index 0000000..15df4c8 --- /dev/null +++ b/modules/writing.el @@ -0,0 +1,192 @@ +(use-package org-superstar + :hook (org-mode . org-superstar-mode)) + +;; (add-to-list 'load-path "/usr/share/emacs/site-lisp/mu4e") + +(use-package mu4e + :load-path "/usr/share/emacs/site-lisp/mu4e" + :config + (setq mu4e-change-filenames-when-moving t + mu4e-update-interval (* 5 60) ;; Every 5 minutes. + mu4e-get-mail-command "mbsync -a" + mu4e-maildir "~/.cache/mail" + mu4e-compose-signature + (concat "Chris Hayward\n" + "https://chrishayward.xyz\n")) + + ;; Ensure plain text scales for all devices. + (setq mu4e-compose-format-flowed t) + + ;; GPG signing key for outbound mail. + (setq mml-secure-openpgp-signers '("37AB1CB72B741E478CA026D43025DCBD46F81C0F")) + (add-hook 'message-send-hook 'mml-secure-message-sign-pgpmime) + + (setq message-send-mail-function 'smtpmail-send-it) + + ;; Configure mail account(s). + (setq mu4e-contexts + (list + ;; Main + ;; chris@chrishayward.xyz + (make-mu4e-context + :name "Main" + :match-func + (lambda (msg) + (when msg + (string-prefix-p "/Main" (mu4e-message-field msg :maildir)))) + :vars + '((user-full-name . "Christopher James Hayward") + (user-mail-address . "chris@chrishayward.xyz") + (smtpmail-smtp-server . "mail.chrishayward.xyz") + (smtpmail-smtp-service . 587) + (smtpmail-stream-type . starttls)))))) + +(dotfiles/leader + "m" '(mu4e :which-key "Mail")) + +(use-package org-roam + :hook (after-init . org-roam-mode) + :custom (org-roam-directory "~/.local/source/brain")) + +(use-package org-roam-server + :hook (org-roam-mode . org-roam-server-mode)) + +(dotfiles/leader + "r" '(:ignore t :which-key "Roam") + "rf" '(org-roam-find-file :which-key "Find") + "rb" '(org-roam-buffer-toggle-display :which-key "Buffer") + "rc" '(org-roam-capture :which-key "Capture") + "rd" '(:ignore t :which-key "Dailies") + "rdd" '(org-roam-dailies-find-date :which-key "Date") + "rdt" '(org-roam-dailies-find-today :which-key "Today") + "rdm" '(org-roam-dailies-find-tomorrow :which-key "Tomorrow") + "rdy" '(org-roam-dailies-find-yesterday :which-key "Yesterday")) + +(setq org-roam-capture-templates + '(("d" "Default" plain (function org-roam-capture--get-point) + "%?" + :file-name "${slug}" + :head "#+TITLE: ${title}\n" + :unnarrowed t))) + +(setq org-roam-dailies-capture-templates + '(("d" "Default" entry (function org-roam-capture--get-point) + "* %?" + :file-name "daily/%<%Y-%m-%d>" + :head "#+TITLE: %<%Y-%m-%d>\n"))) + +(defvar dotfiles/bib "~/.local/source/brain/resources.bib") +(defvar dotfiles/notes "~/.local/source/brain/notes/") + +(use-package org-noter + :after org + :config + (setq org-noter-always-create-frame nil + org-noter-notes-search-path dotfiles/notes)) + +(use-package org-pdftools + :hook (org-mode . org-pdftools-setup-link)) + +(use-package org-noter-pdftools + :after org-noter + :config + (with-eval-after-load 'pdf-annot + (add-hook 'pdf-annot-active-handler-functions #'org-noter-pdftools-jump-to-note))) + +(setq bibtex-completion-notes-path dotfiles/notes + bibtex-completion-bibliography dotfiles/bib + bibtex-completion-pdf-field "file" + bibtex-completion-notes-template-multiple-files + (concat + "#+TITLE: ${title}\n" + "#+ROAM_KEY: cite:${=key=}\n" + "#* TODO Notes\n" + ":PROPERTIES:\n" + ":CUSTOM_ID: ${=key}\n" + ":NOTER_DOCUMENT: %(orb-process-file-field \"${=key=}\")\n" + ":AUTHOR: ${author-abbrev}\n" + ":JOURNAL: ${journaltitle}\n" + ":DATE: ${date}\n" + ":YEAR: ${year}\n" + ":DOI: ${doi}\n" + ":URL: ${url}\n" + ":END:\n\n")) + +(use-package org-ref + :config + (setq org-ref-completion-library 'org-ref-helm-cite + org-ref-get-pdf-filename-function 'org-ref-get-pdf-filename-helm-bibtex + org-ref-default-bibliography dotfiles/bib + org-ref-bibliography-notes dotfiles/notes + org-ref-notes-directory dotfiles/notes + org-ref-notes-function 'orb-edit-notes + org-ref-note-title-format "* TODO %y - %t\n +:PROPERTIES:\n +:CUSTOM_ID: %k\n +:NOTER_DOCUMENT: %F\n +:ROAM_KEY: cite:%k\n +:AUTHOR: %9a\n +:JOURNAL: %j\n +:YEAR: %y\n +:VOLUME: %v\n +:PAGES: %p\n +:DOI: %D\n +:URL: %U\n +:END:\n\n")) + +(use-package org-roam-bibtex + :after (org-roam) + :hook (org-roam-mode . org-roam-bibtex-mode) + :config + (setq orb-preformat-keywords + '("=key=" "title" "url" "file" "author-or-editor" "keywords"))) + +(add-to-list 'org-roam-capture-templates + '("n" "Notes" plain (function org-roam-capture--get-point) + "" + :file-name "notes/${slug}" + :head "#+TITLE: ${=key=}: ${title}\n\n +#+ROAM_KEY:${ref}\n\n* ${title}\n +:PROPERTIES:\n +:CUSTOM_ID: ${=key=}\n +:URL: ${url}\n +:AUTHOR: ${author-or-editor}\n +:NOTER_DOCUMENT:%(orb-process-file-field \"${=key=}\")\n +:NOTER_PAGE:\n +:END:\n\n")) + +(setq org-agenda-files '("~/.local/source/brain/daily/" + "~/.local/source/secrets/org/")) + +(dotfiles/leader + "a" '(org-agenda :which-key "Agenda")) + +(use-package ox-hugo + :after ox) + +(add-to-list 'org-roam-capture-templates + '("b" "Blogging" plain (function org-roam-capture--get-point) + "%?" + :file-name "posts/${slug}" + :head "#+TITLE: ${title}\n +#+HUGO_BASE_DIR: ~/.local/source/website\n +#+HUGO_SECTION: posts\n")) + +(use-package gif-screencast + :custom + (gif-screencast-output-directory "~/.local/source/brain/screen/")) + +(dotfiles/leader + "s" '(:ignore t :which-key "Screencast") + "ss" '(gif-screencast-start-or-stop :which-key "Start / Stop") + "sp" '(gif-screencast-toggle-pause :which-key "Pause")) + +(use-package ox-reveal + :after ox + :custom (org-reveal-root "https://cdn.jsdelivr.net/reveal.js/3.9.2/")) + +(add-to-list 'org-roam-capture-templates + '("p" "Presentation" plain (function org-roam-capture--get-point) + "%?" + :file-name "slides/${slug}" + :head "#+TITLE: ${title}\n"))