Move emacs dir from thoom-emacs/ to emacs/

This commit is contained in:
2024-10-03 14:45:33 -07:00
parent 8fdb6dca82
commit da83c7673a
8 changed files with 6 additions and 5 deletions

8
emacs/.gitignore vendored Normal file
View File

@@ -0,0 +1,8 @@
*
!.gitignore
!*.org
!*.el
!.gitkeep
!snippets/
!snippets/**
flycheck_init.el

541
emacs/ThoomEmacs.org Normal file
View File

@@ -0,0 +1,541 @@
#+title: Thoom Emacs
#+PROPERTY: header-args:emacs-lisp :tangle ./init.el :mkdirp yes
#+STARTUP: content
* DONE Prelude
** Package Management - Elpaca
#+BEGIN_SRC emacs-lisp
(defvar elpaca-installer-version 0.7)
(defvar elpaca-directory (expand-file-name "elpaca/" user-emacs-directory))
(defvar elpaca-builds-directory (expand-file-name "builds/" elpaca-directory))
(defvar elpaca-repos-directory (expand-file-name "repos/" elpaca-directory))
(defvar elpaca-order '(elpaca :repo "https://github.com/progfolio/elpaca.git"
:ref nil :depth 1
:files (:defaults "elpaca-test.el" (:exclude "extensions"))
:build (:not elpaca--activate-package)))
(let* ((repo (expand-file-name "elpaca/" elpaca-repos-directory))
(build (expand-file-name "elpaca/" elpaca-builds-directory))
(order (cdr elpaca-order))
(default-directory repo))
(add-to-list 'load-path (if (file-exists-p build) build repo))
(unless (file-exists-p repo)
(make-directory repo t)
(when (< emacs-major-version 28) (require 'subr-x))
(condition-case-unless-debug err
(if-let ((buffer (pop-to-buffer-same-window "*elpaca-bootstrap*"))
((zerop (apply #'call-process `("git" nil ,buffer t "clone"
,@(when-let ((depth (plist-get order :depth)))
(list (format "--depth=%d" depth) "--no-single-branch"))
,(plist-get order :repo) ,repo))))
((zerop (call-process "git" nil buffer t "checkout"
(or (plist-get order :ref) "--"))))
(emacs (concat invocation-directory invocation-name))
((zerop (call-process emacs nil buffer nil "-Q" "-L" "." "--batch"
"--eval" "(byte-recompile-directory \".\" 0 'force)")))
((require 'elpaca))
((elpaca-generate-autoloads "elpaca" repo)))
(progn (message "%s" (buffer-string)) (kill-buffer buffer))
(error "%s" (with-current-buffer buffer (buffer-string))))
((error) (warn "%s" err) (delete-directory repo 'recursive))))
(unless (require 'elpaca-autoloads nil t)
(require 'elpaca)
(elpaca-generate-autoloads "elpaca" repo)
(load "./elpaca-autoloads")))
(add-hook 'after-init-hook #'elpaca-process-queues)
(elpaca `(,@elpaca-order))
(elpaca elpaca-use-package
(elpaca-use-package-mode))
;; Wait for elpaca-use-package to finish installing before proceding
(elpaca-wait)
#+END_SRC
** Utility constants for checking operating system
#+begin_src emacs-lisp
;; Check the system used
(defconst ON-LINUX (eq system-type 'gnu/linux))
(defconst ON-MAC (eq system-type 'darwin))
(defconst ON-BSD (or ON-MAC (eq system-type 'berkeley-unix)))
(defconst ON-WINDOWS (memq system-type '(cygwin windows-nt ms-dos)))
#+end_src
** Fix PATH on macOS
Emacs on macOS doesn't naturally find shell variables like PATH, so to help it out we run a shell and load some variables from the env command.
#+begin_src emacs-lisp
(use-package exec-path-from-shell
:straight t
:if (and ON-MAC (memq window-system '(mac ns)))
:config
(dolist (var '("NIX_SSL_CERT_FILE"
"NIX_PATH"
"NIX_PROFILES"))
(add-to-list 'exec-path-from-shell-variables var))
(exec-path-from-shell-initialize))
#+end_src
** Auto-tangle this file
#+begin_src emacs-lisp
(defun thoom/org-babel-tangle-config ()
(when (string-equal (file-truename (buffer-file-name))
(expand-file-name "~/.dotfiles/thoom-emacs/ThoomEmacs.org"))
;; Dynamic scoping to the rescue
(let ((org-confirm-babel-evaluate nil))
(org-babel-tangle))))
(add-hook 'org-mode-hook (lambda () (add-hook 'after-save-hook #'thoom/org-babel-tangle-config)))
#+end_src
* DONE Basic UI Tweaks
** Theme
#+begin_src emacs-lisp
(use-package doom-themes
:straight t
:config
;; Global settings (defaults)
(setq doom-themes-enable-bold t ; if nil, bold is universally disabled
doom-themes-enable-italic t) ; if nil, italics is universally disabled
(load-theme 'doom-one t)
;; Enable flashing mode-line on errors
(doom-themes-visual-bell-config)
;; Corrects (and improves) org-mode's native fontification.
(doom-themes-org-config))
#+end_src
** Transparency
#+begin_src emacs-lisp
(set-frame-parameter (selected-frame) 'alpha '(99 98))
(add-to-list 'default-frame-alist '(alpha 99 98))
#+end_src
** Hiding Clutter
Disable a bunch of stuff we don't want to see.
#+BEGIN_SRC emacs-lisp
(setq inhibit-startup-message t
use-dialog-box nil)
(tool-bar-mode -1)
(scroll-bar-mode -1)
;; On a Mac, the menu bar doesn't take up screen real-estate, so leave it on
(unless ON-MAC
(menu-bar-mode -1))
#+END_SRC
** General Settings
Set some common settings, like global-auto-revert-mode.
#+BEGIN_SRC emacs-lisp
(setq-default scroll-error-top-bottom t)
;; Revert buffers when the underlying file has changed
(global-auto-revert-mode 1)
;; Remember recent files
(recentf-mode 1)
;; Save what you enter into minibuffer prompts
(setq history-length 25)
(savehist-mode 1)
;; Visually mark the line the cursor is on
(global-hl-line-mode 1)
;; TODO - Decide whether to enable this
;; (defalias 'yes-or-no-p 'y-or-n-p)
;; tabs are for monsters
(setq-default indent-tabs-mode nil)
(setq-default tab-width 4)
(setq-default sentence-end-double-space nil)
#+END_SRC
** hl-todo
#+begin_src emacs-lisp
(use-package hl-todo
:straight t
:init
(global-hl-todo-mode))
#+end_src
** Repeat Mode
Repeat-mode just needs to be enabled. Keymaps are defined through use-package's ~:repeat-map~ directive.
#+begin_src emacs-lisp
(repeat-mode 1)
#+end_src
** Tab Bar
#+begin_src emacs-lisp
(tab-bar-mode)
;; TODO - keybindings
#+end_src
** Custom File
Set a location for the custom file so it doesn't pollute this file.
#+BEGIN_SRC emacs-lisp
(setq custom-file (locate-user-emacs-file "custom-vars.el"))
#+END_SRC
* Emacs Server
#+begin_src emacs-lisp
(require 'server)
(unless (server-running-p) (server-start))
#+end_src
* Keybindings
** DONE Which-key
#+begin_src emacs-lisp
(use-package which-key
:straight t
:init
(which-key-mode)
(which-key-setup-side-window-bottom))
#+end_src
** WAIT Keybindings
#+BEGIN_SRC emacs-lisp
(use-package emacs
:bind
;; Window management
(("C-c w v" . split-window-right)
("C-c w s" . split-window-below)
("C-S-h" . windmove-left)
("C-S-j" . windmove-down)
("C-S-k" . windmove-up)
("C-S-l" . windmove-right)
;; Tab management
("C-c w t c" . tab-bar-new-tab)
("C-c w t r" . tab-rename)
("C-c w t d" . tab-bar-close-tab)
("C-c w t n" . tab-bar-switch-to-next-tab)
("C-c w t p" . tab-bar-switch-to-prev-tab)
;; Mac keybindings for tab management
("s-t" . tab-bar-new-tab)
("s-}" . tab-bar-switch-to-next-tab)
("s-{" . tab-bar-switch-to-prev-tab)
;; Common keybindings with tab switching in browsers, for use with my mouse bindings
("C-<next>" . tab-bar-switch-to-next-tab)
("C-<prior>" . tab-bar-switch-to-prev-tab)
;; Buffer management
("C-c b d" . kill-this-buffer)
("C-c b b" . consult-buffer)
("C-c b p" . previous-buffer)
("C-c b n" . next-buffer)
("C-c b C-c" . server-edit)
;; File management
("C-c f f" . find-file)
("C-c f r" . consult-recent-file)
("C-c f j" . dired-jump)
;; TODO - C-c g p for open project in magit
("C-o" . pop-global-mark)
("M-DEL" . backward-kill-word)
("C-:" . execute-extended-command-for-buffer))
:init
;; mark-page is not very useful, and shadows project.el bindings in Meow keypad
(unbind-key "C-x C-p"))
#+END_SRC
** DONE Dired
#+begin_src emacs-lisp
(use-package dired
:bind (:map dired-mode-map
("h" . dired-up-directory)
("l" . dired-find-file)))
#+end_src
* Editing
** WAIT Fancy Indenting
When in indent-rigidly mode (=+= in normal state), use =H/L= to adjust indent by single character increments and =h/l= to adjust by tab stops.
#+begin_src emacs-lisp
;; TODO - define keys to move region up and down by lines
(define-key indent-rigidly-map (kbd "H") 'indent-rigidly-left)
(define-key indent-rigidly-map (kbd "L") 'indent-rigidly-right)
(define-key indent-rigidly-map (kbd "h") 'indent-rigidly-left-to-tab-stop)
(define-key indent-rigidly-map (kbd "l") 'indent-rigidly-right-to-tab-stop)
#+end_src
** DONE Autocompletion
#+begin_src emacs-lisp
(use-package corfu
:straight t
;; Optional customizations
;; :custom
;; (corfu-cycle t) ;; Enable cycling for `corfu-next/previous'
;; (corfu-auto t) ;; Enable auto completion
;; (corfu-separator ?\s) ;; Orderless field separator
;; (corfu-quit-at-boundary nil) ;; Never quit at completion boundary
;; (corfu-quit-no-match nil) ;; Never quit, even if there is no match
;; (corfu-preview-current nil) ;; Disable current candidate preview
;; (corfu-preselect-first nil) ;; Disable candidate preselection
;; (corfu-on-exact-match nil) ;; Configure handling of exact matches
;; (corfu-echo-documentation nil) ;; Disable documentation in the echo area
;; (corfu-scroll-margin 5) ;; Use scroll margin
;; Enable Corfu only for certain modes.
;; :hook ((prog-mode . corfu-mode)
;; (shell-mode . corfu-mode)
;; (eshell-mode . corfu-mode))
;; Recommended: Enable Corfu globally.
;; This is recommended since Dabbrev can be used globally (M-/).
;; See also `corfu-excluded-modes'.
:init
(global-corfu-mode))
(use-package emacs
:init
(setq tab-always-indent 'complete))
#+end_src
** DONE Dumb-Jump
#+begin_src emacs-lisp
(use-package dumb-jump
:straight t
:config
(add-hook 'xref-backend-functions #'dumb-jump-xref-activate)
(setq xref-show-definitions-function #'xref-show-definitions-completing-read))
#+end_src
* Org
#+begin_src emacs-lisp
(use-package org
:hook (org-mode . visual-line-mode)
:bind (:map
org-mode-map
("C-x C-o c" . thoom-org-clear-all)
:repeat-map
thoom/org-previous-next-visible-heading-repeat-map
("n" . org-next-visible-heading)
("C-n" . org-next-visible-heading)
("p" . org-previous-visible-heading)
("C-p" . org-previous-visible-heading))
:config
;; Add structure templates
(add-to-list 'org-modules 'org-tempo t)
(add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp"))
(setq org-edit-src-content-indentation 0))
(use-package org-bullets
:straight t
:hook org-mode)
#+end_src
** DONE Groceries
#+begin_src emacs-lisp
(defun thoom-org-clear-all ()
(interactive)
(goto-char 0)
(org-map-entries
(lambda ()
(org-todo "")))
(flush-lines "CLOSED")
(message "Entries cleared."))
#+end_src
* VMOCE
** DONE Vertico
#+begin_src emacs-lisp
(use-package vertico
:straight (:files (:defaults "extensions/*"))
:init
(vertico-mode)
:bind (:map vertico-map
("C-j" . vertico-next)
("C-k" . vertico-previous)))
(use-package vertico-directory
:after vertico
:bind (:map vertico-map
("C-h" . vertico-directory-delete-word)
("C-l" . vertico-directory-enter)))
#+end_src
** DONE Marginalia
#+begin_src emacs-lisp
(use-package marginalia
:straight t
;; Either bind `marginalia-cycle' globally or only in the minibuffer
:bind (:map minibuffer-local-map
("M-A" . marginalia-cycle))
:init
(marginalia-mode))
#+end_src
** DONE Orderless
#+begin_src emacs-lisp
(use-package orderless
:straight t
:init
;; Configure a custom style dispatcher (see the Consult wiki)
;; (setq orderless-style-dispatchers '(+orderless-dispatch)
;; orderless-component-separator #'orderless-escapable-split-on-space)
(setq completion-styles '(orderless basic)
completion-category-defaults nil
completion-category-overrides '((file (styles partial-completion)))))
#+end_src
** DONE Consult
#+begin_src emacs-lisp
(use-package consult
:straight t
;; Replace bindings. Lazily loaded due by `use-package'.
:bind (;; C-c bindings (mode-specific-map)
("C-c h" . consult-history)
("C-c m" . consult-mode-command)
("C-c k" . consult-kmacro)
;; C-x bindings (ctl-x-map)
("C-x M-:" . consult-complex-command) ;; orig. repeat-complex-command
("C-x C-b" . consult-buffer)
("C-x b" . consult-buffer) ;; orig. switch-to-buffer
("C-x 4 b" . consult-buffer-other-window) ;; orig. switch-to-buffer-other-window
("C-x 5 b" . consult-buffer-other-frame) ;; orig. switch-to-buffer-other-frame
("C-x r b" . consult-bookmark) ;; orig. bookmark-jump
("C-x p b" . consult-project-buffer) ;; orig. project-switch-to-buffer
;; Custom M-# bindings for fast register access
("M-#" . consult-register-load)
("M-'" . consult-register-store) ;; orig. abbrev-prefix-mark (unrelated)
("C-M-#" . consult-register)
;; Other custom bindings
("M-y" . consult-yank-pop) ;; orig. yank-pop
("<help> a" . consult-apropos) ;; orig. apropos-command
;; M-g bindings (goto-map)
("M-g e" . consult-compile-error)
("M-g f" . consult-flymake) ;; Alternative: consult-flycheck
("M-g g" . consult-goto-line) ;; orig. goto-line
("M-g M-g" . consult-goto-line) ;; orig. goto-line
("M-g o" . consult-outline) ;; Alternative: consult-org-heading
("M-g m" . consult-mark)
("M-g k" . consult-global-mark)
("M-g i" . consult-imenu)
("M-g I" . consult-imenu-multi)
;; M-s bindings (search-map)
("M-s d" . consult-find)
("M-s D" . consult-locate)
("M-s g" . consult-grep)
("M-s G" . consult-git-grep)
("M-s r" . consult-ripgrep)
("M-s l" . consult-line)
("M-s L" . consult-line-multi)
("M-s m" . consult-multi-occur)
("M-s k" . consult-keep-lines)
("M-s u" . consult-focus-lines)
;; Isearch integration
("M-s e" . consult-isearch-history)
:map isearch-mode-map
("M-e" . consult-isearch-history) ;; orig. isearch-edit-string
("M-s e" . consult-isearch-history) ;; orig. isearch-edit-string
("M-s l" . consult-line) ;; needed by consult-line to detect isearch
("M-s L" . consult-line-multi) ;; needed by consult-line to detect isearch
;; Minibuffer history
:map minibuffer-local-map
("M-s" . consult-history) ;; orig. next-matching-history-element
("M-r" . consult-history)) ;; orig. previous-matching-history-element
;; Enable automatic preview at point in the *Completions* buffer. This is
;; relevant when you use the default completion UI.
:hook (completion-list-mode . consult-preview-at-point-mode)
;; The :init configuration is always executed (Not lazy)
:init
;; Optionally configure the register formatting. This improves the register
;; preview for `consult-register', `consult-register-load',
;; `consult-register-store' and the Emacs built-ins.
(setq register-preview-delay 0.5
register-preview-function #'consult-register-format)
;; Optionally tweak the register preview window.
;; This adds thin lines, sorting and hides the mode line of the window.
(advice-add #'register-preview :override #'consult-register-window)
;; Use Consult to select xref locations with preview
(setq xref-show-xrefs-function #'consult-xref
xref-show-definitions-function #'consult-xref)
;; Configure other variables and modes in the :config section,
;; after lazily loading the package.
:config
;; Optionally configure preview. The default value
;; is 'any, such that any key triggers the preview.
;; (setq consult-preview-key 'any)
;; (setq consult-preview-key (kbd "M-."))
;; (setq consult-preview-key (list (kbd "<S-down>") (kbd "<S-up>")))
;; For some commands and buffer sources it is useful to configure the
;; :preview-key on a per-command basis using the `consult-customize' macro.
(consult-customize
consult-theme
:preview-key '(:debounce 0.2 any)
consult-ripgrep consult-git-grep consult-grep
consult-bookmark consult-recent-file consult-xref
consult--source-bookmark consult--source-recent-file
consult--source-project-recent-file
:preview-key (kbd "M-."))
;; Optionally configure the narrowing key.
;; Both < and C-+ work reasonably well.
(setq consult-narrow-key "<") ;; (kbd "C-+")
;; Optionally make narrowing help available in the minibuffer.
;; You may want to use `embark-prefix-help-command' or which-key instead.
;; (define-key consult-narrow-map (vconcat consult-narrow-key "?") #'consult-narrow-help)
;; By default `consult-project-function' uses `project-root' from project.el.
;; Optionally configure a different project root function.
;; There are multiple reasonable alternatives to chose from.
;;;; 1. project.el (the default)
;; (setq consult-project-function #'consult--default-project--function)
;;;; 2. projectile.el (projectile-project-root)
;; (autoload 'projectile-project-root "projectile")
;; (setq consult-project-function (lambda (_) (projectile-project-root)))
;;;; 3. vc.el (vc-root-dir)
;; (setq consult-project-function (lambda (_) (vc-root-dir)))
;;;; 4. locate-dominating-file
;; (setq consult-project-function (lambda (_) (locate-dominating-file "." ".git")))
)
#+end_src
** DONE Embark
#+begin_src emacs-lisp
(use-package embark
:straight t
:bind
(("C-." . embark-act) ;; pick some comfortable binding
("C-;" . embark-dwim) ;; good alternative: M-.
("C-h B" . embark-bindings)) ;; alternative for `describe-bindings'
:init
;; Optionally replace the key help with a completing-read interface
(setq prefix-help-command #'embark-prefix-help-command)
:config
;; Hide the mode line of the Embark live/completions buffers
(add-to-list 'display-buffer-alist
'("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
nil
(window-parameters (mode-line-format . none)))))
;; Consult users will also want the embark-consult package.
(use-package embark-consult
:straight t
:after (embark consult)
:demand t ; only necessary if you have the hook below
;; if you want to have consult previews as you move around an
;; auto-updating embark collect buffer
:hook
(embark-collect-mode . consult-preview-at-point-mode))
#+end_src
* DONE Git
#+begin_src emacs-lisp
(use-package magit
:straight t
:custom (magit-save-repository-buffers 'dontask)
:bind (("C-x g" . magit-status)
:map magit-mode-map
(":" . execute-extended-command)
("x" . magit-discard)))
#+end_src
* DONE Direnv
#+begin_src emacs-lisp
(use-package direnv
:straight t
:config
(direnv-mode))
#+end_src
* Programming
** TODO LSP
** TODO Python
** TODO Web
** TODO Nix

0
emacs/backups/.gitkeep Normal file
View File

8
emacs/early-init.el Normal file
View File

@@ -0,0 +1,8 @@
;; Disable package.el in favor of straight.el
(setq package-enable-at-startup nil)
(setq gc-cons-threshold most-positive-fixnum)
(add-hook 'emacs-startup-hook
(lambda ()
(setq gc-cons-threshold (* 16 1024 1024))))

985
emacs/init.el Normal file
View File

@@ -0,0 +1,985 @@
;;; Preamble
;; Suppress native compilation warnings
(setq native-comp-async-report-warnings-errors nil)
;; Set a location for the custom file so it doesn't pollute this file.
(setq custom-file (locate-user-emacs-file "custom-vars.el"))
;;; Elpaca package manager
(defvar elpaca-installer-version 0.7)
(defvar elpaca-directory (expand-file-name "elpaca/" user-emacs-directory))
(defvar elpaca-builds-directory (expand-file-name "builds/" elpaca-directory))
(defvar elpaca-repos-directory (expand-file-name "repos/" elpaca-directory))
(defvar elpaca-order '(elpaca :repo "https://github.com/progfolio/elpaca.git"
:ref nil :depth 1
:files (:defaults "elpaca-test.el" (:exclude "extensions"))
:build (:not elpaca--activate-package)))
(let* ((repo (expand-file-name "elpaca/" elpaca-repos-directory))
(build (expand-file-name "elpaca/" elpaca-builds-directory))
(order (cdr elpaca-order))
(default-directory repo))
(add-to-list 'load-path (if (file-exists-p build) build repo))
(unless (file-exists-p repo)
(make-directory repo t)
(when (< emacs-major-version 28) (require 'subr-x))
(condition-case-unless-debug err
(if-let ((buffer (pop-to-buffer-same-window "*elpaca-bootstrap*"))
((zerop (apply #'call-process `("git" nil ,buffer t "clone"
,@(when-let ((depth (plist-get order :depth)))
(list (format "--depth=%d" depth) "--no-single-branch"))
,(plist-get order :repo) ,repo))))
((zerop (call-process "git" nil buffer t "checkout"
(or (plist-get order :ref) "--"))))
(emacs (concat invocation-directory invocation-name))
((zerop (call-process emacs nil buffer nil "-Q" "-L" "." "--batch"
"--eval" "(byte-recompile-directory \".\" 0 'force)")))
((require 'elpaca))
((elpaca-generate-autoloads "elpaca" repo)))
(progn (message "%s" (buffer-string)) (kill-buffer buffer))
(error "%s" (with-current-buffer buffer (buffer-string))))
((error) (warn "%s" err) (delete-directory repo 'recursive))))
(unless (require 'elpaca-autoloads nil t)
(require 'elpaca)
(elpaca-generate-autoloads "elpaca" repo)
(load "./elpaca-autoloads")))
(add-hook 'after-init-hook #'elpaca-process-queues)
(elpaca `(,@elpaca-order))
(elpaca elpaca-use-package
(elpaca-use-package-mode))
(elpaca-wait)
;; Magit depends on newer versions of seq/transient than Emacs bundles, but Elpaca
;; can't or won't update them on its own.
(defun +elpaca-unload-seq (e)
(and (featurep 'seq) (unload-feature 'seq t))
(elpaca--continue-build e))
(defun +elpaca-seq-build-steps ()
(append (butlast (if (file-exists-p (expand-file-name "seq" elpaca-builds-directory))
elpaca--pre-built-steps elpaca-build-steps))
(list '+elpaca-unload-seq 'elpaca--activate-package)))
(use-package seq :ensure `(seq :build ,(+elpaca-seq-build-steps)))
(use-package transient :ensure t)
(elpaca-wait)
;;; OS-specific tweaks
(defconst ON-LINUX (eq system-type 'gnu/linux))
(defconst ON-MAC (eq system-type 'darwin))
(defconst ON-BSD (or ON-MAC (eq system-type 'berkeley-unix)))
(defconst ON-WINDOWS (memq system-type '(cygwin windows-nt ms-dos)))
;; Emacs on macOS doesn't naturally find shell variables like PATH,
;; so to help it out we run a shell and load some variables from the env command.
(use-package exec-path-from-shell
:ensure t
:if (and ON-MAC (memq window-system '(mac ns)))
:config
(dolist (var '("NIX_SSL_CERT_FILE"
"NIX_PATH"
"NIX_PROFILES"))
(add-to-list 'exec-path-from-shell-variables var))
(exec-path-from-shell-initialize))
(elpaca-wait)
;;; Keybindings
(use-package emacs
:bind (("C-c o b" . reveal-in-file-browser)
("C-h C-i" . info-apropos)
("C-x )" . kmacro-end-or-call-macro)
;; Eval related mappings
("C-x e" . nil)
("C-x e b" . eval-buffer)
("C-x e d" . eval-defun)
("C-x e r" . eval-region)
("C-x e e" . eval-expression)
;; Window-management
("C-o" . nil)
("C-o C-o" . other-window)
("C-o o" . other-window)
("C-o b" . consult-buffer-other-window-no-focus)
("C-o B" . consult-buffer-other-window)
("C-o /" . split-window-right)
("C-o -" . split-window-below)
("C-o C-k" . delete-window)
("C-o 1" . delete-other-windows)
("C-o w" . windmove-up)
("C-o s" . windmove-down)
("C-o a" . windmove-left)
("C-o d" . windmove-right)
("C-o W" . windmove-swap-states-up)
("C-o S" . windmove-swap-states-down)
("C-o A" . windmove-swap-states-left)
("C-o D" . windmove-swap-states-right)
;; TODO C-wasd for resizing
;; TODO C-/ for undo window state change
("C-o z" . thoom/zoom-window)
;; TODO other-window scrolling
("C-o n" . next-buffer)
("C-o p" . previous-buffer)
:repeat-map windmove-repeat-map
("w" . windmove-up)
("a" . windmove-left)
("s" . windmove-down)
("d" . windmove-right)
("W" . windmove-swap-states-up)
("S" . windmove-swap-states-down)
("A" . windmove-swap-states-left)
("D" . windmove-swap-states-right)
:repeat-map next-buffer-repeat-map
("n" . next-buffer)
("p" . previous-buffer)
:repeat-map kmacro-repeat-map
(")" . kmacro-end-or-call-macro)))
;;;; which-key
(use-package which-key
:ensure t
:init
(which-key-mode)
(which-key-setup-side-window-bottom))
;;;; Mac modifier keys
;; Use right-option as regular option on Mac
(setq ns-alternate-modifier 'meta)
(setq ns-right-alternate-modifier 'none)
(setq ns-right-command-modifier 'meta)
;;; Editing
;;;; MWIM
(use-package mwim
:ensure t
:bind (([remap move-beginning-of-line] . mwim-beginning)
([remap move-end-of-line] . mwim-end)
:map visual-line-mode-map
("C-a" . mwim-beginning)
("C-e" . mwim-end))
:init
(defun mwim-visual-line-end ()
(mwim-point-at
(end-of-visual-line)))
(defun mwim-visual-line-beginning ()
(mwim-point-at
(beginning-of-visual-line)))
:custom
(mwim-beginning-position-functions
'(mwim-visual-line-beginning
mwim-line-beginning
mwim-code-beginning
mwim-comment-beginning))
(mwim-end-position-functions
'(mwim-visual-line-end
mwim-block-end
mwim-code-end
mwim-line-end)))
;;;; Isearch
;; Allow movement during isearch
;; C/M-v move to next/previous match not currently visible
;; M-</> move to first/last match in buffer
(setq isearch-allow-motion t)
(setq isearch-wrap-pause nil)
;;;; Avy
(use-package avy
:ensure t
:bind
(("C-j" . avy-goto-char-timer)
([remap goto-line] . avy-goto-line)
:map isearch-mode-map
("C-j" . avy-isearch)
:map lisp-interaction-mode-map
("C-j" . nil))
:demand t
:config
(defun avy-action-embark (pt)
(unwind-protect
(save-excursion
(goto-char pt)
(embark-act))
(select-window
(cdr (ring-ref avy-ring 0))))
t)
(defun avy-action-embark-dwim (pt)
(unwind-protect
(save-excursion
(goto-char pt)
(embark-dwim))
(select-window
(cdr (ring-ref avy-ring 0))))
t)
(defun avy-action-isearch (pt)
(unwind-protect
(goto-char pt)
(isearch-forward-thing-at-point))
t)
(setf (alist-get ?\; avy-dispatch-alist) 'avy-action-embark)
(setf (alist-get ?\: avy-dispatch-alist) 'avy-action-embark-dwim)
(setf (alist-get ?i avy-dispatch-alist) 'avy-action-isearch)
(setq avy-timeout-seconds 0.25)
;; Always show candidates even when there's just one, to give an
;; opportunity to select an avy action
(setq avy-single-candidate-jump nil))
(use-package avy-zap
:ensure t
:bind (("C-z" . avy-zap-up-to-char-dwim)
("M-z" . avy-zap-to-char-dwim)))
;;;; Expand-region
(use-package expand-region
:ensure t
:bind (("C-=" . er/expand-region)))
;;;; Dot-mode
(use-package dot-mode
:ensure t
:config
(global-dot-mode t))
;;;; Vundo
(use-package vundo
:ensure t
:bind ("M-/" . vundo))
;;;; Outli
(use-package outli
:ensure (:host github :repo "jdtsmith/outli")
:bind (:map outli-mode-map
("C-c C-p" . (lambda () (interactive) (outline-back-to-heading))))
:hook ((prog-mode . outli-mode)
(text-mode . outli-mode)
(outli-mode . reveal-mode)))
(use-package reveal
:bind (:map reveal-mode-map
([remap move-beginning-of-line] . mwim-beginning)
([remap move-end-of-line] . mwim-end)))
;;;; Jinx
(use-package jinx
:hook (emacs-startup . global-jinx-mode)
:bind (("M-$" . jinx-correct)
("C-M-$" . jinx-languages)))
;;; Completion
;;;; Vertico
(use-package vertico
:ensure t
:init
(vertico-mode)
(vertico-multiform-mode 1)
(add-to-list 'vertico-multiform-categories
'(jinx grid (vertico-grid-annotate . 20))))
(use-package vertico-directory
:after vertico
:bind (:map vertico-map
("C-h" . vertico-directory-delete-word)
("C-l" . vertico-directory-enter)))
;;;; Marginalia
(use-package marginalia
:ensure t
;; Either bind `marginalia-cycle' globally or only in the minibuffer
:bind (:map minibuffer-local-map
("M-A" . marginalia-cycle))
:init
(marginalia-mode))
;;;; Orderless
(use-package orderless
:ensure t
:init
(setq completion-ignore-case t)
(setq completion-styles '(orderless basic)
completion-category-defaults nil
completion-category-overrides '((file (styles partial-completion)))))
;;;; Consult
(use-package consult
:ensure t
;; Replace bindings. Lazily loaded due by `use-package'.
:bind (("C-x b" . consult-buffer)
("C-x C-b" . consult-buffer)
("C-x p g" . consult-ripgrep)
("C-x p b" . consult-project-buffer)
("C-x p F" . consult-fd)
("M-i" . consult-imenu)
("M-y" . consult-yank-from-kill-ring))
;; Enable automatic preview at point in the *Completions* buffer. This is
;; relevant when you use the default completion UI.
;; :hook (completion-list-mode . consult-preview-at-point-mode)
:init
;; Optionally configure the register formatting. This improves the register
;; preview for `consult-register', `consult-register-load',
;; `consult-register-store' and the Emacs built-ins.
(setq register-preview-delay 0.5
register-preview-function #'consult-register-format)
;; Optionally tweak the register preview window.
;; This adds thin lines, sorting and hides the mode line of the window.
(advice-add #'register-preview :override #'consult-register-window)
;; Use Consult to select xref locations with preview
(setq xref-show-xrefs-function #'consult-xref
xref-show-definitions-function #'consult-xref)
(defun consult-buffer-other-window-no-focus ()
(interactive)
(with-selected-window (next-window)
(consult-buffer)))
:config
;; For some commands and buffer sources it is useful to configure the
;; :preview-key on a per-command basis using the `consult-customize' macro.
(consult-customize
consult-theme
:preview-key '(:debounce 0.5 any)
consult-ripgrep consult-git-grep consult-grep
consult-bookmark consult-recent-file consult-xref
consult--source-bookmark consult--source-recent-file
consult--source-project-recent-file))
(use-package consult-dir
:ensure t
:bind (("C-x C-d" . consult-dir)
:map vertico-map
("C-x C-d" . consult-dir)
("C-x C-j" . consult-dir-jump-file)))
;;;; Embark
(use-package embark
:ensure t
:bind
(("C-;" . embark-act) ;; pick some comfortable binding
("C-:" . embark-dwim) ;; good alternative: M-.
("C-h B" . embark-bindings)) ;; alternative for `describe-bindings'
:init
;; Optionally replace the key help with a completing-read interface
(setq prefix-help-command #'embark-prefix-help-command)
:config
;; Hide the mode line of the Embark live/completions buffers
(add-to-list 'display-buffer-alist
'("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
nil
(window-parameters (mode-line-format . none)))))
;; Consult users will also want the embark-consult package.
(use-package embark-consult
:ensure t
:after (embark consult)
:demand t ; only necessary if you have the hook below
;; if you want to have consult previews as you move around an
;; auto-updating embark collect buffer
:hook
(embark-collect-mode . consult-preview-at-point-mode))
;;;; completion-at-point
(use-package corfu
:ensure t
:bind
(("C-'" . completion-at-point))
:init
(global-corfu-mode))
(use-package cape
:ensure t
;; Bind prefix keymap providing all Cape commands under a mnemonic key.
:bind ("C-c p" . cape-prefix-map) ;; Alternative keys: M-p, M-+, ...
:custom
(cape-dabbrev-check-other-buffers nil)
(cape-file-directory-must-exist nil)
:init
(add-hook 'completion-at-point-functions #'cape-dabbrev)
(add-hook 'completion-at-point-functions #'cape-file)
(add-hook 'completion-at-point-functions #'cape-elisp-block))
;;;; yasnippet
(use-package yasnippet
:ensure t
:init
(require 'em-cmpl)
(yas-global-mode 1))
;;; Appearance
;;;; Theme
(use-package doom-themes
:ensure t
:config
(setq doom-themes-enable-bold t
doom-themes-enable-italic t)
(load-theme 'doom-monokai-pro t)
;; Lighten comments slightly for better contrast
(custom-theme-set-faces
'doom-monokai-pro
'(font-lock-comment-face
((t (:foreground "#9A989A")))))
(enable-theme 'doom-monokai-pro)
;; Enable flashing mode-line on errors
(doom-themes-visual-bell-config)
;; Corrects (and improves) org-mode's native fontification.
(doom-themes-org-config))
;;;; Modeline
(use-package doom-modeline
:ensure t
:init
(doom-modeline-mode 1)
(setq doom-modeline-total-line-number nil))
(use-package nerd-icons
:ensure t)
;;;; Window size
(modify-all-frames-parameters '((alpha 99 99)
(top . 50)
(left . 100)
(width . 120)
(height . 60)))
;;;; Fonts
(setq thoom-font-candidates
'("FiraCode Nerd Font Mono" "Fira Code" "Menlo" "Deja Vu Sans"))
(defvar thoom-font
(seq-find #'x-list-fonts thoom-font-candidates)
"The default font to use.")
(defvar thoom-font-size
(if ON-MAC
14
12)
"The default font size to use.")
(modify-all-frames-parameters
`((font . ,(concat thoom-font "-" (number-to-string thoom-font-size)))))
;;;; Hide clutter
(setq inhibit-startup-message t
use-dialog-box nil)
(tool-bar-mode -1)
(scroll-bar-mode -1)
;; On a Mac, the menu bar doesn't take up screen real-estate, so leave it on
(unless ON-MAC
(menu-bar-mode -1))
;;; Window management
(setq switch-to-buffer-obey-display-actions t)
(use-package emacs
:bind (("s-t" . tab-bar-new-tab)
("s-w" . tab-bar-close-tab)
("s-}" . tab-bar-switch-to-next-tab)
("s-{" . tab-bar-switch-to-prev-tab))
:init
(tab-bar-mode 1))
;;;; Popper
(use-package popper
:ensure t
:bind (("M-o" . popper-toggle)
("C-o t" . popper-toggle-type)
("C-o ." . popper-cycle))
:init
(setq popper-reference-buffers
'("\\*Messages\\*"
"Output\\*$"
"\\*Async Shell Command\\*"
"\\*Backtrace\\*"
"\\*Compile-Log\\*"
"\\*Flycheck errors\\*"
help-mode
compilation-mode
"\\*eshell.*\\*" eshell-mode))
(defun thoom/popper-window-height (window)
"Make eshell popups take half the frame height, otherwise defer to popper--fit-window-height"
(let ((buffer (window-buffer window)))
(if (with-current-buffer buffer
(derived-mode-p 'eshell-mode))
(/ (frame-height (window-frame window)) 2)
(popper--fit-window-height window))))
(setq popper-window-height #'thoom/popper-window-height)
;; (setq popper-group-function #'popper-group-by-project)
(popper-mode +1)
(popper-echo-mode +1))
;;;; Zooming
(defvar thoom/zoom-saved-windows nil
"Variable to store the current window configuration for thoom/zoom.")
(defun thoom/zoom-window ()
"Delete other windows, or restore the saved window configuration if available."
(interactive)
;; Clean up if the saved config isn't valid anymore.
(if (and thoom/zoom-saved-windows
(not (window-configuration-p thoom/zoom-saved-windows)))
(setq thoom/zoom-saved-windows nil))
(if thoom/zoom-saved-windows
(progn
(set-window-configuration thoom/zoom-saved-windows)
(setq thoom/zoom-saved-windows nil))
(setq thoom/zoom-saved-windows (current-window-configuration))
(if (window-parameter (selected-window) 'window-side)
(shrink-window -100)
(delete-other-windows))))
;;; Dired
(use-package dired
:bind (:map dired-mode-map
("C-o" . nil)
("h" . dired-up-directory)))
(use-package dirvish
:ensure t
:init
(dirvish-override-dired-mode))
;;; Misc tweaks
;; When scrolling by page and hitting top/bottom, move cursor to top/bottom of buffer
(setq-default scroll-error-top-bottom t)
;; Revert buffers when the underlying file has changed
(global-auto-revert-mode 1)
;; Remember recent files
(recentf-mode 1)
(setq recentf-max-menu-items 20)
(setq recentf-max-saved-items 1000)
;; Save what you enter into minibuffer prompts
(setq history-length 25)
(savehist-mode 1)
;; Visually mark the line the cursor is on
(global-hl-line-mode 1)
;; Enable repeat mode. Keymaps are defined through use-package's :repeat-map directive.
(repeat-mode 1)
;; Answer questions with y/n instead of yes/no
(defalias 'yes-or-no-p 'y-or-n-p)
;; when opening a help window, switch focus to it unless a help window was already open
(setq-default help-window-select t)
;; tabs are for monsters
(setq-default indent-tabs-mode nil)
(setq-default tab-width 4)
(setq-default sentence-end-double-space nil)
;; Don't clobber the OS clipboard completely
(setq save-interprogram-paste-before-kill t)
;; automatically cleanup whitespace on save
(defun my-whitespace-cleanup ()
"Run `whitespace-cleanup' except for TSV files."
(unless (or (derived-mode-p 'text-mode) ; Adjust this check if necessary
(string-match "\\.tsv\\'" buffer-file-name))
(whitespace-cleanup)))
(add-hook 'before-save-hook 'my-whitespace-cleanup)
;; clean up backup file spam
(setq backup-directory-alist `(("." . "~/.saves")
("/etc/\\.*" . nil))
delete-old-versions t
kept-new-versions 4
kept-old-versions 2
version-control t)
;;;; Project
(use-package project
:config
;; Make project.el recognize directories with a .project file as project roots
(add-to-list 'project-vc-extra-root-markers ".project"))
;;;; hl-todo
(use-package hl-todo
:ensure t
:init
(global-hl-todo-mode))
;;;; View-mode
;; Read-only buffers activate view mode, toggle read only with C-x C-q
(use-package view
:init
(setq view-read-only t)
:bind (:map view-mode-map
("v" . View-scroll-half-page-forward)
("V" . View-scroll-half-page-backward)))
;;;; Direnv
(use-package direnv
:ensure t
:config
(setq direnv-always-show-summary nil)
(direnv-mode))
;;;; Explain-pause
(use-package explain-pause-mode
:ensure (:host github :repo "lastquestion/explain-pause-mode"))
;;;; Reveal-in-finder
(defun first-executable (candidates)
(seq-find #'executable-find candidates))
;; Reveal in finder/nautilus/whatever
(defun reveal-in-file-browser ()
(interactive)
(call-process
(first-executable '("xdg-open" "open"))
nil nil nil "."))
;;; Org-mode
(use-package org
:bind (("C-c o ," . thoom/org-clear-all)
("C-c o s" . org-screenshot)
("C-c SPC" . org-table-blank-field)
;; Unbind to make room for avy and mwim
:map org-mode-map
("C-j" . nil)
("C-a" . mwim-beginning)
("C-e" . mwim-end)
:map org-src-mode-map
("C-c C-c" . org-edit-src-exit))
:hook ((org-mode . visual-line-mode))
:custom
(org-special-ctrl-a/e 'reversed)
(org-hide-emphasis-markers t)
(org-use-speed-commands t)
(add-to-list 'org-speed-commands '("h" . org-fold-hide-sublevels))
(org-use-fast-todo-selection 'expert)
(org-todo-keywords '((sequence "TODO(t)" "BLOCKED(b)" "|" "DONE(d)")))
(org-image-actual-width '(800)))
(use-package org-bullets
:ensure t
:config
(add-hook 'org-mode-hook (lambda () (org-bullets-mode 1))))
;; Eagerly load org-mode
(with-temp-buffer (org-mode))
(defun thoom/org-clear-all ()
(interactive)
(goto-char 0)
(org-map-entries
(lambda ()
(org-todo "")))
;;(flush-lines "CLOSED")
(message "Entries cleared."))
;;;; Screenshots for games
;; Steps to set up:
;; 1. Install ShareX, add ShareX folder to PATH
;; 2. Create hotkey named GameNotes with settings:
;; Capture preconfigured window
;; Capture -> Pre configured window title: <game name>
;; Override after capture tasks to "Save image to file"
;; Override screenshots folder to org-screenshot-import-path
;; Override Upload settings -> File naming -> Name pattern
;; "GameNotes_%t_%y-%mo-%d-%h-%mi-%s.%ms"
;; 3. Put the following at the top of the org file:
;; #+STARTUP: inlineimages
;; #+ATTR_HTML: :width 500px
(defvar org-screenshot-import-path "/mnt/c/Users/thoom/Seafile/Games/Screenshots/")
(defvar org-screenshot-export-path org-screenshot-import-path)
(defvar org-screenshot-exec-path "ShareX.exe")
(defvar org-screenshot-exec-args "-s -workflow GameNotes")
(defun org-screenshot ()
(interactive)
(let* ((heading-name (org-get-heading t t t t))
;; Strip out the font information from the heading name
(_ (set-text-properties 0 (length heading-name) nil heading-name))
(_ (shell-command (concat org-screenshot-exec-path " " org-screenshot-exec-args)))
;; shell-command returns immediately, so wait until the screenshot is likely to have been taken
(_ (sit-for 0.35))
(in-file (car (nreverse (directory-files org-screenshot-import-path 'full "GameNotes"))))
(out-dir-name (file-name-sans-extension (file-name-nondirectory buffer-file-name)))
(out-dir (file-name-as-directory (concat (file-name-as-directory org-screenshot-export-path) out-dir-name)))
(out-file (concat out-dir heading-name "-" (org-id-uuid) ".png")))
(if (stringp in-file)
(save-excursion
(unless (file-exists-p out-dir)
(make-directory out-dir))
(rename-file in-file out-file)
(message (format "Saved %S to %S" in-file out-file))
(org-next-visible-heading 1)
(org-open-line 1)
(org-insert-link nil out-file))
(progn
(message "Failed to find saved screenshot.")))))
;;; (Ma)git
(use-package magit
:after seq
:ensure t
:custom (magit-save-repository-buffers 'dontask)
:bind (("C-x g" . magit-status)
:map magit-mode-map
(":" . execute-extended-command)
("x" . magit-discard)
:map magit-diff-section-map
("C-j" . nil)
:map magit-file-section-map
;; Unbind to stop overriding avy
("C-j" . nil)))
;;; Programming languages
;;;; Treesitter
(use-package treesit-auto
:ensure t
:custom
(treesit-auto-install 'prompt)
:config
(treesit-auto-add-to-auto-mode-alist 'all)
(global-treesit-auto-mode))
;;;; Markdown
(use-package markdown-mode
:ensure t
:mode ("README\\.md\\'" . gfm-mode)
:hook ((markdown-mode . visual-line-mode)))
;; TODO - replace with https://github.com/sshaw/copy-as-format if necessary
(defun copy-source-for-reddit ()
(interactive)
(let ((contents (buffer-substring (point) (mark))))
(with-temp-buffer
(insert contents)
(mark-whole-buffer)
(indent-rigidly (point) (mark) 4 t)
(mark-whole-buffer)
(kill-ring-save 0 0 t))))
(keymap-global-set "C-c o r" #'copy-source-for-reddit)
;;;; YAML
(use-package yaml-mode
:ensure t)
;;;; Rust
(use-package rust-mode
:ensure t)
;;;; Docker
(use-package dockerfile-mode
:ensure t)
;;;; LSP
(use-package lsp-mode
:ensure t
:commands lsp
:custom
(lsp-completion-provider :none)
:init
(setq lsp-keymap-prefix "C-c l")
;; from https://github.com/minad/corfu/wiki
(defun my/lsp-mode-setup-completion ()
(setf (alist-get 'styles (alist-get 'lsp-capf completion-category-defaults))
'(orderless)))
(defun lsp-booster--advice-json-parse (old-fn &rest args)
"Try to parse bytecode instead of json."
(or
(when (equal (following-char) ?#)
(let ((bytecode (read (current-buffer))))
(when (byte-code-function-p bytecode)
(funcall bytecode))))
(apply old-fn args)))
(advice-add (if (progn (require 'json)
(fboundp 'json-parse-buffer))
'json-parse-buffer
'json-read)
:around
#'lsp-booster--advice-json-parse)
(defun lsp-booster--advice-final-command (old-fn cmd &optional test?)
"Prepend emacs-lsp-booster command to lsp CMD."
(let ((orig-result (funcall old-fn cmd test?)))
(if (and (not test?) ;; for check lsp-server-present?
(not (file-remote-p default-directory)) ;; see lsp-resolve-final-command, it would add extra shell wrapper
lsp-use-plists
(not (functionp 'json-rpc-connection)) ;; native json-rpc
(executable-find "emacs-lsp-booster"))
(progn
(when-let ((command-from-exec-path (executable-find (car orig-result)))) ;; resolve command from exec-path (in case not found in $PATH)
(setcar orig-result command-from-exec-path))
(message "Using emacs-lsp-booster for %s!" orig-result)
(cons "emacs-lsp-booster" orig-result))
orig-result)))
(advice-add 'lsp-resolve-final-command :around #'lsp-booster--advice-final-command)
:hook ((rust-ts-mode . lsp-deferred)
(lsp-mode . lsp-enable-which-key-integration)
(lsp-completion-mode . my/lsp-mode-setup-completion)))
(use-package lsp-ui
:ensure t
:commands lsp-ui-mode
:custom
(lsp-ui-sideline-show-diagnostics nil))
;;;; Flycheck
(use-package flycheck
:ensure t
:init
(setq flycheck-keymap-prefix (kbd "C-c e"))
(global-flycheck-mode)
:bind (:repeat-map flycheck-repeat-map
("n" . flycheck-next-error)
("p" . flycheck-previous-error)))
;;;; Nix
(use-package nix-mode
:ensure t
:mode "\\.nix\\'")
;;;; Lisp
(if (string-match "x86_64-apple" system-configuration)
;; The latest version of parinfer-rust-mode is incompatible with x86 Macs, so fall back on an earlier commit
(use-package parinfer-rust-mode
:ensure (:host
github
:repo
"justinbarclay/parinfer-rust-mode"
:ref
"8df117a3b54d9e01266a3905b132a1d082944702")
:hook emacs-lisp-mode)
(use-package parinfer-rust-mode
:ensure t
:hook emacs-lisp-mode))
;;; Eshell
;;;; Eshell
(use-package eshell
:bind (("M-`" . thoom/eshell-toggle))
:config
(setq eshell-destroy-buffer-when-process-dies t
eshell-scroll-to-bottom-on-input t
eshell-history-size 10000
eshell-save-history-on-exit t
eshell-visual-commands '()
eshell-banner-message "")
(defun thoom/eshell-toggle ()
"Toggle eshell based on context.
If in eshell, call `popper-toggle`.
If not in eshell but in a project, call `project-eshell`.
Otherwise, call `eshell`."
(interactive)
(if (derived-mode-p 'eshell-mode)
(popper-toggle)
(if (project-current)
(project-eshell)
(eshell))))
;; From https://karthinks.com/software/jumping-directories-in-eshell/
(defun eshell/j (&optional regexp)
"Navigate to a previously visited directory in eshell, or to
any directory proffered by `consult-dir'."
(let ((eshell-dirs (delete-dups
(mapcar 'abbreviate-file-name
(ring-elements eshell-last-dir-ring)))))
(cond
((and (not regexp) (featurep 'consult-dir))
(let* ((consult-dir--source-eshell `(:name "Eshell"
:narrow ?e
:category file
:face consult-file
:items ,eshell-dirs))
(consult-dir-sources (cons consult-dir--source-eshell
consult-dir-sources)))
(eshell/cd (substring-no-properties
(consult-dir--pick "Switch directory: ")))))
(t (eshell/cd (if regexp (eshell-find-previous-directory regexp)
(completing-read "cd: " eshell-dirs))))))))
(use-package eshell
:bind (:map eshell-hist-mode-map
("M-r" . consult-history))
:after em-hist)
(use-package pcre2el
:ensure t
:config
(defmacro prx (&rest rx-sexp)
"Convert rx-compatible regular expressions to PCRE."
`(rxt-elisp-to-pcre (rx ,@rx-sexp))))
(use-package eshell-p10k
:ensure (:host github :repo "elken/eshell-p10k")
:config
(eshell-p10k-def-segment time
""
(format-time-string "%H:%M" (current-time))
'eshell-p10k-distro-face)
(defun num-exitcode-string ()
(if (= eshell-last-command-status 0)
(number-to-string eshell-p10k--prompt-num-index)
(format "%d (%d)" eshell-p10k--prompt-num-index eshell-last-command-status)))
(defun num-exitcode-face ()
(if (= eshell-last-command-status 0)
'eshell-p10k-git-clean-face
'eshell-p10k-git-dirty-face))
(eshell-p10k-def-segment num-exitcode
""
(num-exitcode-string)
(num-exitcode-face))
(defun eshell-p10k-prompt-function ()
"Prompt defining function."
(eshell-p10k-def-prompt '(num-exitcode time dir)))
(setq eshell-prompt-function #'eshell-p10k-prompt-function
eshell-prompt-regexp eshell-p10k-prompt-string))
(use-package eshell-syntax-highlighting
:after eshell-mode
:ensure t
:config
(eshell-syntax-highlighting-global-mode +1))
;;;; Eat
(use-package eat
:ensure t
:custom
(eat-term-name "xterm-256color")
:init
(eval-after-load 'eshell #'eat-eshell-mode)
(eval-after-load 'eshell #'eat-eshell-visual-command-mode)
:config
(defun advise-eat-keymap (map)
(define-key map [?\C-o] nil)
(define-key map (vector meta-prefix-char ?`) nil)
(define-key map [S-v] #'eat-yank))
(define-advice eat-eshell-semi-char-mode
(:after (&rest r))
(advise-eat-keymap eat-eshell-semi-char-mode-map))
(define-advice eat-semi-char-mode
(:after (&rest r))
(advise-eat-keymap eat-semi-char-mode-map))
:hook (eat-mode . (lambda ()
(setq display-line-numbers nil)
(hl-line-mode -1))))

View File

@@ -0,0 +1,4 @@
#name : Eshell for loop
#key : for
# --
for f in ${1:*} { ${2:echo} "$f"; $3} $0

View File

@@ -0,0 +1,7 @@
# -*- mode: snippet -*-
# name: Org Src Block
# key: ,src
# --
#+BEGIN_SRC $1
$2
#+END_SRC