mirror of
https://gitlab.com/dwt1/dotfiles.git
synced 2026-04-11 19:17:19 +10:00
Updating Doom Emacs.
This commit is contained in:
19
.bashrc
19
.bashrc
@@ -6,10 +6,12 @@
|
||||
#
|
||||
# My bash config. Not much to see here. Some pretty standard stuff.
|
||||
|
||||
PATH="$HOME/.local/bin${PATH:+:${PATH}}"
|
||||
EDITOR="nvim"
|
||||
export TERM="st-256color"
|
||||
export HISTCONTROL=ignoredups:erasedups # no duplicate entries
|
||||
PATH="$HOME/.local/bin${PATH:+:${PATH}}" # adding .local/bin to $PATH
|
||||
export TERM="xterm-256color" # getting proper colors
|
||||
export HISTCONTROL=ignoredups:erasedups # no duplicate entries
|
||||
export ALTERNATE_EDITOR="" # setting for emacsclient
|
||||
export EDITOR="emacsclient -t -a ''" # $EDITOR use Emacs in terminal
|
||||
export VISUAL="emacsclient -c -a emacs" # $VISUAL use Emacs in GUI mode
|
||||
|
||||
[[ $- != *i* ]] && return
|
||||
|
||||
@@ -150,8 +152,15 @@ alias sudo='sudo '
|
||||
alias ..='cd ..'
|
||||
alias ...='cd ../..'
|
||||
|
||||
# vim
|
||||
# vim and emacs
|
||||
alias vim=nvim
|
||||
alias em="/usr/bin/emacs -nw"
|
||||
alias emacs="emacsclient -c -a ''"
|
||||
|
||||
# devour windows
|
||||
alias mpv="devour mpv"
|
||||
alias sxiv="devour sxiv"
|
||||
alias zathura="devour zathura"
|
||||
|
||||
# broot
|
||||
alias br='br -dhp'
|
||||
|
||||
@@ -1,28 +1,64 @@
|
||||
;;; .doom.d/config.el -*- lexical-binding: t; -*-
|
||||
;;; $DOOMDIR/config.el -*- lexical-binding: t; -*-
|
||||
|
||||
;; Place your private configuration here!
|
||||
;; ____ _____
|
||||
;; | _ \_ _| Derek Taylor (DistroTube)
|
||||
;; | | | || | http://www.youtube.com/c/DistroTube
|
||||
;; | |_| || | http://www.gitlab.com/dwt1/
|
||||
;; |____/ |_|
|
||||
;;
|
||||
;; A customized config for Doom Emacs (https://github.com/hlissner/doom-emacs)
|
||||
;; Modified by Derek Taylor (http://www.gitlab.com/dwt1/)
|
||||
;; Place your private configuration here! Remember, you do not need to run 'doom
|
||||
;; sync' after modifying this file!
|
||||
|
||||
;; Setting the font.
|
||||
(setq doom-font (font-spec :family "Mononoki Nerd Font Mono" :size 15))
|
||||
;;(setq doom-font (font-spec :family "SauceCodePro Nerd Font" :size 15))
|
||||
|
||||
;; Setting the theme
|
||||
;; Some functionality uses this to identify you, e.g. GPG configuration, email
|
||||
;; clients, file templates and snippets.
|
||||
(setq user-full-name "Derek Taylor"
|
||||
user-mail-address "derek@distrotube.com")
|
||||
|
||||
;; Doom exposes five (optional) variables for controlling fonts in Doom. Here
|
||||
;; are the three important ones:
|
||||
;;
|
||||
;; + `doom-font'
|
||||
;; + `doom-variable-pitch-font'
|
||||
;; + `doom-big-font' -- used for `doom-big-font-mode'; use this for
|
||||
;; presentations or streaming.
|
||||
;;
|
||||
;; They all accept either a font-spec, font string ("Input Mono-12"), or xlfd
|
||||
;; font string. You generally only need these two:
|
||||
(setq doom-font (font-spec :family "Mononoki Nerd Font" :size 15)
|
||||
doom-variable-pitch-font (font-spec :family "Mononoki Nerd Font" :size 15))
|
||||
|
||||
;; There are two ways to load a theme. Both assume the theme is installed and
|
||||
;; available. You can either set `doom-theme' or manually load a theme with the
|
||||
;; `load-theme' function. This is the default:
|
||||
(setq doom-theme 'doom-palenight)
|
||||
|
||||
;; If you use `org' and don't want your org files in the default location below,
|
||||
;; change `org-directory'. It must be set before org loads!
|
||||
(setq org-directory "~/Documents/org/")
|
||||
|
||||
;; This determines the style of line numbers in effect. If set to `nil', line
|
||||
;; numbers are disabled. For relative line numbers, set this to `relative'.
|
||||
(setq display-line-numbers-type t)
|
||||
|
||||
;; Setting the neotree width to be adjustable.
|
||||
(setq neo-window-fixed-size nil)
|
||||
|
||||
;; Sets binding to toggle line wrap on/off.
|
||||
(global-set-key "\C-x\ t" 'toggle-truncate-lines)
|
||||
|
||||
;; Sets binding to launch elfeed
|
||||
(global-set-key (kbd "C-x w") 'elfeed)
|
||||
|
||||
;; Set browser to eww
|
||||
(setq browse-url-browser-function 'eww-browse-url)
|
||||
|
||||
;; Force splits to open on the right
|
||||
(defun prefer-horizontal-split ()
|
||||
(set-variable 'split-height-threshold nil t)
|
||||
(set-variable 'split-width-threshold 40 t)) ; make this as low as needed
|
||||
(add-hook 'markdown-mode-hook 'prefer-horizontal-split)
|
||||
|
||||
;; Image previews in dired
|
||||
(global-set-key (kbd "C-x i") 'peep-dired)
|
||||
(evil-define-key 'normal peep-dired-mode-map (kbd "j") 'peep-dired-next-file
|
||||
(kbd "k") 'peep-dired-prev-file)
|
||||
(add-hook 'peep-dired-hook 'evil-normalize-keymaps)
|
||||
|
||||
;; Sets transparency for focuses and unfocused frames.
|
||||
;; (set-frame-parameter (selected-frame) 'alpha '(95 . 80))
|
||||
;; (add-to-list 'default-frame-alist '(alpha . (95 . 80)))
|
||||
@@ -37,14 +73,33 @@
|
||||
;; highlight-indent-guides-delay 0.01
|
||||
;; highlight-indent-guides-responsive 'top
|
||||
;; highlight-indent-guides-auto-enabled nil))
|
||||
(use-package emms
|
||||
:ensure t
|
||||
:config
|
||||
(require 'emms-setup)
|
||||
(require 'emms-info)
|
||||
(require 'emms-cue) ;; Required for processing flacs.
|
||||
(require 'emms-mode-line)
|
||||
(require 'emms-playing-time)
|
||||
(setq emms-source-file-default-directory "~/Music/Non-Classical/70s-80s/")
|
||||
(setq emms-playlist-buffer-name "*Music*")
|
||||
(setq emms-info-asynchronously t)
|
||||
(unless (eq system-type 'windows-nt)
|
||||
(setq emms-source-file-directory-tree-function
|
||||
'emms-source-file-directory-tree-find))
|
||||
(emms-all)
|
||||
(emms-default-players)
|
||||
(emms-mode-line 1)
|
||||
(emms-playing-time 1))
|
||||
|
||||
(require 'emms-setup)
|
||||
(emms-standard)
|
||||
(emms-default-players)
|
||||
|
||||
;; Setting up mu4e which is an email client that works within emacs.
|
||||
;; You must install mu4e and mbsync through your Linux distribution's
|
||||
;; package manager.
|
||||
|
||||
;; Adding path to mu4e
|
||||
(add-to-list 'load-path "/usr/local/share/emacs/site-lisp/mu4e")
|
||||
|
||||
(require 'mu4e)
|
||||
(setq mu4e-get-mail-command "mbsync -c ~/.emacs.d/mu4e/.mbsyncrc -a"
|
||||
mu4e-update-interval 300)
|
||||
@@ -71,5 +126,38 @@
|
||||
smtpmail-default-smtp-server "smtp.1and1.com"
|
||||
smtpmail-smtp-server "smtp.1and1.com"
|
||||
smtpmail-smtp-service 587)
|
||||
;; don't keep message buffers around
|
||||
(setq message-kill-buffer-on-exit t)
|
||||
|
||||
|
||||
;; Here are some additional functions/macros that could help you configure Doom:
|
||||
;;
|
||||
;; - `load!' for loading external *.el files relative to this one
|
||||
;; - `use-package!' for configuring packages
|
||||
;; - `after!' for running code after a package has loaded
|
||||
;; - `add-load-path!' for adding directories to the `load-path', relative to
|
||||
;; this file. Emacs searches the `load-path' when you load packages with
|
||||
;; `require' or `use-package'.
|
||||
;; - `map!' for binding new keys
|
||||
;;
|
||||
;; To get information about any of these functions/macros, move the cursor over
|
||||
;; the highlighted symbol at press 'K' (non-evil users must press 'C-c c k').
|
||||
;; This will open documentation for it, including demos of how they are used.
|
||||
;;
|
||||
;; You can also try 'gd' (or 'C-c c d') to jump to their definition and see how
|
||||
;; they are implemented.
|
||||
|
||||
(custom-set-variables
|
||||
;; custom-set-variables was added by Custom.
|
||||
;; If you edit it by hand, you could mess it up, so be careful.
|
||||
;; Your init file should contain only one such instance.
|
||||
;; If there is more than one, they won't work right.
|
||||
'(elfeed-feeds
|
||||
(quote
|
||||
("https://www.gamingonlinux.com/article_rss.php" "https://hackaday.com/blog/feed/" "https://opensource.com/feed" "https://linux.softpedia.com/backend.xml" "https://itsfoss.com/feed/" "https://www.zdnet.com/topic/linux/rss.xml" "https://www.phoronix.com/rss.php" "http://feeds.feedburner.com/d0od" "https://www.computerworld.com/index.rss" "https://www.networkworld.com/category/linux/index.rss" "https://www.techrepublic.com/rssfeeds/topic/open-source/" "https://betanews.com/feed" "http://lxer.com/module/newswire/headlines.rss" "https://distrowatch.com/news/dwd.xml")))
|
||||
'(package-selected-packages (quote (peep-dired nav-flash evil-mu4e emms elfeed))))
|
||||
|
||||
(custom-set-faces
|
||||
;; custom-set-faces was added by Custom.
|
||||
;; If you edit it by hand, you could mess it up, so be careful.
|
||||
;; Your init file should contain only one such instance.
|
||||
;; If there is more than one, they won't work right.
|
||||
)
|
||||
|
||||
126
.doom.d/init.el
126
.doom.d/init.el
@@ -1,14 +1,20 @@
|
||||
;;; init.el -*- lexical-binding: t; -*-
|
||||
|
||||
;; Copy this file to ~/.doom.d/init.el or ~/.config/doom/init.el ('doom install'
|
||||
;; will do this for you). The `doom!' block below controls what modules are
|
||||
;; enabled and in what order they will be loaded. Remember to run 'doom refresh'
|
||||
;; after modifying it.
|
||||
;;
|
||||
;; More information about these modules (and what flags they support) can be
|
||||
;; found in modules/README.org.
|
||||
;; This file controls what Doom modules are enabled and what order they load
|
||||
;; in. Remember to run 'doom sync' after modifying it!
|
||||
|
||||
|
||||
;; NOTE Press 'SPC h d h' (or 'C-h d h' for non-vim users) to access Doom's
|
||||
;; documentation. There you'll find a "Module Index" link where you'll find
|
||||
;; a comprehensive list of Doom's modules and what flags they support.
|
||||
|
||||
;; NOTE Move your cursor over a module's name (or its flags) and press 'K' (or
|
||||
;; 'C-c c k' for non-vim users) to view its documentation. This works on
|
||||
;; flags as well (those symbols that start with a plus).
|
||||
;;
|
||||
;; Alternatively, press 'gd' (or 'C-c c d') on a module to browse its
|
||||
;; directory (for easy access to its source code).
|
||||
|
||||
;; Adding path to mu4e
|
||||
(add-to-list 'load-path "/usr/local/share/emacs/site-lisp/mu4e")
|
||||
|
||||
(doom! :input
|
||||
@@ -29,22 +35,22 @@
|
||||
;;fill-column ; a `fill-column' indicator
|
||||
hl-todo ; highlight TODO/FIXME/NOTE/DEPRECATED/HACK/REVIEW
|
||||
;;hydra
|
||||
indent-guides ; highlighted indent columns
|
||||
indent-guides ; highlighted indent columns
|
||||
;;minimap ; show a map of the code on the side
|
||||
modeline ; snazzy, Atom-inspired modeline, plus API
|
||||
nav-flash ; blink the current line after jumping
|
||||
;;nav-flash ; blink cursor line after big motions
|
||||
neotree ; a project drawer, like NERDTree for vim
|
||||
ophints ; highlight the region an operation acts on
|
||||
(popup ; tame sudden yet inevitable temporary windows
|
||||
+all ; catch all popups that start with an asterix
|
||||
+defaults) ; default popup rules
|
||||
;;pretty-code ; replace bits of code with pretty symbols
|
||||
(popup +defaults) ; tame sudden yet inevitable temporary windows
|
||||
;;pretty-code ; ligatures or substitute text with pretty symbols
|
||||
;;tabs ; an tab bar for Emacs
|
||||
;;treemacs ; a project drawer, like neotree but cooler
|
||||
;;unicode ; extended unicode support for various languages
|
||||
vc-gutter ; vcs diff in the fringe
|
||||
vi-tilde-fringe ; fringe tildes to mark beyond EOB
|
||||
window-select ; visually switch windows
|
||||
;;window-select ; visually switch windows
|
||||
workspaces ; tab emulation, persistence & separate workspaces
|
||||
;;zen ; distraction-free coding or writing
|
||||
|
||||
:editor
|
||||
(evil +everywhere); come to the dark side, we have cookies
|
||||
@@ -53,24 +59,30 @@
|
||||
;;(format +onsave) ; automated prettiness
|
||||
;;god ; run Emacs commands without modifier keys
|
||||
;;lispy ; vim for lisp, for people who don't like vim
|
||||
multiple-cursors ; editing in many places at once
|
||||
;;multiple-cursors ; editing in many places at once
|
||||
;;objed ; text object editing for the innocent
|
||||
;;parinfer ; turn lisp into python, sort of
|
||||
rotate-text ; cycle region at point between text candidates
|
||||
;;rotate-text ; cycle region at point between text candidates
|
||||
snippets ; my elves. They type so I don't have to
|
||||
;;word-wrap ; soft wrapping with language-aware indent
|
||||
|
||||
:emacs
|
||||
dired ; making dired pretty [functional]
|
||||
electric ; smarter, keyword-based electric-indent
|
||||
ibuffer ; interactive buffer management
|
||||
vc ; version-control and Emacs, sitting in a tree
|
||||
dired ; making dired pretty [functional]
|
||||
electric ; smarter, keyword-based electric-indent
|
||||
;;ibuffer ; interactive buffer management
|
||||
undo ; persistent, smarter undo for your inevitable mistakes
|
||||
vc ; version-control and Emacs, sitting in a tree
|
||||
|
||||
:term
|
||||
eshell ; a consistent, cross-platform shell (WIP)
|
||||
;;shell ; a terminal REPL for Emacs
|
||||
;;term ; terminals in Emacs
|
||||
vterm ; another terminals in Emacs
|
||||
eshell ; the elisp shell that works everywhere
|
||||
;;shell ; simple shell REPL for Emacs
|
||||
;;term ; basic terminal emulator for Emacs
|
||||
vterm ; the best terminal emulation in Emacs
|
||||
|
||||
:checkers
|
||||
syntax ; tasing you for every semicolon you forget
|
||||
;;spell ; tasing you for misspelling mispelling
|
||||
;;grammar ; tasing grammar mistake every you make
|
||||
|
||||
:tools
|
||||
;;ansible
|
||||
@@ -80,11 +92,8 @@
|
||||
;;editorconfig ; let someone else argue about tabs vs spaces
|
||||
;;ein ; tame Jupyter notebooks with emacs
|
||||
(eval +overlay) ; run code, run (also, repls)
|
||||
flycheck ; tasing you for every semicolon you forget
|
||||
;;flyspell ; tasing you for misspelling mispelling
|
||||
;;gist ; interacting with github gists
|
||||
(lookup ; helps you navigate your code and documentation
|
||||
+docsets) ; ...or in Dash docsets locally
|
||||
lookup ; navigate your code and its documentation
|
||||
;;lsp
|
||||
;;macos ; MacOS-specific commands
|
||||
magit ; a git porcelain for Emacs
|
||||
@@ -93,69 +102,69 @@
|
||||
;;pdf ; pdf enhancements
|
||||
;;prodigy ; FIXME managing external services & code builders
|
||||
;;rgb ; creating color strings
|
||||
;;taskrunner ; taskrunner for all your projects
|
||||
;;terraform ; infrastructure as code
|
||||
;;tmux ; an API for interacting with tmux
|
||||
;;upload ; map local to remote projects via ssh/ftp
|
||||
|
||||
:lang
|
||||
;;agda ; types of types of types of types...
|
||||
;;assembly ; assembly for fun or debugging
|
||||
;;cc ; C/C++/Obj-C madness
|
||||
;;clojure ; java with a lisp
|
||||
common-lisp ; if you've seen one lisp, you've seen them all
|
||||
;;common-lisp ; if you've seen one lisp, you've seen them all
|
||||
;;coq ; proofs-as-programs
|
||||
;;crystal ; ruby at the speed of c
|
||||
;;csharp ; unity, .NET, and mono shenanigans
|
||||
data ; config/data formats
|
||||
;;data ; config/data formats
|
||||
;;(dart +flutter) ; paint ui and not much else
|
||||
;;elixir ; erlang done right
|
||||
;;elm ; care for a cup of TEA?
|
||||
emacs-lisp ; drown in parentheses
|
||||
emacs-lisp ; drown in parentheses
|
||||
;;erlang ; an elegant language for a more civilized age
|
||||
;;ess ; emacs speaks statistics
|
||||
;;faust ; dsp, but you get to keep your soul
|
||||
;;fsharp ; ML stands for Microsoft's Language
|
||||
;;go ; the hipster dialect
|
||||
(haskell +dante) ; a language that's lazier than I am
|
||||
;;fsharp ; ML stands for Microsoft's Language
|
||||
;;fstar ; (dependent) types and (monadic) effects and Z3
|
||||
;;gdscript ; the language you waited for
|
||||
;;(go +lsp) ; the hipster dialect
|
||||
(haskell +dante) ; a language that's lazier than I am
|
||||
;;hy ; readability of scheme w/ speed of python
|
||||
;;idris ;
|
||||
json ; At least it ain't XML
|
||||
;;(java +meghanada) ; the poster child for carpal tunnel syndrome
|
||||
javascript ; all(hope(abandon(ye(who(enter(here))))))
|
||||
javascript ; all(hope(abandon(ye(who(enter(here))))))
|
||||
;;julia ; a better, faster MATLAB
|
||||
;;kotlin ; a better, slicker Java(Script)
|
||||
latex ; writing papers in Emacs has never been so fun
|
||||
latex ; writing papers in Emacs has never been so fun
|
||||
;;lean
|
||||
;;factor
|
||||
;;ledger ; an accounting system in Emacs
|
||||
lua ; one-based indices? one-based indices
|
||||
markdown ; writing docs for people to ignore
|
||||
lua ; one-based indices? one-based indices
|
||||
markdown ; writing docs for people to ignore
|
||||
;;nim ; python + lisp at the speed of c
|
||||
;;nix ; I hereby declare "nix geht mehr!"
|
||||
;;ocaml ; an objective camel
|
||||
(org ; organize your plain life in plain text
|
||||
+dragndrop ; drag & drop files/images into org buffers
|
||||
+hugo ; use Emacs for hugo blogging
|
||||
+ipython ; ipython/jupyter support for babel
|
||||
+pandoc ; export-with-pandoc support
|
||||
;;+pomodoro ; be fruitful with the tomato technique
|
||||
+present) ; using org-mode for presentations
|
||||
perl ; write code no one else can comprehend
|
||||
php ; perl's insecure younger brother
|
||||
org ; organize your plain life in plain text
|
||||
php ; perl's insecure younger brother
|
||||
;;plantuml ; diagrams for confusing people more
|
||||
;;purescript ; javascript, but functional
|
||||
python ; beautiful is better than ugly
|
||||
python ; beautiful is better than ugly
|
||||
;;qt ; the 'cutest' gui framework ever
|
||||
;;racket ; a DSL for DSLs
|
||||
;;raku ; the artist formerly known as perl6
|
||||
;;rest ; Emacs as a REST client
|
||||
;;rst ; ReST in peace
|
||||
;;ruby ; 1.step {|i| p "Ruby is #{i.even? ? 'love' : 'life'}"}
|
||||
;;(ruby +rails) ; 1.step {|i| p "Ruby is #{i.even? ? 'love' : 'life'}"}
|
||||
;;rust ; Fe2O3.unwrap().unwrap().unwrap().unwrap()
|
||||
;;scala ; java, but good
|
||||
;;scheme ; a fully conniving family of lisps
|
||||
sh ; she sells {ba,z,fi}sh shells on the C xor
|
||||
;;sml
|
||||
;;solidity ; do you need a blockchain? No.
|
||||
;;swift ; who asked for emoji variables?
|
||||
;;terra ; Earth and Moon in alignment for performance.
|
||||
web ; the tubes
|
||||
web ; the tubes
|
||||
yaml ; JSON, but readable
|
||||
|
||||
:email
|
||||
;;(mu4e +gmail)
|
||||
@@ -167,20 +176,7 @@
|
||||
;;irc ; how neckbeards socialize
|
||||
;;(rss +org) ; emacs as an RSS reader
|
||||
;;twitter ; twitter client https://twitter.com/vnought
|
||||
;;write ; emacs for writers (fiction, notes, papers, etc.)
|
||||
|
||||
:config
|
||||
;;literate
|
||||
(default +bindings +smartparens))
|
||||
(custom-set-variables
|
||||
;; custom-set-variables was added by Custom.
|
||||
;; If you edit it by hand, you could mess it up, so be careful.
|
||||
;; Your init file should contain only one such instance.
|
||||
;; If there is more than one, they won't work right.
|
||||
'(org-agenda-files (quote ("~/org-basics.org" "~/Documents/org/orgmode.org"))))
|
||||
(custom-set-faces
|
||||
;; custom-set-faces was added by Custom.
|
||||
;; If you edit it by hand, you could mess it up, so be careful.
|
||||
;; Your init file should contain only one such instance.
|
||||
;; If there is more than one, they won't work right.
|
||||
)
|
||||
|
||||
@@ -1,10 +1,53 @@
|
||||
;; -*- no-byte-compile: t; -*-
|
||||
;;; .doom.d/packages.el
|
||||
;;; $DOOMDIR/packages.el
|
||||
|
||||
;;; Examples:
|
||||
;; (package! some-package)
|
||||
;; (package! another-package :recipe (:host github :repo "username/repo"))
|
||||
;; (package! builtin-package :disable t)
|
||||
;; To install a package with Doom you must declare them here and run 'doom sync'
|
||||
;; on the command line, then restart Emacs for the changes to take effect -- or
|
||||
;; use 'M-x doom/reload'.
|
||||
|
||||
|
||||
;; To install SOME-PACKAGE from MELPA, ELPA or emacsmirror:
|
||||
;(package! some-package)
|
||||
|
||||
;; To install a package directly from a remote git repo, you must specify a
|
||||
;; `:recipe'. You'll find documentation on what `:recipe' accepts here:
|
||||
;; https://github.com/raxod502/straight.el#the-recipe-format
|
||||
;(package! another-package
|
||||
; :recipe (:host github :repo "username/repo"))
|
||||
|
||||
;; If the package you are trying to install does not contain a PACKAGENAME.el
|
||||
;; file, or is located in a subdirectory of the repo, you'll need to specify
|
||||
;; `:files' in the `:recipe':
|
||||
;(package! this-package
|
||||
; :recipe (:host github :repo "username/repo"
|
||||
; :files ("some-file.el" "src/lisp/*.el")))
|
||||
|
||||
;; If you'd like to disable a package included with Doom, you can do so here
|
||||
;; with the `:disable' property:
|
||||
;(package! builtin-package :disable t)
|
||||
|
||||
;; You can override the recipe of a built in package without having to specify
|
||||
;; all the properties for `:recipe'. These will inherit the rest of its recipe
|
||||
;; from Doom or MELPA/ELPA/Emacsmirror:
|
||||
;(package! builtin-package :recipe (:nonrecursive t))
|
||||
;(package! builtin-package-2 :recipe (:repo "myfork/package"))
|
||||
|
||||
;; Specify a `:branch' to install a package from a particular branch or tag.
|
||||
;; This is required for some packages whose default branch isn't 'master' (which
|
||||
;; our package manager can't deal with; see raxod502/straight.el#279)
|
||||
;(package! builtin-package :recipe (:branch "develop"))
|
||||
|
||||
;; Use `:pin' to specify a particular commit to install.
|
||||
;(package! builtin-package :pin "1a2b3c4d5e")
|
||||
|
||||
|
||||
;; Doom's packages are pinned to a specific commit and updated from release to
|
||||
;; release. The `unpin!' macro allows you to unpin single packages...
|
||||
;(unpin! pinned-package)
|
||||
;; ...or multiple packages
|
||||
;(unpin! pinned-package another-pinned-package)
|
||||
;; ...Or *all* packages (NOT RECOMMENDED; will likely break things)
|
||||
;(unpin! t)
|
||||
(package! emojify)
|
||||
(package! elfeed)
|
||||
(package! peep-dired)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Henrik Lissner.
|
||||
Copyright (c) 2016-2020 Henrik Lissner.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
|
||||
@@ -1,178 +1,254 @@
|
||||
<a href="http://doomemacs.org">
|
||||
<img src="https://img.shields.io/github/tag/hlissner/doom-emacs.svg?label=release&color=orange" alt="Made with Doom Emacs">
|
||||
</a>
|
||||
<a href="https://emacs.org">
|
||||
<img src="https://img.shields.io/badge/Made_for-Emacs_26.1+-blueviolet.svg" alt="Made for Emacs 26.1+">
|
||||
</a>
|
||||
<a href="https://github.com/hlissner/doom-emacs/actions">
|
||||
<img src="https://github.com/hlissner/doom-emacs/workflows/CI/badge.svg" alt="Build status: develop">
|
||||
</a>
|
||||
<a href="https://discord.gg/bcZ6P3y">
|
||||
<img src="https://img.shields.io/badge/Discord-blue.svg?logo=discord&label=join" alt="Join our discord server" align="right">
|
||||
</a>
|
||||
<br><br>
|
||||
<div align="center">
|
||||
|
||||
# Doom Emacs
|
||||
|
||||
[Install](#install) • [Documentation] • [FAQ] • [Screenshots] • [Contribute](#contribute)
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
[][Discord]
|
||||
|
||||

|
||||
|
||||
<p align="center">
|
||||
<b><a href="/../../tree/screenshots">Screenshots</a></b>
|
||||
|
|
||||
<b><a href="docs/getting_started.org">Get started</a></b>
|
||||
|
|
||||
<b><a href="docs/contributing.org">Contribute</a></b>
|
||||
|
|
||||
<b><a href="docs/index.org">Documentation</a></b>
|
||||
|
|
||||
<b><a href="docs/faq.org">FAQ</a></b>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
**Quick start**
|
||||
### Table of Contents
|
||||
- [Introduction](#introduction)
|
||||
- [Features](#features)
|
||||
- [Prerequisites](#prerequisites)
|
||||
- [Install](#install)
|
||||
- [Roadmap](#roadmap)
|
||||
- [Getting help](#getting-help)
|
||||
- [Contribute](#contribute)
|
||||
|
||||
```bash
|
||||
git clone https://github.com/hlissner/doom-emacs ~/.emacs.d
|
||||
|
||||
# Introduction
|
||||
<a href="http://ultravioletbat.deviantart.com/art/Yay-Evil-111710573">
|
||||
<img src="https://raw.githubusercontent.com/hlissner/doom-emacs/screenshots/cacochan.png" align="right" />
|
||||
</a>
|
||||
|
||||
> It is a story as old as time. A stubborn, shell-dwelling, and melodramatic
|
||||
> vimmer—envious of the features of modern text editors—spirals into
|
||||
> despair before he succumbs to the [dark side][evil-mode]. This is his config.
|
||||
|
||||
Doom is a configuration framework for [GNU Emacs] tailored for Emacs bankruptcy
|
||||
veterans who want less framework in their frameworks, a modicum of stability
|
||||
(and reproducibility) from their package manager, and the performance of a hand
|
||||
rolled config (or better). It can be a foundation for your own config or a
|
||||
resource for Emacs enthusiasts to learn more about our favorite operating
|
||||
system.
|
||||
|
||||
Its design is guided by these mantras:
|
||||
|
||||
+ **Gotta go fast.** Startup and run-time performance are priorities. Doom goes
|
||||
beyond by modifying packages to be snappier and load lazier.
|
||||
+ **Close to metal.** There's less between you and vanilla Emacs by design.
|
||||
That's less to grok and less to work around when you tinker. Internals ought
|
||||
to be written as if reading them were part of Doom's UX, and it is!
|
||||
+ **Opinionated, but not stubborn.** Doom is about reasonable defaults and
|
||||
curated opinions, but use as little or as much of it as you like.
|
||||
+ **Your system, your rules.** You know better. At least, Doom hopes so! It
|
||||
won't *automatically* install system dependencies (and will force plugins not
|
||||
to either). Rely on `doom doctor` to tell you what's missing.
|
||||
+ **Nix/Guix is a great idea!** The Emacs ecosystem is temperamental. Things
|
||||
break and they break often. Disaster recovery should be a priority! Doom's
|
||||
package management should be declarative and your private config reproducible,
|
||||
and comes with a means to roll back releases and updates (still a WIP).
|
||||
|
||||
Check out [the FAQ][FAQ] for answers to common questions about the project.
|
||||
|
||||
|
||||
# Features
|
||||
- Minimalistic good looks inspired by modern editors.
|
||||
- Curated and sane defaults for many packages, (major) OSes, and Emacs itself.
|
||||
- A modular organizational structure for separating concerns in your config.
|
||||
- A standard library designed to simplify your elisp bike shedding.
|
||||
- A declarative [package management system][package-management] (powered by
|
||||
[straight.el]) with a command line interface. Install packages from anywhere,
|
||||
not just (M)ELPA, and pin them to any commit.
|
||||
- Optional vim emulation powered by [evil-mode], including ports of popular vim
|
||||
plugins like [vim-sneak], [vim-easymotion], [vim-unimpaired] and
|
||||
[more][ported-vim-plugins]!
|
||||
- Opt-in LSP integration for many languages, using [lsp-mode] or [eglot]
|
||||
- Support for *many* programming languages. Includes syntax highlighting,
|
||||
linters/checker integration, inline code evaluation, code completion (where
|
||||
possible), REPLs, documentation lookups, snippets, and more!
|
||||
- Support for *many* tools, like docker, pass, ansible, terraform, and more.
|
||||
- A Spacemacs-esque [keybinding scheme][bindings], centered around leader
|
||||
and localleader prefix keys (<kbd>SPC</kbd> and <kbd>SPC</kbd><kbd>m</kbd> for
|
||||
evil users, <kbd>C-c</kbd> and <kbd>C-c l</kbd> for vanilla users).
|
||||
- A rule-based [popup manager][popup-system] to control how temporary buffers
|
||||
are displayed (and disposed of).
|
||||
- Per-file indentation style detection and [editorconfig] integration. Let
|
||||
someone else can argue about tabs vs **_spaces_**.
|
||||
- Project-management tools and framework-specific minor modes with their own
|
||||
snippets libraries.
|
||||
- Project search (and replace) utilities, powered by [ripgrep] and [ivy] or
|
||||
[helm].
|
||||
- Isolated and persistent workspaces (also substitutes for vim tabs).
|
||||
- Support for Chinese and Japanese input systems.
|
||||
- Save a snapshot of your shell environment to a file for Emacs to load at
|
||||
startup. No more struggling to get Emacs to inherit your `PATH`, among other
|
||||
things.
|
||||
|
||||
|
||||
# Prerequisites
|
||||
+ Git 2.23+
|
||||
+ Emacs 26.1+ (*27 is recommended*) with GNUTLS support
|
||||
+ [ripgrep] 11.0+
|
||||
+ GNU `find`
|
||||
+ *OPTIONAL:* [fd] 7.3.0+ (improves file indexing performance for some commands)
|
||||
|
||||
Doom is comprised of [~150 optional modules][Modules], some of which may have
|
||||
additional dependencies. [Visit their documentation][Modules] or run `bin/doom
|
||||
doctor` to check for any that you may have missed.
|
||||
|
||||
|
||||
# Install
|
||||
``` sh
|
||||
git clone --depth 1 https://github.com/hlissner/doom-emacs ~/.emacs.d
|
||||
~/.emacs.d/bin/doom install
|
||||
```
|
||||
|
||||
**Table of Contents**
|
||||
Then [read our Getting Started guide][getting-started] to be walked through
|
||||
installing, configuring and maintaining Doom Emacs.
|
||||
|
||||
- [What is Doom Emacs](#what-is-doom-emacs)
|
||||
- [Doom's mantras](#dooms-mantras)
|
||||
- [Features](#features)
|
||||
- [Getting Help](#getting-help)
|
||||
- [Community](#community)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
- [Contributing](#contributing)
|
||||
It's a good idea to add `~/.emacs.d/bin` to your `PATH`! Other `bin/doom`
|
||||
commands you should know about:
|
||||
|
||||
# What is Doom Emacs
|
||||
+ `doom sync` to synchronize your private config with Doom by installing missing
|
||||
packages, removing orphaned packages, and regenerating caches. Run this
|
||||
whenever you modify your private `init.el` or `packages.el`, or install/remove
|
||||
an Emacs package through your OS package manager (e.g. mu4e or agda).
|
||||
+ `doom upgrade` to update Doom to the latest release & all installed packages.
|
||||
+ `doom doctor` to diagnose common issues with your system and config.
|
||||
+ `doom env` to dump a snapshot of your shell environment to a file that Doom
|
||||
will load at startup. This allows Emacs to inherit your `PATH`, among other
|
||||
things.
|
||||
+ `doom build` to recompile all installed packages (use this if you up/downgrade
|
||||
Emacs).
|
||||
|
||||
<a href="http://ultravioletbat.deviantart.com/art/Yay-Evil-111710573">
|
||||
<img src="https://github.com/hlissner/doom-emacs/raw/screenshots/cacochan.png" align="right" />
|
||||
</a>
|
||||
|
||||
It is a story as old as time. A stubborn, shell-dwelling, and melodramatic
|
||||
vimmer -- envious of the features of modern text editors -- spirals into despair
|
||||
before succumbing to the [dark side][url:evil-mode]. This is his config.
|
||||
# Roadmap
|
||||
Doom is an active and ongoing project. To make that development more
|
||||
transparent, its roadmap (and other concerns) are published across three github
|
||||
project boards and a newsletter:
|
||||
|
||||
Doom is a configuration for [GNU Emacs](https://www.gnu.org/software/emacs/)
|
||||
designed to make Emacs faster and easier to customize. It can serve as framework
|
||||
for your own configuration or a resource for fellow Emacs enthusiasts who want
|
||||
to learn more about our favorite OS.
|
||||
+ [Development Roadmap](https://github.com/hlissner/doom-emacs/projects/3):
|
||||
roughly outlines our goals between release milestones and their progress.
|
||||
+ [Plugins under review](https://github.com/hlissner/doom-emacs/projects/2):
|
||||
lists plugins we are watching and considering for inclusion, and what their
|
||||
status for inclusion is. Please consult this list before requesting new
|
||||
packages/features.
|
||||
+ [Upstream bugs](https://github.com/hlissner/doom-emacs/projects/5): lists
|
||||
issues that originate from elsewhere, and whether or not we have local
|
||||
workarounds or temporary fixes for them.
|
||||
+ ~~Doom's newsletter~~ (not finished) will contain changelogs in between
|
||||
releases.
|
||||
|
||||
|
||||
## Doom's mantras
|
||||
# Getting help
|
||||
Emacs is no journey of a mere thousand miles. You _will_ run into problems and
|
||||
mysterious errors. When you do, here are some places you can look for help:
|
||||
|
||||
- **Gotta go fast.** Startup and run-time performance are high priorities.
|
||||
Expensive functionality (built-in or in plugins) is modified and optimized
|
||||
toward this end, otherwise, they must be opt-in.
|
||||
- **Close to metal.** There's less between you and vanilla Emacs, by design.
|
||||
There's less to grok. Modules should be syntactically sweet and backend logic
|
||||
explicit and abstraction-light. The code itself ought to be designed as if
|
||||
grokking it were part of the user experience; and it is!
|
||||
- **Opinionated, but not stubborn.** Doom is a bundle of reasonable defaults
|
||||
and curated opinions, but you aren't stuck with it. Use as little or as much
|
||||
of it as you like. Use it as-is as a complete Emacs distribution; disable
|
||||
everything and use it as a baseline for your own; or anywhere in between.
|
||||
- **Your system, your rules.** There are more ways to set up your programming
|
||||
environment than there are dislikes on Youtube Rewind '18, so Doom and its
|
||||
plugins promise not to *automatically* (and definitely not *silently*) install
|
||||
system dependencies. This means fonts, packages and programs. `doom doctor`
|
||||
will tell you what's missing though!
|
||||
+ [Our documentation][documentation] covers many use cases.
|
||||
+ [The Configuration section][configuration] covers how to configure Doom and
|
||||
its packages.
|
||||
+ [The Package Management section][package-management] covers how to install
|
||||
and disable packages.
|
||||
+ [This section][bin/doom] explains the `bin/doom` script's most important
|
||||
commands.
|
||||
+ [This section][common-mistakes] lists some common configuration mistakes new
|
||||
users make, when migrating a config from another distro or their own.
|
||||
+ [This answer][change-theme] shows you how to add your own themes to your
|
||||
private config.
|
||||
+ [This answer][change-font] shows you how to change the default font.
|
||||
+ Your issue may be documented in the [FAQ].
|
||||
+ With Emacs built-in help system documentation is a keystroke away:
|
||||
+ For functions: <kbd>SPC h f</kbd> or <kbd>C-h f</kbd>
|
||||
+ For variables: <kbd>SPC h v</kbd> or <kbd>C-h v</kbd>
|
||||
+ For a keybind: <kbd>SPC h k</kbd> or <kbd>C-h k</kbd>
|
||||
+ To search available keybinds: <kbd>SPC h b b</kbd> or <kbd>C-h b b</kbd>
|
||||
+ Run `bin/doom doctor` to detect common issues with your development
|
||||
environment and private config.
|
||||
+ Check out the [FAQ], in case your question has already been answered.
|
||||
+ Search [Doom's issue tracker](/issues) in case your issue was already
|
||||
reported.
|
||||
+ Hop on [our Discord server][discord]; it's active and friendly! Keep an eye on
|
||||
the #announcements channel, where I announce breaking updates and releases.
|
||||
|
||||
## Features
|
||||
|
||||
- A curated set of sane defaults for all packages, all (major) OSes, and Emacs
|
||||
itself.
|
||||
- Support for *many* programming languages. Too many to list. Includes syntax
|
||||
highlighting, linters/checker integration, inline code evaluation, code
|
||||
completion (where possible), REPLs, documentation lookups, snippets, and more!
|
||||
- Support for *many* tools, like docker, pass, ansible, terraform, and more.
|
||||
- Minimalistic good looks inspired by modern editors.
|
||||
- A modular architecture for a more organized Emacs configuration.
|
||||
- A custom elisp library to help you simplify your config.
|
||||
- A declarative [package management system][doom:packages] (powered by
|
||||
[straight.el][url:straight]) with a command line interface. Install packages
|
||||
from anywhere, not just (M)ELPA.
|
||||
- Vim-emulation powered by [evil-mode][url:evil-mode], including ports of
|
||||
popular vim plugins and functionality.
|
||||
- A Spacemacs-esque [keybinding scheme][doom:bindings], centered around leader
|
||||
and localleader prefix keys (<kbd>SPC</kbd> and <kbd>SPC</kbd><kbd>m</kbd>, by
|
||||
default).
|
||||
- A rule-based [popup management system][doom:popups] that dictates how
|
||||
temporary or disposable buffers are displayed (and disposed of).
|
||||
- Automatic indentation detection and [editorconfig][url:editorconfig]
|
||||
integration. Let someone else argue about tabs vs **\_\***spaces**\*\_**.
|
||||
- Project-management tools and framework-specific minor modes with their own
|
||||
snippets libraries.
|
||||
- Project search (and replace) utilities, powered by
|
||||
[the_silver_searcher][url:the_silver_searcher] or [ripgrep][url:ripgrep].
|
||||
- Isolated and persistent workspaces (also substitutes for vim tabs).
|
||||
- An environment variables file generator and loader, so that Emacs can
|
||||
perfectly inherit your shell configuration.
|
||||
- Everything is optional!
|
||||
# Contribute
|
||||
[](http://makeapullrequest.com)
|
||||
[](https://github.com/bbatsov/emacs-lisp-style-guide)
|
||||
[][liberapay]
|
||||
[][paypal]
|
||||
|
||||
# Getting Help
|
||||
Doom is a labor of love and incurable madness, but I'm only one guy. Doom
|
||||
wouldn't be where it is today without your help. I welcome contributions of any
|
||||
kind!
|
||||
|
||||
## Community
|
||||
+ I :heart: pull requests and bug reports (see the [Contributing
|
||||
Guidelines][contribute])!
|
||||
+ Don't hesitate to [tell me my Elisp-fu
|
||||
sucks](https://github.com/hlissner/doom-emacs/issues/new), but please tell me
|
||||
why.
|
||||
+ Hop on [our Discord server][Discord] and say hi! Help others, hang out or talk
|
||||
to me about Emacs, gamedev, programming, physics, pixel art, anime, gaming --
|
||||
anything you like. Nourish this lonely soul.
|
||||
+ If you'd like to support my work financially, buy me a drink through
|
||||
[liberapay] or [paypal]. My work contends with studies, adventures in indie
|
||||
gamedev and freelance work. Donations help me allocate more time to my Emacs
|
||||
and OSS capers.
|
||||
|
||||
[](https://sourcerer.io/fame/hlissner/hlissner/doom-emacs/links/0)
|
||||
[](https://sourcerer.io/fame/hlissner/hlissner/doom-emacs/links/1)
|
||||
[](https://sourcerer.io/fame/hlissner/hlissner/doom-emacs/links/2)
|
||||
[](https://sourcerer.io/fame/hlissner/hlissner/doom-emacs/links/3)
|
||||
[](https://sourcerer.io/fame/hlissner/hlissner/doom-emacs/links/4)
|
||||
[](https://sourcerer.io/fame/hlissner/hlissner/doom-emacs/links/5)
|
||||
[](https://sourcerer.io/fame/hlissner/hlissner/doom-emacs/links/6)
|
||||
[](https://sourcerer.io/fame/hlissner/hlissner/doom-emacs/links/7)
|
||||
|
||||
We have [a Discord server][url:discord]! Hop on and say hi!
|
||||
|
||||
## Troubleshooting
|
||||
[contribute]: docs/contributing.org
|
||||
[discord]: https://discord.gg/qvGgnVx
|
||||
[documentation]: docs/index.org
|
||||
[faq]: docs/faq.org
|
||||
[getting-started]: docs/getting_started.org
|
||||
[install]: docs/getting_started.org#install
|
||||
[backtrace]: docs/getting_started.org#how-to-extract-a-backtrace-from-an-error
|
||||
[configuration]: docs/getting_started.org#configuring-doom
|
||||
[package-management]: docs/getting_started.org#package-management
|
||||
[bin/doom]: docs/getting_started.org#the-bindoom-utility
|
||||
[common-mistakes]: docs/getting_started.org#common-mistakes-when-configuring-doom-emacs
|
||||
[change-theme]: docs/faq.org#how-do-i-change-the-theme
|
||||
[change-font]: docs/faq.org#how-do-i-change-the-fonts
|
||||
[modules]: docs/modules.org
|
||||
[popup-system]: modules/ui/popup/README.org
|
||||
[screenshots]: #screenshots
|
||||
|
||||
Encountered strange behavior or an error? Here are some things to try before you
|
||||
shoot off that bug report:
|
||||
[bindings]: modules/config/default/+evil-bindings.el
|
||||
[editorconfig]: http://editorconfig.org/
|
||||
[evil-mode]: https://github.com/emacs-evil/evil
|
||||
[fd]: https://github.com/sharkdp/fd
|
||||
[gnu emacs]: https://www.gnu.org/software/emacs/
|
||||
[helm]: https://github.com/emacs-helm/helm
|
||||
[ivy]: https://github.com/abo-abo/swiper
|
||||
[lsp-mode]: https://github.com/emacs-lsp/lsp-mode
|
||||
[eglot]: https://github.com/joaotavora/eglot
|
||||
[nix]: https://nixos.org
|
||||
[ported-vim-plugins]: modules/editor/evil/README.org#ported-vim-plugins
|
||||
[ripgrep]: https://github.com/BurntSushi/ripgrep
|
||||
[straight.el]: https://github.com/raxod502/straight.el
|
||||
[vim-easymotion]: https://github.com/easymotion/vim-easymotion
|
||||
[vim-lion]: https://github.com/tommcdo/vim-lion
|
||||
[vim-sneak]: https://github.com/justinmk/vim-sneak
|
||||
[vim-unimpaired]: https://github.com/tpope/vim-unimpaired
|
||||
|
||||
- Run `bin/doom refresh`. This ensures Doom is properly set up and its autoloads
|
||||
files are up-to-date.
|
||||
- If you have byte-compiled your config (with `bin/doom compile`), see if
|
||||
`bin/doom clean` makes the issue go away. Never debug issues with a
|
||||
byte-compiled config, it will make your job harder.
|
||||
- Run `bin/doom doctor` to detect common issues in your development environment.
|
||||
- Search Doom's issue tracker for mention of any error messages you've received.
|
||||
- [Visit our FAQ][docs:faq] to see if your issue is listed.
|
||||
|
||||
If all else fails, [file that bug report][github:new-issue]! Please include the
|
||||
behavior you've observed, the behavior you expected, and any error messages or
|
||||
warnings logged to the \*Messages\* buffer (can be opened with <kbd>SPC h
|
||||
e</kbd> or `M-x view-echo-area-messages`).
|
||||
|
||||
It's a great help if you included a backtrace with errors, i.e. `M-x
|
||||
toggle-debug-on-error` then recreating the error(s).
|
||||
|
||||
## Contributing
|
||||
|
||||
Doom (and my Emacs work in general) is a labor of love and incurable madness,
|
||||
done on my spare time. If you'd like to support my work, there are many things
|
||||
you can do to help; I welcome any contribution!
|
||||
|
||||
- I love pull requests and bug reports. Check out the [Contributing
|
||||
Guidelines][docs:contributing] to find out how you can help out.
|
||||
- I welcome Elisp pointers! Don't hesitate to [tell me my Elisp-fu
|
||||
sucks][github:new-issue] (but please tell me why).
|
||||
- Hop on [our Discord server][url:discord] and say hi! Help others out, hang out
|
||||
or talk to me about Emacs, or gamedev, or programming, machine learning,
|
||||
physics, pixel art, anime, gaming -- anything you like. Nourish this lonely
|
||||
soul!
|
||||
- If you'd like to support my work financially, consider buying me a drink
|
||||
through [liberapay][url:liberapay] or [paypal][url:paypal]. Donations are a
|
||||
great help. My work here contends with studies, ventures in indie gamedev, and
|
||||
my freelance work.
|
||||
|
||||
[docs:wiki]: docs/index.org
|
||||
[docs:wiki-quickstart]: docs/getting_started.org
|
||||
[docs:wiki-modules]: docs/index.org#Module%20List
|
||||
[docs:wiki-customization]: docs/getting_started.org#Customize
|
||||
[docs:contributing]: docs/contributing.org
|
||||
[docs:faq]: docs/faq.org
|
||||
[github:new-issue]: https://github.com/hlissner/doom-emacs/issues/new
|
||||
[doom:bindings]: modules/config/default/+evil-bindings.el
|
||||
[doom:packages]: core/autoload/packages.el
|
||||
[doom:popups]: modules/ui/popup/README.org
|
||||
[url:discord]: https://discord.gg/bcZ6P3y
|
||||
[url:liberapay]: https://liberapay.com/hlissner/donate
|
||||
[url:paypal]: https://paypal.me/henriklissner/10
|
||||
[url:editorconfig]: http://editorconfig.org/
|
||||
[url:evil-mode]: https://github.com/emacs-evil/evil
|
||||
[url:ripgrep]: https://github.com/BurntSushi/ripgrep
|
||||
[url:the_silver_searcher]: https://github.com/ggreer/the_silver_searcher
|
||||
[url:straight]: https://github.com/raxod502/straight.el
|
||||
[liberapay]: https://liberapay.com/hlissner/donate
|
||||
[paypal]: https://paypal.me/henriklissner/10
|
||||
|
||||
@@ -1,30 +1,45 @@
|
||||
#!/usr/bin/env sh
|
||||
:; ( echo "$EMACS" | grep -q "term" ) && EMACS=emacs || EMACS=${EMACS:-emacs} # -*-emacs-lisp-*-
|
||||
:; command -v $EMACS >/dev/null || { >&2 echo "Can't find emacs in your PATH"; exit 1; }
|
||||
:; VERSION=$($EMACS --version | head -n1)
|
||||
:; case "$VERSION" in *\ 2[0-5].[0-9]) echo "Detected Emacs $VERSION"; echo "Doom only supports Emacs 26.1 and newer"; echo; exit 2 ;; esac
|
||||
:; DOOMBASE="$(dirname "$0")/.."
|
||||
:; [ "$1" = -d ] || [ "$1" = --debug ] && { shift; export DEBUG=1; }
|
||||
:; [ "$1" = run ] && { cd "$DOOMBASE"; shift; exec $EMACS -q --no-splash -l bin/doom "$@"; exit 0; }
|
||||
:; exec $EMACS --script "$0" -- "$@"
|
||||
:; exit 0
|
||||
:; _VERSION=$($EMACS --version | head -n1)
|
||||
:; case "$_VERSION" in *\ 2[0-5].[0-9]) echo "Detected Emacs $_VERSION"; echo "Doom only supports Emacs 26.1 and newer"; echo; exit 2 ;; esac
|
||||
:; _DOOMBASE="${EMACSDIR:-$(dirname "$0")/..}"
|
||||
:; _DOOMPOST="$_DOOMBASE/.local/.doom.sh"
|
||||
:; rm -f "$_DOOMPOST"
|
||||
:; $EMACS --no-site-file --script "$0" -- "$@"
|
||||
:; CODE=$?
|
||||
:; [ -x "$_DOOMPOST" ] && PATH="$_DOOMBASE/bin:$PATH" "$_DOOMPOST" "$0" "$@"
|
||||
:; exit $CODE
|
||||
|
||||
;; CLI ops tend to eat a lot of memory. To speed it up, stave off the GC, but
|
||||
;; not to `most-positive-fixnum' like we do in init.el; that's too high -- we
|
||||
;; don't want to intentionally leak memory.
|
||||
(setq gc-cons-threshold 134217728) ; 128mb
|
||||
|
||||
(let* ((loaddir (file-name-directory (file-truename load-file-name)))
|
||||
(emacsdir (getenv "EMACSDIR"))
|
||||
(user-emacs-directory (or emacsdir (expand-file-name "../" loaddir)))
|
||||
(load-prefer-newer t))
|
||||
(user-emacs-directory
|
||||
(abbreviate-file-name
|
||||
(if emacsdir
|
||||
(file-name-as-directory emacsdir)
|
||||
(expand-file-name "../" loaddir)))))
|
||||
|
||||
(push (expand-file-name "core" user-emacs-directory) load-path)
|
||||
(require 'core)
|
||||
;;
|
||||
(load (expand-file-name "core/core.el" user-emacs-directory) nil t)
|
||||
|
||||
;; HACK Load `cl' and site files manually so we can stop them from polluting
|
||||
;; CLI logs with deprecation and file load messages.
|
||||
(quiet! (when (> emacs-major-version 26)
|
||||
(require 'cl))
|
||||
(load "site-start" t t))
|
||||
|
||||
(doom-log "Initializing Doom CLI")
|
||||
(require 'core-cli)
|
||||
|
||||
(defcli! :main
|
||||
((help-p ["-h" "--help"] "Same as help command")
|
||||
(debug-p ["-d" "--debug"] "Turns on doom-debug-mode (and debug-on-error)")
|
||||
(debug-p ["-d" "--debug"] "Turns on doom-debug-p (and debug-on-error)")
|
||||
(yes-p ["-y" "--yes"] "Auto-accept all confirmation prompts")
|
||||
(emacsdir ["--emacsdir" dir] "Use the emacs config at DIR (e.g. ~/.emacs.d)")
|
||||
(doomdir ["--doomdir" dir] "Use the private module at DIR (e.g. ~/.doom.d)")
|
||||
(localdir ["--localdir" dir] "Use DIR as your local storage directory")
|
||||
&optional command &rest args)
|
||||
"A command line interface for managing Doom Emacs.
|
||||
|
||||
@@ -33,74 +48,80 @@ Includes package management, diagnostics, unit tests, and byte-compilation.
|
||||
This tool also makes it trivial to launch Emacs out of a different folder or
|
||||
with a different private module."
|
||||
:bare t
|
||||
(when emacsdir
|
||||
(setq user-emacs-directory (file-name-as-directory emacsdir))
|
||||
(print! (info "EMACSDIR=%s") localdir))
|
||||
(when doomdir
|
||||
(setenv "DOOMDIR" doomdir)
|
||||
(print! (info "DOOMDIR=%s") localdir))
|
||||
(when localdir
|
||||
(setenv "DOOMLOCALDIR" localdir)
|
||||
(print! (info "DOOMLOCALDIR=%s") localdir))
|
||||
(when debug-p
|
||||
(setenv "DEBUG" "1")
|
||||
(setq doom-debug-mode t)
|
||||
(setq doom-debug-p t)
|
||||
(print! (info "Debug mode on")))
|
||||
(when yes-p
|
||||
(setenv "YES" "1")
|
||||
(setq doom-auto-accept t)
|
||||
(print! (info "Auto-yes on")))
|
||||
(when help-p
|
||||
(push command args)
|
||||
(when command
|
||||
(push command args))
|
||||
(setq command "help"))
|
||||
|
||||
;; Reload core in case any of the directories were changed.
|
||||
(when (or emacsdir doomdir localdir)
|
||||
(load! "core/core.el" user-emacs-directory))
|
||||
(when (equal (user-real-uid) 0)
|
||||
(print!
|
||||
(concat "WARNING: This script is running as root. This likely wasn't intentional, and\n"
|
||||
"is unnecessary to use this script. This will cause file permissions errors\n"
|
||||
"later if you use this Doom installation on a non-root account.\n"))
|
||||
(unless (or doom-auto-accept (y-or-n-p "Continue anyway?"))
|
||||
(user-error "Aborted")))
|
||||
|
||||
(cond ((not noninteractive)
|
||||
(print! "Doom launched out of %s (test mode)" (path user-emacs-directory))
|
||||
(load! "init.el" user-emacs-directory)
|
||||
(doom-run-all-startup-hooks-h))
|
||||
;; Load any the user's private init.el or any cli.el files in modules. This
|
||||
;; gives the user (and modules) an opportunity to define their own CLI
|
||||
;; commands, or to customize the CLI to better suit them.
|
||||
(load! doom-module-init-file doom-private-dir t)
|
||||
(maphash (doom-module-loader doom-cli-file) doom-modules)
|
||||
(load! doom-cli-file doom-private-dir t)
|
||||
(run-hooks 'doom-cli-pre-hook)
|
||||
|
||||
((null command)
|
||||
(doom-cli-execute "help"))
|
||||
|
||||
((condition-case e
|
||||
(let ((start-time (current-time)))
|
||||
(and (doom-cli-execute command args)
|
||||
(print! (success "Finished! (%.4fs)")
|
||||
(float-time
|
||||
(time-subtract (current-time)
|
||||
start-time)))))
|
||||
(user-error
|
||||
(print! (error "%s\n") (error-message-string e))
|
||||
(print! (yellow "See 'doom help %s' for documentation on this command.") (car args))
|
||||
(error "")) ; Ensure non-zero exit code
|
||||
((debug error)
|
||||
(print! (error "There was an unexpected error:"))
|
||||
(print-group!
|
||||
(print! "%s %s" (bold "Type:") (car e))
|
||||
(print! (bold "Message:"))
|
||||
(print-group!
|
||||
(print! "%s" (get (car e) 'error-message)))
|
||||
(print! (bold "Data:"))
|
||||
(print-group!
|
||||
(if (cdr e)
|
||||
(dolist (item (cdr e))
|
||||
(print! "%S" item))
|
||||
(print! "n/a"))))
|
||||
(unless debug-on-error
|
||||
(terpri)
|
||||
(print!
|
||||
(concat "Run the command again with the -d (or --debug) switch to enable debug\n"
|
||||
"mode and (hopefully) generate a backtrace from this error:\n"
|
||||
"\n %s\n\n"
|
||||
"If you file a bug report, please include it!")
|
||||
(string-join (append (list (file-name-nondirectory load-file-name) "-d" command)
|
||||
args)
|
||||
" "))
|
||||
(error ""))))))) ; Ensure non-zero exit code
|
||||
(let (print-level print-gensym print-length)
|
||||
(condition-case e
|
||||
(if (null command)
|
||||
(doom-cli-execute "help")
|
||||
(let ((start-time (current-time)))
|
||||
(and (doom-cli-execute command args)
|
||||
(progn (run-hooks 'doom-cli-post-hook) t)
|
||||
(print! (success "Finished! (%.4fs)")
|
||||
(float-time
|
||||
(time-subtract (current-time)
|
||||
start-time))))))
|
||||
(user-error
|
||||
(print! (error "%s\n") (error-message-string e))
|
||||
(print! (yellow "See 'doom help %s' for documentation on this command.") (car args))
|
||||
(error "")) ; Ensure non-zero exit code
|
||||
((debug error)
|
||||
(print! (error "There was an unexpected error:"))
|
||||
(print-group!
|
||||
(print! "%s %s" (bold "Type:") (car e))
|
||||
(print! (bold "Message:"))
|
||||
(print-group!
|
||||
(print! "%s" (get (car e) 'error-message)))
|
||||
(print! (bold "Data:"))
|
||||
(print-group!
|
||||
(if (cdr e)
|
||||
(dolist (item (cdr e))
|
||||
(print! "%S" item))
|
||||
(print! "n/a")))
|
||||
(when (and (bound-and-true-p straight-process-buffer)
|
||||
(string-match-p (regexp-quote straight-process-buffer)
|
||||
(error-message-string e)))
|
||||
(print! (bold "Straight output:"))
|
||||
(print-group! (print! "%s" (straight--process-get-output)))))
|
||||
(unless debug-on-error
|
||||
(terpri)
|
||||
(print!
|
||||
(concat "Run the command again with the -d (or --debug) switch to enable debug\n"
|
||||
"mode and (hopefully) generate a backtrace from this error:\n"
|
||||
"\n %s\n\n"
|
||||
"If you file a bug report, please include it!")
|
||||
(string-join (append (list (file-name-nondirectory load-file-name) "-d" command)
|
||||
args)
|
||||
" "))
|
||||
;; Ensure non-zero exit code
|
||||
(error ""))))))
|
||||
|
||||
(doom-cli-execute :main (cdr (member "--" argv)))
|
||||
(setq argv nil))
|
||||
|
||||
@@ -14,7 +14,7 @@ cleanup() {
|
||||
}
|
||||
|
||||
# If emacs isn't running, we start a temporary daemon, solely for this window.
|
||||
if ! emacsclient -e nil; then
|
||||
if ! emacsclient --suppress-output --eval nil; then
|
||||
emacs --daemon
|
||||
trap cleanup EXIT INT TERM
|
||||
daemon=1
|
||||
@@ -22,8 +22,8 @@ fi
|
||||
|
||||
# org-capture key mapped to argument flags
|
||||
# keys=$(emacsclient -e "(+org-capture-available-keys)" | cut -d '"' -f2)
|
||||
while getopts hk opt; do
|
||||
key="\"$opt\""
|
||||
while getopts "hk:" opt; do
|
||||
key="\"$OPTARG\""
|
||||
break
|
||||
done
|
||||
shift $((OPTIND-1))
|
||||
@@ -32,7 +32,7 @@ shift $((OPTIND-1))
|
||||
|
||||
if [ $daemon ]; then
|
||||
emacsclient -a "" \
|
||||
-c -F '((name . "org-capture") (width . 70) (height . 25) (transient . t))' \
|
||||
-c -F '((name . "doom-capture") (width . 70) (height . 25) (transient . t))' \
|
||||
-e "(+org-capture/open-frame \"$str\" ${key:-nil})"
|
||||
else
|
||||
# Non-daemon servers flicker a lot if frames are created from terminal, so we
|
||||
|
||||
@@ -36,7 +36,7 @@ it if it doesn't exist).")
|
||||
|
||||
|
||||
;;
|
||||
;; Functions
|
||||
;;; Functions
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-buffer-frame-predicate (buf)
|
||||
@@ -139,6 +139,8 @@ If BUFFER-OR-NAME is omitted or nil, the current buffer is tested."
|
||||
(stringp buffer-or-name)
|
||||
(signal 'wrong-type-argument (list '(bufferp stringp) buffer-or-name)))
|
||||
(when-let (buf (get-buffer buffer-or-name))
|
||||
(when-let (basebuf (buffer-base-buffer buf))
|
||||
(setq buf basebuf))
|
||||
(and (buffer-live-p buf)
|
||||
(not (doom-temp-buffer-p buf))
|
||||
(or (buffer-local-value 'doom-real-buffer-p buf)
|
||||
@@ -195,7 +197,9 @@ If DERIVED-P, test with `derived-mode-p', otherwise use `eq'."
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-set-buffer-real (buffer flag)
|
||||
"Forcibly mark BUFFER as FLAG (non-nil = real)."
|
||||
"Forcibly mark BUFFER as FLAG (non-nil = real).
|
||||
|
||||
See `doom-real-buffer-p' for an explanation for real buffers."
|
||||
(with-current-buffer buffer
|
||||
(setq doom-real-buffer-p flag)))
|
||||
|
||||
@@ -251,7 +255,9 @@ regex PATTERN. Returns the number of killed buffers."
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-mark-buffer-as-real-h ()
|
||||
"Hook function that marks the current buffer as real."
|
||||
"Hook function that marks the current buffer as real.
|
||||
|
||||
See `doom-real-buffer-p' for an explanation for real buffers."
|
||||
(doom-set-buffer-real (current-buffer) t))
|
||||
|
||||
|
||||
@@ -272,6 +278,12 @@ If DONT-SAVE, don't prompt to save modified buffers (discarding their changes)."
|
||||
(set-buffer-modified-p nil)))
|
||||
(doom-kill-buffer-fixup-windows buffer))
|
||||
|
||||
|
||||
(defun doom--message-or-count (interactive message count)
|
||||
(if interactive
|
||||
(message message count)
|
||||
count))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/kill-all-buffers (&optional buffer-list interactive)
|
||||
"Kill all buffers and closes their windows.
|
||||
@@ -286,14 +298,14 @@ belong to the current project."
|
||||
(if (null buffer-list)
|
||||
(message "No buffers to kill")
|
||||
(save-some-buffers)
|
||||
(delete-other-windows)
|
||||
(when (memq (current-buffer) buffer-list)
|
||||
(switch-to-buffer (doom-fallback-buffer)))
|
||||
(mapc #'doom-kill-buffer-and-windows buffer-list)
|
||||
(delete-other-windows)
|
||||
(when interactive
|
||||
(message "Killed %s buffers"
|
||||
(- (length buffer-list)
|
||||
(length (cl-remove-if-not #'buffer-live-p buffer-list)))))))
|
||||
(mapc #'kill-buffer buffer-list)
|
||||
(doom--message-or-count
|
||||
interactive "Killed %d buffers"
|
||||
(- (length buffer-list)
|
||||
(length (cl-remove-if-not #'buffer-live-p buffer-list))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/kill-other-buffers (&optional buffer-list interactive)
|
||||
@@ -308,10 +320,10 @@ project."
|
||||
(doom-buffer-list)))
|
||||
t))
|
||||
(mapc #'doom-kill-buffer-and-windows buffer-list)
|
||||
(when interactive
|
||||
(message "Killed %s buffers"
|
||||
(- (length buffer-list)
|
||||
(length (cl-remove-if-not #'buffer-live-p buffer-list))))))
|
||||
(doom--message-or-count
|
||||
interactive "Killed %d other buffers"
|
||||
(- (length buffer-list)
|
||||
(length (cl-remove-if-not #'buffer-live-p buffer-list)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/kill-matching-buffers (pattern &optional buffer-list interactive)
|
||||
@@ -341,10 +353,10 @@ current project."
|
||||
(if current-prefix-arg (doom-project-buffer-list)))
|
||||
t))
|
||||
(mapc #'kill-buffer buffer-list)
|
||||
(when interactive
|
||||
(message "Killed %s buried buffers"
|
||||
(- (length buffer-list)
|
||||
(length (cl-remove-if-not #'buffer-live-p buffer-list))))))
|
||||
(doom--message-or-count
|
||||
interactive "Killed %d buried buffers"
|
||||
(- (length buffer-list)
|
||||
(length (cl-remove-if-not #'buffer-live-p buffer-list)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/kill-project-buffers (project &optional interactive)
|
||||
@@ -362,9 +374,9 @@ current project."
|
||||
nil)
|
||||
t))
|
||||
(when project
|
||||
(let ((buffers (doom-project-buffer-list project)))
|
||||
(doom-kill-buffers-fixup-windows buffers)
|
||||
(when interactive
|
||||
(message "Killed %d buffer(s)"
|
||||
(- (length buffers)
|
||||
(length (cl-remove-if-not #'buffer-live-p buffers))))))))
|
||||
(let ((buffer-list (doom-project-buffer-list project)))
|
||||
(doom-kill-buffers-fixup-windows buffer-list)
|
||||
(doom--message-or-count
|
||||
interactive "Killed %d project buffers"
|
||||
(- (length buffer-list)
|
||||
(length (cl-remove-if-not #'buffer-live-p buffer-list)))))))
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
;;; core/autoload/cache.el -*- lexical-binding: t; -*-
|
||||
|
||||
;; This little library thinly wraps around persistent-soft (which is a pcache
|
||||
;; wrapper, how about that). It has three purposes:
|
||||
;;
|
||||
;; + To encapsulate the cache backend (persistent-soft/pcache in this case), in
|
||||
;; case it needs to change.
|
||||
;; + To provide `doom-cache-persist': a mechanism for easily persisting
|
||||
;; variables across Emacs sessions.
|
||||
;; + To lazy-load persistent-soft until it is really needed.
|
||||
;;
|
||||
;; Like persistent-soft, caches assume a 2-tier structure, where all caches are
|
||||
;; namespaced by location.
|
||||
|
||||
(defvar doom-cache-alists '(t)
|
||||
"An alist of alists, containing lists of variables for the doom cache library
|
||||
to persist across Emacs sessions.")
|
||||
|
||||
(defvar doom-cache-location 'doom
|
||||
"The default location for cache files. This symbol is translated into a file
|
||||
name under `pcache-directory' (by default a subdirectory under
|
||||
`doom-cache-dir'). One file may contain multiple cache entries.")
|
||||
|
||||
(defun doom-save-persistent-cache-h ()
|
||||
"Hook to run when an Emacs session is killed. Saves all persisted variables
|
||||
listed in `doom-cache-alists' to files."
|
||||
(dolist (alist (butlast doom-cache-alists 1))
|
||||
(cl-loop with key = (car alist)
|
||||
for var in (cdr alist)
|
||||
if (symbol-value var)
|
||||
do (doom-cache-set var it nil key))))
|
||||
(add-hook 'kill-emacs-hook #'doom-save-persistent-cache-h)
|
||||
|
||||
|
||||
;;
|
||||
;; Library
|
||||
|
||||
;;;###autoload
|
||||
(defmacro with-cache! (location &rest body)
|
||||
"Runs BODY with a different default `doom-cache-location'."
|
||||
(declare (indent defun))
|
||||
`(let ((doom-cache-location ',location))
|
||||
,@body))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-cache-persist (location variables)
|
||||
"Persist VARIABLES (list of symbols) in LOCATION (symbol).
|
||||
|
||||
This populates these variables with cached values, if one exists, and saves them
|
||||
to file when Emacs quits.
|
||||
|
||||
Warning: this is incompatible with buffer-local variables."
|
||||
(dolist (var variables)
|
||||
(when (doom-cache-exists var location)
|
||||
(set var (doom-cache-get var location))))
|
||||
(setf (alist-get location doom-cache-alists)
|
||||
(append variables (cdr (assq location doom-cache-alists)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-cache-desist (location &optional variables)
|
||||
"Unregisters VARIABLES (list of symbols) in LOCATION (symbol) from
|
||||
`doom-cache-alists', thus preventing them from being saved between sessions.
|
||||
Does not affect the actual variables themselves or their values."
|
||||
(if variables
|
||||
(setf (alist-get location doom-cache-alists)
|
||||
(cl-set-difference (cdr (assq location doom-cache-alists))
|
||||
variables))
|
||||
(delq (assq location doom-cache-alists)
|
||||
doom-cache-alists)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-cache-get (key &optional location)
|
||||
"Retrieve KEY from LOCATION (defaults to `doom-cache-location'), if it exists
|
||||
and hasn't expired."
|
||||
(persistent-soft-fetch
|
||||
key (symbol-name (or location doom-cache-location))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-cache-set (key value &optional ttl location)
|
||||
"Set KEY to VALUE in the cache. TTL is the time (in seconds) until this cache
|
||||
entry expires. LOCATION is the super-key to store this cache item under; the
|
||||
default is `doom-cache-location'. "
|
||||
(persistent-soft-store
|
||||
key value
|
||||
(symbol-name (or location doom-cache-location)) ttl))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-cache-exists (key &optional location)
|
||||
"Returns t if KEY exists at LOCATION (defaults to `doom-cache-location')."
|
||||
(persistent-soft-exists-p key (or location doom-cache-location)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-cache-clear (&optional location)
|
||||
"Clear a cache LOCATION (defaults to `doom-cache-location')."
|
||||
(persistent-soft-flush (or location doom-cache-location)))
|
||||
@@ -1,45 +0,0 @@
|
||||
;;; core/autoload/cli.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;
|
||||
;;; Library
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-call-process (command &rest args)
|
||||
"Execute COMMAND with ARGS synchronously.
|
||||
|
||||
Returns (STATUS . OUTPUT) when it is done, where STATUS is the returned error
|
||||
code of the process and OUTPUT is its stdout output."
|
||||
(with-temp-buffer
|
||||
(cons (or (apply #'call-process command nil t nil args)
|
||||
-1)
|
||||
(string-trim (buffer-string)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-exec-process (command &rest args)
|
||||
"Execute COMMAND with ARGS synchronously.
|
||||
|
||||
Unlike `doom-call-process', this pipes output to `standard-output' on the fly to
|
||||
simulate 'exec' in the shell, so batch scripts could run external programs
|
||||
synchronously without sacrificing their output.
|
||||
|
||||
Warning: freezes indefinitely on any stdin prompt."
|
||||
;; FIXME Is there any way to handle prompts?
|
||||
(with-temp-buffer
|
||||
(cons (let ((process
|
||||
(make-process :name "doom-sh"
|
||||
:buffer (current-buffer)
|
||||
:command (cons command args)
|
||||
:connection-type 'pipe))
|
||||
done-p)
|
||||
(set-process-filter
|
||||
process (lambda (_process output)
|
||||
(princ output (current-buffer))
|
||||
(princ output)))
|
||||
(set-process-sentinel
|
||||
process (lambda (process _event)
|
||||
(when (memq (process-status process) '(exit stop))
|
||||
(setq done-p t))))
|
||||
(while (not done-p)
|
||||
(sit-for 0.1))
|
||||
(process-exit-status process))
|
||||
(string-trim (buffer-string)))))
|
||||
@@ -26,8 +26,9 @@
|
||||
(doom-project-find-file doom-private-dir))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/goto-doomblock ()
|
||||
"Open your private init.el and go to your `doom!' block."
|
||||
(defun doom/goto-private-init-file ()
|
||||
"Open your private init.el file.
|
||||
And jumps to your `doom!' block."
|
||||
(interactive)
|
||||
(find-file (expand-file-name "init.el" doom-private-dir))
|
||||
(goto-char
|
||||
@@ -37,13 +38,13 @@
|
||||
(point))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/goto-config-file ()
|
||||
(defun doom/goto-private-config-file ()
|
||||
"Open your private config.el file."
|
||||
(interactive)
|
||||
(find-file (expand-file-name "config.el" doom-private-dir)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/goto-packages-file ()
|
||||
(defun doom/goto-private-packages-file ()
|
||||
"Open your private packages.el file."
|
||||
(interactive)
|
||||
(find-file (expand-file-name "packages.el" doom-private-dir)))
|
||||
@@ -52,42 +53,48 @@
|
||||
;;
|
||||
;;; Managements
|
||||
|
||||
(cl-defmacro doom--compile (command &key on-success on-failure)
|
||||
(declare (indent defun))
|
||||
`(with-current-buffer (compile ,command)
|
||||
(add-hook
|
||||
'compilation-finish-functions
|
||||
(lambda (_buf status)
|
||||
(if (equal status "finished\n")
|
||||
,on-success
|
||||
,on-failure))
|
||||
nil 'local)))
|
||||
(defmacro doom--if-compile (command on-success &optional on-failure)
|
||||
(declare (indent 2))
|
||||
(let ((windowsym (make-symbol "doom-sync-window")))
|
||||
`(with-current-buffer (compile ,command t)
|
||||
(let ((,windowsym (get-buffer-window (current-buffer))))
|
||||
(select-window ,windowsym)
|
||||
(add-hook
|
||||
'compilation-finish-functions
|
||||
(lambda (_buf status)
|
||||
(if (equal status "finished\n")
|
||||
(progn
|
||||
(delete-window ,windowsym)
|
||||
,on-success)
|
||||
,on-failure))
|
||||
nil 'local)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/reload ()
|
||||
"Reloads your private config.
|
||||
|
||||
This is experimental! It will try to do as `bin/doom refresh' does, but from
|
||||
within this Emacs session. i.e. it reload autoloads files (if necessary),
|
||||
reloads your package list, and lastly, reloads your private config.el.
|
||||
This is experimental! It will try to do as `bin/doom sync' does, but from within
|
||||
this Emacs session. i.e. it reload autoloads files (if necessary), reloads your
|
||||
package list, and lastly, reloads your private config.el.
|
||||
|
||||
Runs `doom-reload-hook' afterwards."
|
||||
(interactive)
|
||||
(require 'core-cli)
|
||||
(when (and IS-WINDOWS (file-exists-p doom-env-file))
|
||||
(warn "Can't regenerate envvar file from within Emacs. Run 'doom env' from the console"))
|
||||
(doom--compile (format "%s refresh -e" doom-bin)
|
||||
:on-success
|
||||
(let ((doom-reloading-p t))
|
||||
(doom-initialize 'force)
|
||||
(with-demoted-errors "PRIVATE CONFIG ERROR: %s"
|
||||
(general-auto-unbind-keys)
|
||||
(unwind-protect
|
||||
(doom-initialize-modules 'force)
|
||||
(general-auto-unbind-keys t)))
|
||||
(run-hook-wrapped 'doom-reload-hook #'doom-try-run-hook)
|
||||
(print! (success "Config successfully reloaded!")))
|
||||
:on-failure
|
||||
(message "Can't regenerate envvar file from within Emacs. Run 'doom env' from the console"))
|
||||
;; In case doom/reload is run before incrementally loaded packages are loaded,
|
||||
;; which could cause odd load order issues.
|
||||
(mapc #'require (cdr doom-incremental-packages))
|
||||
(doom--if-compile (format "%s sync -e" doom-bin)
|
||||
(let ((doom-reloading-p t))
|
||||
(doom-initialize 'force)
|
||||
(with-demoted-errors "PRIVATE CONFIG ERROR: %s"
|
||||
(general-auto-unbind-keys)
|
||||
(unwind-protect
|
||||
(doom-initialize-modules 'force)
|
||||
(general-auto-unbind-keys t)))
|
||||
(run-hook-wrapped 'doom-reload-hook #'doom-try-run-hook)
|
||||
(message "Config successfully reloaded!"))
|
||||
(user-error "Failed to reload your config")))
|
||||
|
||||
;;;###autoload
|
||||
@@ -98,13 +105,13 @@ This is much faster and safer than `doom/reload', but not as comprehensive. This
|
||||
reloads your package and module visibility, but does not install new packages or
|
||||
remove orphaned ones. It also doesn't reload your private config.
|
||||
|
||||
It is useful to only pull in changes performed by 'doom refresh' on the command
|
||||
It is useful to only pull in changes performed by 'doom sync' on the command
|
||||
line."
|
||||
(interactive)
|
||||
(require 'core-cli)
|
||||
(require 'core-packages)
|
||||
(doom-initialize-packages)
|
||||
(doom-cli-reload-autoloads nil 'force))
|
||||
(doom-autoloads-reload))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/reload-env (&optional arg)
|
||||
@@ -118,25 +125,22 @@ imported into Emacs."
|
||||
(interactive "P")
|
||||
(when IS-WINDOWS
|
||||
(user-error "Cannot reload envvar file from within Emacs on Windows, run it from cmd.exe"))
|
||||
(doom--compile
|
||||
(format "%s -ic '%s env%s'"
|
||||
(string-trim
|
||||
(shell-command-to-string
|
||||
(format "getent passwd %S | cut -d: -f7"
|
||||
(user-login-name))))
|
||||
doom-bin (if arg " -c" ""))
|
||||
:on-success
|
||||
(let ((doom-reloading-p t))
|
||||
(unless arg
|
||||
(doom-load-envvars-file doom-env-file)))
|
||||
:on-failure
|
||||
(doom--if-compile
|
||||
(format "%s -ic '%s env%s'"
|
||||
(string-trim
|
||||
(shell-command-to-string
|
||||
(format "getent passwd %S | cut -d: -f7"
|
||||
(user-login-name))))
|
||||
doom-bin (if arg " -c" ""))
|
||||
(let ((doom-reloading-p t))
|
||||
(unless arg
|
||||
(doom-load-envvars-file doom-env-file)))
|
||||
(error "Failed to generate env file")))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/upgrade ()
|
||||
"Run 'doom upgrade' then prompt to restart Emacs."
|
||||
(interactive)
|
||||
(doom--compile (format "%s upgrade" doom-bin)
|
||||
:on-success
|
||||
(when (y-or-n-p "You must restart Emacs for the upgrade to take effect.\n\nRestart Emacs?")
|
||||
(doom/restart-and-restore))))
|
||||
(doom--if-compile (format "%s -y upgrade" doom-bin)
|
||||
(when (y-or-n-p "You must restart Emacs for the upgrade to take effect.\n\nRestart Emacs?")
|
||||
(doom/restart-and-restore))))
|
||||
|
||||
@@ -1,5 +1,37 @@
|
||||
;;; core/autoload/debug.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;
|
||||
;;; Doom's debug mode
|
||||
|
||||
;;;###autoload
|
||||
(defvar doom-debug-variables
|
||||
'(doom-debug-p
|
||||
init-file-debug
|
||||
debug-on-error
|
||||
garbage-collection-messages
|
||||
use-package-verbose
|
||||
jka-compr-verbose
|
||||
lsp-log-io
|
||||
gcmh-verbose
|
||||
magit-refresh-verbose
|
||||
url-debug)
|
||||
"A list of variable to toggle on `doom-debug-mode'.")
|
||||
|
||||
;;;###autoload
|
||||
(define-minor-mode doom-debug-mode
|
||||
"Toggle `debug-on-error' and `doom-debug-p' for verbose logging."
|
||||
:init-value doom-debug-p
|
||||
:global t
|
||||
(let ((value
|
||||
(cond ((eq arg 'toggle) (not doom-debug-mode))
|
||||
((> (prefix-numeric-value arg) 0)))))
|
||||
(mapc (doom-rpartial #'set value) doom-debug-variables)
|
||||
(message "Debug mode %s" (if value "on" "off"))))
|
||||
|
||||
|
||||
;;
|
||||
;;; Hooks
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-run-all-startup-hooks-h ()
|
||||
"Run all startup Emacs hooks. Meant to be executed after starting Emacs with
|
||||
@@ -17,36 +49,44 @@
|
||||
;;
|
||||
;;; Helpers
|
||||
|
||||
(defun doom-template-insert (template)
|
||||
"TODO"
|
||||
(let ((file (expand-file-name (format "templates/%s" template) doom-core-dir)))
|
||||
(when (file-exists-p file)
|
||||
(insert-file-contents file))))
|
||||
(defsubst doom--collect-forms-in (file form)
|
||||
(when (file-readable-p file)
|
||||
(let (forms)
|
||||
(with-temp-buffer
|
||||
(insert-file-contents file)
|
||||
(let (emacs-lisp-mode) (emacs-lisp-mode))
|
||||
(while (re-search-forward (format "(%s " (regexp-quote form)) nil t)
|
||||
(let ((ppss (syntax-ppss)))
|
||||
(unless (or (nth 4 ppss)
|
||||
(nth 3 ppss))
|
||||
(save-excursion
|
||||
(goto-char (match-beginning 0))
|
||||
(push (sexp-at-point) forms)))))
|
||||
(nreverse forms)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-info ()
|
||||
"Returns diagnostic information about the current Emacs session in markdown,
|
||||
ready to be pasted in a bug report on github."
|
||||
(require 'vc-git)
|
||||
(require 'core-packages)
|
||||
(let ((default-directory doom-emacs-dir)
|
||||
(doom-modules (doom-modules)))
|
||||
(cl-letf
|
||||
(((symbol-function 'sh)
|
||||
(lambda (&rest args)
|
||||
(cdr (apply #'doom-call-process args)))))
|
||||
(doom-modules (doom-module-list)))
|
||||
(letf! (defun sh (&rest args) (cdr (apply #'doom-call-process args)))
|
||||
`((emacs
|
||||
(version . ,emacs-version)
|
||||
(features ,@system-configuration-features)
|
||||
(build . ,(format-time-string "%b %d, %Y" emacs-build-time))
|
||||
(buildopts ,system-configuration-options)
|
||||
(windowsys . ,(if noninteractive 'batch window-system))
|
||||
(windowsys . ,(if doom-interactive-p window-system 'batch))
|
||||
(daemonp . ,(cond ((daemonp) 'daemon)
|
||||
((and (require 'server)
|
||||
(server-running-p))
|
||||
'server-running))))
|
||||
(doom
|
||||
(version . ,doom-version)
|
||||
(build . ,(sh "git" "log" "-1" "--format=%D %h %ci")))
|
||||
(build . ,(sh "git" "log" "-1" "--format=%D %h %ci"))
|
||||
(dir . ,(abbreviate-file-name (file-truename doom-private-dir))))
|
||||
(system
|
||||
(type . ,system-type)
|
||||
(config . ,system-configuration)
|
||||
@@ -79,14 +119,19 @@ ready to be pasted in a bug report on github."
|
||||
'("n/a")))
|
||||
(packages
|
||||
,@(or (condition-case e
|
||||
(cl-loop for (name . plist) in (doom-package-list)
|
||||
if (cl-find :private (plist-get plist :modules)
|
||||
:key #'car)
|
||||
collect
|
||||
(if-let (splist (doom-plist-delete (copy-sequence plist)
|
||||
:modules))
|
||||
(prin1-to-string (cons name splist))
|
||||
name))
|
||||
(mapcar
|
||||
#'cdr (doom--collect-forms-in
|
||||
(doom-path doom-private-dir "packages.el")
|
||||
"package!"))
|
||||
(error (format "<%S>" e)))
|
||||
'("n/a")))
|
||||
(unpin
|
||||
,@(or (condition-case e
|
||||
(mapcan #'identity
|
||||
(mapcar
|
||||
#'cdr (doom--collect-forms-in
|
||||
(doom-path doom-private-dir "packages.el")
|
||||
"unpin!")))
|
||||
(error (format "<%S>" e)))
|
||||
'("n/a")))
|
||||
(elpa
|
||||
@@ -109,13 +154,13 @@ branch and commit."
|
||||
(interactive)
|
||||
(require 'vc-git)
|
||||
(let ((default-directory doom-core-dir))
|
||||
(print! "Doom v%s (Emacs v%s)\nBranch: %s\nCommit: %s\nBuild date: %s"
|
||||
(print! "Doom v%s (%s)\nEmacs v%s\nBranch: %s\nBuild date: %s"
|
||||
doom-version
|
||||
(or (vc-git-working-revision doom-core-dir)
|
||||
"n/a")
|
||||
emacs-version
|
||||
(or (vc-git--symbolic-ref doom-core-dir)
|
||||
"n/a")
|
||||
(or (vc-git-working-revision doom-core-dir)
|
||||
"n/a")
|
||||
(or (cdr (doom-call-process "git" "log" "-1" "--format=%ci"))
|
||||
"n/a"))))
|
||||
|
||||
@@ -127,22 +172,23 @@ markdown and copies it to your clipboard, ready to be pasted into bug reports!"
|
||||
(let ((buffer (get-buffer-create "*doom-info*"))
|
||||
(info (doom-info)))
|
||||
(with-current-buffer buffer
|
||||
(unless (or noninteractive
|
||||
(eq major-mode 'markdown-mode)
|
||||
(not (fboundp 'markdown-mode)))
|
||||
(markdown-mode))
|
||||
(or (not doom-interactive-p)
|
||||
(eq major-mode 'markdown-mode)
|
||||
(not (fboundp 'markdown-mode))
|
||||
(markdown-mode))
|
||||
(erase-buffer)
|
||||
(if raw
|
||||
(progn
|
||||
(save-excursion
|
||||
(pp info (current-buffer)))
|
||||
(when (search-forward "(modules " nil t)
|
||||
(goto-char (match-beginning 0))
|
||||
(cl-destructuring-bind (beg . end)
|
||||
(bounds-of-thing-at-point 'sexp)
|
||||
(let ((sexp (prin1-to-string (sexp-at-point))))
|
||||
(delete-region beg end)
|
||||
(insert sexp)))))
|
||||
(dolist (sym '(modules packages))
|
||||
(when (re-search-forward (format "^ *\\((%s\\)" sym) nil t)
|
||||
(goto-char (match-beginning 1))
|
||||
(cl-destructuring-bind (beg . end)
|
||||
(bounds-of-thing-at-point 'sexp)
|
||||
(let ((sexp (prin1-to-string (sexp-at-point))))
|
||||
(delete-region beg end)
|
||||
(insert sexp))))))
|
||||
(insert "<details>\n\n```\n")
|
||||
(dolist (group info)
|
||||
(insert! "%-8s%-10s %s\n"
|
||||
@@ -153,7 +199,7 @@ markdown and copies it to your clipboard, ready to be pasted into bug reports!"
|
||||
(insert! (indent 8 "%-10s %s\n")
|
||||
((car spec) (cdr spec)))))
|
||||
(insert "```\n</details>"))
|
||||
(if noninteractive
|
||||
(if (not doom-interactive-p)
|
||||
(print! (buffer-string))
|
||||
(switch-to-buffer buffer)
|
||||
(kill-new (buffer-string))
|
||||
@@ -161,15 +207,45 @@ markdown and copies it to your clipboard, ready to be pasted into bug reports!"
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/am-i-secure ()
|
||||
"Test to see if your root certificates are securely configured in emacs."
|
||||
"Test to see if your root certificates are securely configured in emacs.
|
||||
Some items are not supported by the `nsm.el' module."
|
||||
(declare (interactive-only t))
|
||||
(interactive)
|
||||
(unless (string-match-p "\\_<GNUTLS\\_>" system-configuration-features)
|
||||
(warn "gnutls support isn't built into Emacs, there may be problems"))
|
||||
(if-let* ((bad-hosts
|
||||
(cl-loop for bad
|
||||
in '("https://wrong.host.badssl.com/"
|
||||
"https://self-signed.badssl.com/")
|
||||
in '("https://expired.badssl.com/"
|
||||
"https://wrong.host.badssl.com/"
|
||||
"https://self-signed.badssl.com/"
|
||||
"https://untrusted-root.badssl.com/"
|
||||
;; "https://revoked.badssl.com/"
|
||||
;; "https://pinning-test.badssl.com/"
|
||||
"https://sha1-intermediate.badssl.com/"
|
||||
"https://rc4-md5.badssl.com/"
|
||||
"https://rc4.badssl.com/"
|
||||
"https://3des.badssl.com/"
|
||||
"https://null.badssl.com/"
|
||||
"https://sha1-intermediate.badssl.com/"
|
||||
;; "https://client-cert-missing.badssl.com/"
|
||||
"https://dh480.badssl.com/"
|
||||
"https://dh512.badssl.com/"
|
||||
"https://dh-small-subgroup.badssl.com/"
|
||||
"https://dh-composite.badssl.com/"
|
||||
"https://invalid-expected-sct.badssl.com/"
|
||||
;; "https://no-sct.badssl.com/"
|
||||
;; "https://mixed-script.badssl.com/"
|
||||
;; "https://very.badssl.com/"
|
||||
"https://subdomain.preloaded-hsts.badssl.com/"
|
||||
"https://superfish.badssl.com/"
|
||||
"https://edellroot.badssl.com/"
|
||||
"https://dsdtestprovider.badssl.com/"
|
||||
"https://preact-cli.badssl.com/"
|
||||
"https://webpack-dev-server.badssl.com/"
|
||||
"https://captive-portal.badssl.com/"
|
||||
"https://mitm-software.badssl.com/"
|
||||
"https://sha1-2016.badssl.com/"
|
||||
"https://sha1-2017.badssl.com/")
|
||||
if (condition-case _e
|
||||
(url-retrieve-synchronously bad)
|
||||
(error nil))
|
||||
@@ -193,48 +269,59 @@ markdown and copies it to your clipboard, ready to be pasted into bug reports!"
|
||||
(file (make-temp-file "doom-sandbox-")))
|
||||
(require 'package)
|
||||
(with-temp-file file
|
||||
(insert
|
||||
(prin1-to-string
|
||||
(macroexp-progn
|
||||
(append `((setq noninteractive nil
|
||||
doom-debug-mode t
|
||||
load-path ',load-path
|
||||
package--init-file-ensured t
|
||||
package-user-dir ,package-user-dir
|
||||
package-archives ',package-archives
|
||||
user-emacs-directory ,doom-emacs-dir)
|
||||
(with-eval-after-load 'undo-tree
|
||||
;; undo-tree throws errors because `buffer-undo-tree' isn't
|
||||
;; corrrectly initialized
|
||||
(setq-default buffer-undo-tree (make-undo-tree))))
|
||||
(pcase mode
|
||||
(`vanilla-doom+ ; Doom core + modules - private config
|
||||
`((load-file ,(expand-file-name "core.el" doom-core-dir))
|
||||
(doom-initialize)
|
||||
(doom-initialize-core)
|
||||
(add-hook 'window-setup-hook #'doom-display-benchmark-h)
|
||||
(setq doom-modules ',doom-modules)
|
||||
(maphash (lambda (key plist)
|
||||
(let ((doom--current-module key)
|
||||
(doom--current-flags (plist-get plist :flags)))
|
||||
(load! "init" (doom-module-locate-path (car key) (cdr key)) t)))
|
||||
doom-modules)
|
||||
(maphash (lambda (key plist)
|
||||
(let ((doom--current-module key)
|
||||
(doom--current-flags (plist-get plist :flags)))
|
||||
(load! "config" (doom-module-locate-path (car key) (cdr key)) t)))
|
||||
doom-modules)
|
||||
(run-hook-wrapped 'doom-init-modules-hook #'doom-try-run-hook)
|
||||
(doom-run-all-startup-hooks-h)))
|
||||
(`vanilla-doom ; only Doom core
|
||||
`((load-file ,(expand-file-name "core.el" doom-core-dir))
|
||||
(doom-initialize)
|
||||
(doom-initialize-core)
|
||||
(doom-run-all-startup-hooks-h)))
|
||||
(`vanilla ; nothing loaded
|
||||
`((package-initialize)))))))
|
||||
"\n(unwind-protect (progn\n" contents "\n)\n"
|
||||
(format "(delete-file %S))" file)))
|
||||
(prin1 `(progn
|
||||
(setq noninteractive nil
|
||||
process-environment ',doom--initial-process-environment
|
||||
exec-path ',doom--initial-exec-path
|
||||
init-file-debug t
|
||||
load-path ',load-path
|
||||
package--init-file-ensured t
|
||||
package-user-dir ,package-user-dir
|
||||
package-archives ',package-archives
|
||||
user-emacs-directory ,doom-emacs-dir)
|
||||
(with-eval-after-load 'undo-tree
|
||||
;; undo-tree throws errors because `buffer-undo-tree' isn't
|
||||
;; correctly initialized
|
||||
(setq-default buffer-undo-tree (make-undo-tree)))
|
||||
(ignore-errors
|
||||
(delete-directory ,(expand-file-name "auto-save-list" doom-emacs-dir) 'parents)))
|
||||
(current-buffer))
|
||||
(prin1 `(unwind-protect
|
||||
(defun --run-- () ,(read (concat "(progn\n" contents "\n)")))
|
||||
(delete-file ,file))
|
||||
(current-buffer))
|
||||
(prin1 (pcase mode
|
||||
(`vanilla-doom+ ; Doom core + modules - private config
|
||||
`(progn
|
||||
(load-file ,(expand-file-name "core.el" doom-core-dir))
|
||||
(setq doom-modules-dirs (list doom-modules-dir))
|
||||
(let ((doom-init-modules-p t))
|
||||
(doom-initialize)
|
||||
(doom-initialize-core-modules))
|
||||
(setq doom-modules ',doom-modules)
|
||||
(maphash (lambda (key plist)
|
||||
(doom-module-put
|
||||
(car key) (cdr key)
|
||||
:path (doom-module-locate-path (car key) (cdr key))))
|
||||
doom-modules)
|
||||
(--run--)
|
||||
(maphash (doom-module-loader doom-module-init-file) doom-modules)
|
||||
(maphash (doom-module-loader doom-module-config-file) doom-modules)
|
||||
(run-hook-wrapped 'doom-init-modules-hook #'doom-try-run-hook)
|
||||
(doom-run-all-startup-hooks-h)))
|
||||
(`vanilla-doom ; only Doom core
|
||||
`(progn
|
||||
(load-file ,(expand-file-name "core.el" doom-core-dir))
|
||||
(let ((doom-init-modules-p t))
|
||||
(doom-initialize)
|
||||
(doom-initialize-core-modules))
|
||||
(--run--)
|
||||
(doom-run-all-startup-hooks-h)))
|
||||
(`vanilla ; nothing loaded
|
||||
`(progn
|
||||
(package-initialize)
|
||||
(--run--))))
|
||||
(current-buffer)))
|
||||
(let ((args (if (eq mode 'doom)
|
||||
(list "-l" file)
|
||||
(list "-Q" "-l" file))))
|
||||
@@ -254,10 +341,10 @@ markdown and copies it to your clipboard, ready to be pasted into bug reports!"
|
||||
(delete-file file)
|
||||
(signal (car e) (cdr e)))))))
|
||||
|
||||
(fset 'doom--run-vanilla-emacs (lambda! (doom--run-sandbox 'vanilla)))
|
||||
(fset 'doom--run-vanilla-doom (lambda! (doom--run-sandbox 'vanilla-doom)))
|
||||
(fset 'doom--run-vanilla-doom+ (lambda! (doom--run-sandbox 'vanilla-doom+)))
|
||||
(fset 'doom--run-full-doom (lambda! (doom--run-sandbox 'doom)))
|
||||
(fset 'doom--run-vanilla-emacs (cmd! (doom--run-sandbox 'vanilla)))
|
||||
(fset 'doom--run-vanilla-doom (cmd! (doom--run-sandbox 'vanilla-doom)))
|
||||
(fset 'doom--run-vanilla-doom+ (cmd! (doom--run-sandbox 'vanilla-doom+)))
|
||||
(fset 'doom--run-full-doom (cmd! (doom--run-sandbox 'doom)))
|
||||
|
||||
(defvar doom-sandbox-emacs-lisp-mode-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
@@ -293,7 +380,7 @@ to reproduce bugs and determine if Doom is to blame."
|
||||
(doom-sandbox-emacs-lisp-mode)
|
||||
(setq-local default-directory doom-emacs-dir)
|
||||
(unless (buffer-live-p exists)
|
||||
(doom-template-insert "VANILLA_SANDBOX")
|
||||
(insert-file-contents (doom-glob doom-core-dir "templates/VANILLA_SANDBOX"))
|
||||
(let ((contents (substitute-command-keys (buffer-string))))
|
||||
(erase-buffer)
|
||||
(insert contents "\n")))
|
||||
@@ -328,17 +415,3 @@ will be automatically appended to the result."
|
||||
(profiler-report)
|
||||
(profiler-stop))
|
||||
(setq doom--profiler (not doom--profiler)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/toggle-debug-mode (&optional arg)
|
||||
"Toggle `debug-on-error' and `doom-debug-mode' for verbose logging."
|
||||
(interactive (list (or current-prefix-arg 'toggle)))
|
||||
(let ((value
|
||||
(cond ((eq arg 'toggle) (not doom-debug-mode))
|
||||
((> (prefix-numeric-value arg) 0)))))
|
||||
(setq doom-debug-mode value
|
||||
debug-on-error value
|
||||
jka-compr-verbose value
|
||||
lsp-log-io value
|
||||
gcmh-verbose value)
|
||||
(message "Debug mode %s" (if value "on" "off"))))
|
||||
|
||||
@@ -22,23 +22,20 @@ Returns (approximately):
|
||||
|
||||
This is used by `file-exists-p!' and `project-file-exists-p!'."
|
||||
(declare (pure t) (side-effect-free t))
|
||||
(let ((exists-fn (if (fboundp 'projectile-file-exists-p)
|
||||
#'projectile-file-exists-p
|
||||
#'file-exists-p)))
|
||||
(if (and (listp spec)
|
||||
(memq (car spec) '(or and)))
|
||||
(cons (car spec)
|
||||
(mapcar (doom-rpartial #'doom--resolve-path-forms directory)
|
||||
(cdr spec)))
|
||||
(let ((filevar (make-symbol "file")))
|
||||
`(let* ((file-name-handler-alist nil)
|
||||
(,filevar ,spec))
|
||||
(and (stringp ,filevar)
|
||||
,(if directory
|
||||
`(let ((default-directory ,directory))
|
||||
(,exists-fn ,filevar))
|
||||
(list exists-fn filevar))
|
||||
,filevar))))))
|
||||
(if (and (listp spec)
|
||||
(memq (car spec) '(or and)))
|
||||
(cons (car spec)
|
||||
(mapcar (doom-rpartial #'doom--resolve-path-forms directory)
|
||||
(cdr spec)))
|
||||
(let ((filevar (make-symbol "file")))
|
||||
`(let* ((file-name-handler-alist nil)
|
||||
(,filevar ,spec))
|
||||
(and (stringp ,filevar)
|
||||
,(if directory
|
||||
`(let ((default-directory ,directory))
|
||||
(file-exists-p ,filevar))
|
||||
`(file-exists-p ,filevar))
|
||||
,filevar)))))
|
||||
|
||||
(defun doom--path (&rest segments)
|
||||
(let (file-name-handler-alist)
|
||||
@@ -108,26 +105,26 @@ be relative to it.
|
||||
The search recurses up to DEPTH and no further. DEPTH is an integer.
|
||||
|
||||
MATCH is a string regexp. Only entries that match it will be included."
|
||||
(let (file-name-handler-alist
|
||||
result)
|
||||
(let (result file-name-handler-alist)
|
||||
(dolist (file (mapcan (doom-rpartial #'doom-glob "*") (doom-enlist paths)))
|
||||
(cond ((file-directory-p file)
|
||||
(nconcq! result
|
||||
(and (memq type '(t dirs))
|
||||
(string-match-p match file)
|
||||
(not (and filter (funcall filter file)))
|
||||
(not (and (file-symlink-p file)
|
||||
(not follow-symlinks)))
|
||||
(<= mindepth 0)
|
||||
(list (cond (map (funcall map file))
|
||||
(relative-to (file-relative-name file relative-to))
|
||||
(file))))
|
||||
(and (>= depth 1)
|
||||
(apply #'doom-files-in file
|
||||
(append (list :mindepth (1- mindepth)
|
||||
:depth (1- depth)
|
||||
:relative-to relative-to)
|
||||
rest)))))
|
||||
(appendq!
|
||||
result
|
||||
(and (memq type '(t dirs))
|
||||
(string-match-p match file)
|
||||
(not (and filter (funcall filter file)))
|
||||
(not (and (file-symlink-p file)
|
||||
(not follow-symlinks)))
|
||||
(<= mindepth 0)
|
||||
(list (cond (map (funcall map file))
|
||||
(relative-to (file-relative-name file relative-to))
|
||||
(file))))
|
||||
(and (>= depth 1)
|
||||
(apply #'doom-files-in file
|
||||
(append (list :mindepth (1- mindepth)
|
||||
:depth (1- depth)
|
||||
:relative-to relative-to)
|
||||
rest)))))
|
||||
((and (memq type '(t files))
|
||||
(string-match-p match file)
|
||||
(not (and filter (funcall filter file)))
|
||||
@@ -203,53 +200,29 @@ single file or nested compound statement of `and' and `or' statements."
|
||||
;;
|
||||
;;; Helpers
|
||||
|
||||
(defun doom--forget-file (old-path &optional new-path)
|
||||
"Ensure `recentf', `projectile' and `save-place' forget OLD-PATH."
|
||||
(when (bound-and-true-p recentf-mode)
|
||||
(when new-path
|
||||
(recentf-add-file new-path))
|
||||
(recentf-remove-if-non-kept old-path))
|
||||
(when (and (bound-and-true-p projectile-mode)
|
||||
(doom-project-p)
|
||||
(projectile-file-cached-p old-path (doom-project-root)))
|
||||
(projectile-purge-file-from-cache old-path))
|
||||
(when (bound-and-true-p save-place-mode)
|
||||
(save-place-forget-unreadable-files)))
|
||||
|
||||
(defun doom--update-file (path)
|
||||
(when (featurep 'vc)
|
||||
(vc-file-clearprops path)
|
||||
(vc-resynch-buffer path nil t))
|
||||
(when (featurep 'magit)
|
||||
(magit-refresh)))
|
||||
|
||||
(defun doom--copy-file (old-path new-path &optional force-p)
|
||||
(let* ((new-path (expand-file-name new-path))
|
||||
(old-path (file-truename old-path))
|
||||
(new-path (apply #'expand-file-name
|
||||
(if (or (directory-name-p new-path)
|
||||
(file-directory-p new-path))
|
||||
(list (file-name-nondirectory old-path) new-path)
|
||||
(list new-path))))
|
||||
(new-path-dir (file-name-directory new-path))
|
||||
(project-root (doom-project-root))
|
||||
(short-new-name (if (and project-root (file-in-directory-p new-path project-root))
|
||||
(file-relative-name new-path project-root)
|
||||
(abbreviate-file-name new-path))))
|
||||
(unless (file-directory-p new-path-dir)
|
||||
(make-directory new-path-dir t))
|
||||
(when (buffer-modified-p)
|
||||
(save-buffer))
|
||||
(cond ((file-equal-p old-path new-path)
|
||||
(throw 'status 'overwrite-self))
|
||||
((and (file-exists-p new-path)
|
||||
(not force-p)
|
||||
(not (y-or-n-p (format "File already exists at %s, overwrite?" short-new-name))))
|
||||
(throw 'status 'aborted))
|
||||
((file-exists-p old-path)
|
||||
(copy-file old-path new-path t)
|
||||
short-new-name)
|
||||
(short-new-name))))
|
||||
(defun doom--update-files (&rest files)
|
||||
"Ensure FILES are updated in `recentf', `magit' and `save-place'."
|
||||
(let (toplevels)
|
||||
(dolist (file files)
|
||||
(when (featurep 'vc)
|
||||
(vc-file-clearprops file)
|
||||
(when-let (buffer (get-file-buffer file))
|
||||
(with-current-buffer buffer
|
||||
(vc-refresh-state))))
|
||||
(when (featurep 'magit)
|
||||
(when-let (default-directory (magit-toplevel (file-name-directory file)))
|
||||
(cl-pushnew default-directory toplevels)))
|
||||
(unless (file-readable-p file)
|
||||
(when (bound-and-true-p recentf-mode)
|
||||
(recentf-remove-if-non-kept file))
|
||||
(when (and (bound-and-true-p projectile-mode)
|
||||
(doom-project-p)
|
||||
(projectile-file-cached-p file (doom-project-root)))
|
||||
(projectile-purge-file-from-cache file))))
|
||||
(dolist (default-directory toplevels)
|
||||
(magit-refresh))
|
||||
(when (bound-and-true-p save-place-mode)
|
||||
(save-place-forget-unreadable-files))))
|
||||
|
||||
|
||||
;;
|
||||
@@ -257,68 +230,69 @@ single file or nested compound statement of `and' and `or' statements."
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/delete-this-file (&optional path force-p)
|
||||
"Delete FILENAME (defaults to the file associated with current buffer) and
|
||||
kills the buffer. If FORCE-P, force the deletion (don't ask for confirmation)."
|
||||
"Delete PATH, kill its buffers and expunge it from vc/magit cache.
|
||||
|
||||
If PATH is not specified, default to the current buffer's file.
|
||||
|
||||
If FORCE-P, delete without confirmation."
|
||||
(interactive
|
||||
(list (file-truename (buffer-file-name))
|
||||
(list (buffer-file-name (buffer-base-buffer))
|
||||
current-prefix-arg))
|
||||
(let* ((fbase (file-name-sans-extension (file-name-nondirectory path)))
|
||||
(buf (current-buffer)))
|
||||
(cond ((not (file-exists-p path))
|
||||
(error "File doesn't exist: %s" path))
|
||||
((not (or force-p (y-or-n-p (format "Really delete %s?" fbase))))
|
||||
(message "Aborted")
|
||||
nil)
|
||||
((unwind-protect
|
||||
(progn (delete-file path) t)
|
||||
(let ((short-path (file-relative-name path (doom-project-root))))
|
||||
(if (file-exists-p path)
|
||||
(error "Failed to delete %s" short-path)
|
||||
;; Ensures that windows displaying this buffer will be switched
|
||||
;; to real buffers (`doom-real-buffer-p')
|
||||
(doom/kill-this-buffer-in-all-windows buf t)
|
||||
(doom--forget-file path)
|
||||
(doom--update-file path)
|
||||
(message "Successfully deleted %s" short-path))))))))
|
||||
(let* ((path (or path (buffer-file-name (buffer-base-buffer))))
|
||||
(short-path (abbreviate-file-name path)))
|
||||
(unless (and path (file-exists-p path))
|
||||
(user-error "Buffer is not visiting any file"))
|
||||
(unless (file-exists-p path)
|
||||
(error "File doesn't exist: %s" path))
|
||||
(unless (or force-p (y-or-n-p (format "Really delete %S?" short-path)))
|
||||
(user-error "Aborted"))
|
||||
(let ((buf (current-buffer)))
|
||||
(unwind-protect
|
||||
(progn (delete-file path) t)
|
||||
(if (file-exists-p path)
|
||||
(error "Failed to delete %S" short-path)
|
||||
;; Ensures that windows displaying this buffer will be switched to
|
||||
;; real buffers (`doom-real-buffer-p')
|
||||
(doom/kill-this-buffer-in-all-windows buf t)
|
||||
(doom--update-files path)
|
||||
(message "Deleted %S" short-path))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/copy-this-file (new-path &optional force-p)
|
||||
"Copy current buffer's file to NEW-PATH. If FORCE-P, overwrite the destination
|
||||
file if it exists, without confirmation."
|
||||
"Copy current buffer's file to NEW-PATH.
|
||||
|
||||
If FORCE-P, overwrite the destination file if it exists, without confirmation."
|
||||
(interactive
|
||||
(list (read-file-name "Copy file to: ")
|
||||
current-prefix-arg))
|
||||
(pcase (catch 'status
|
||||
(when-let (dest (doom--copy-file (buffer-file-name) new-path force-p))
|
||||
(doom--update-file new-path)
|
||||
(message "File successfully copied to %s" dest)))
|
||||
(`overwrite-self (error "Cannot overwrite self"))
|
||||
(`aborted (message "Aborted"))
|
||||
(_ t)))
|
||||
(unless (and buffer-file-name (file-exists-p buffer-file-name))
|
||||
(user-error "Buffer is not visiting any file"))
|
||||
(let ((old-path (buffer-file-name (buffer-base-buffer)))
|
||||
(new-path (expand-file-name new-path)))
|
||||
(make-directory (file-name-directory new-path) 't)
|
||||
(copy-file old-path new-path (or force-p 1))
|
||||
(doom--update-files old-path new-path)
|
||||
(message "File copied to %S" (abbreviate-file-name new-path))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/move-this-file (new-path &optional force-p)
|
||||
"Move current buffer's file to NEW-PATH. If FORCE-P, overwrite the destination
|
||||
file if it exists, without confirmation."
|
||||
"Move current buffer's file to NEW-PATH.
|
||||
|
||||
If FORCE-P, overwrite the destination file if it exists, without confirmation."
|
||||
(interactive
|
||||
(list (read-file-name "Move file to: ")
|
||||
current-prefix-arg))
|
||||
(pcase (catch 'status
|
||||
(let ((old-path (buffer-file-name))
|
||||
(new-path (expand-file-name new-path)))
|
||||
(when-let (dest (doom--copy-file old-path new-path force-p))
|
||||
(when (file-exists-p old-path)
|
||||
(delete-file old-path))
|
||||
(kill-current-buffer)
|
||||
(doom--forget-file old-path new-path)
|
||||
(doom--update-file new-path)
|
||||
(find-file new-path)
|
||||
(message "File successfully moved to %s" dest))))
|
||||
(`overwrite-self (error "Cannot overwrite self"))
|
||||
(`aborted (message "Aborted"))
|
||||
(_ t)))
|
||||
(unless (and buffer-file-name (file-exists-p buffer-file-name))
|
||||
(user-error "Buffer is not visiting any file"))
|
||||
(let ((old-path (buffer-file-name (buffer-base-buffer)))
|
||||
(new-path (expand-file-name new-path)))
|
||||
(make-directory (file-name-directory new-path) 't)
|
||||
(rename-file old-path new-path (or force-p 1))
|
||||
(set-visited-file-name new-path t t)
|
||||
(doom--update-files old-path new-path)
|
||||
(message "File moved to %S" (abbreviate-file-name new-path))))
|
||||
|
||||
(defun doom--sudo-file (file)
|
||||
(defun doom--sudo-file-path (file)
|
||||
(let ((host (or (file-remote-p file 'host) "localhost")))
|
||||
(concat "/" (when (file-remote-p file)
|
||||
(concat (file-remote-p file 'method) ":"
|
||||
@@ -334,10 +308,32 @@ file if it exists, without confirmation."
|
||||
(defun doom/sudo-find-file (file)
|
||||
"Open FILE as root."
|
||||
(interactive "FOpen file as root: ")
|
||||
(find-file (doom--sudo-file file)))
|
||||
(find-file (doom--sudo-file-path file)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/sudo-this-file ()
|
||||
"Open the current file as root."
|
||||
(interactive)
|
||||
(find-alternate-file (doom--sudo-file buffer-file-name)))
|
||||
(find-file
|
||||
(doom--sudo-file-path
|
||||
(or buffer-file-name
|
||||
(when (or (derived-mode-p 'dired-mode)
|
||||
(derived-mode-p 'wdired-mode))
|
||||
default-directory)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/sudo-save-buffer ()
|
||||
"Save this file as root."
|
||||
(interactive)
|
||||
(let ((file (doom--sudo-file-path buffer-file-name)))
|
||||
(if-let (buffer (find-file-noselect file))
|
||||
(let ((origin (current-buffer)))
|
||||
(copy-to-buffer buffer (point-min) (point-max))
|
||||
(unwind-protect
|
||||
(with-current-buffer buffer
|
||||
(save-buffer))
|
||||
(unless (eq origin buffer)
|
||||
(kill-buffer buffer))
|
||||
(with-current-buffer origin
|
||||
(revert-buffer t t))))
|
||||
(user-error "Unable to open %S" file))))
|
||||
|
||||
@@ -12,7 +12,7 @@ scaled up by `doom-big-font-increment'. See `doom-font' for details on
|
||||
acceptable values for this variable.")
|
||||
|
||||
;;;###autoload
|
||||
(defvar doom-big-font-increment 8
|
||||
(defvar doom-big-font-increment 4
|
||||
"How many steps to increase the font size (with `doom-font' as the base) when
|
||||
`doom-big-font-mode' is enabled and `doom-big-font' is nil.")
|
||||
|
||||
@@ -20,56 +20,47 @@ acceptable values for this variable.")
|
||||
;;
|
||||
;;; Library
|
||||
|
||||
(defun doom--font-name (fontname frame)
|
||||
(defun doom--font-name (fontname)
|
||||
(when (query-fontset fontname)
|
||||
(when-let (ascii (assq 'ascii (aref (fontset-info fontname frame) 2)))
|
||||
(when-let (ascii (assq 'ascii (aref (fontset-info fontname) 2)))
|
||||
(setq fontname (nth 2 ascii))))
|
||||
(or (x-decompose-font-name fontname)
|
||||
(error "Cannot decompose font name")))
|
||||
|
||||
(defun doom--frame-list (&optional frame)
|
||||
"Return a list consisting of FRAME and all of FRAME's child frames."
|
||||
(let ((frame (or frame (selected-frame))))
|
||||
(cons (selected-frame)
|
||||
(cl-loop for fr in (frame-list)
|
||||
if (eq (frame-parameter fr 'parent-frame) frame)
|
||||
collect fr))))
|
||||
|
||||
(defvar doom--font-scale nil)
|
||||
;;;###autoload
|
||||
(defun doom-adjust-font-size (increment &optional frame)
|
||||
(defun doom-adjust-font-size (increment)
|
||||
"Increase size of font in FRAME by INCREMENT.
|
||||
FRAME parameter defaults to current frame."
|
||||
(if (null increment)
|
||||
(let ((frames (doom--frame-list frame)))
|
||||
(dolist (frame frames)
|
||||
(when (frame-parameter frame 'font-scale)
|
||||
(set-frame-parameter frame 'font-scale nil)))
|
||||
(set-frame-font doom-font 'keep-size frames)
|
||||
(and frames t))
|
||||
(let (success)
|
||||
(dolist (frame (doom--frame-list frame))
|
||||
(let* ((font (frame-parameter frame 'font))
|
||||
(font (doom--font-name font frame))
|
||||
(increment (* increment doom-font-increment))
|
||||
(zoom-factor (or (frame-parameter frame 'font-scale) 0)))
|
||||
(let ((new-size (+ (string-to-number (aref font xlfd-regexp-pixelsize-subnum))
|
||||
increment)))
|
||||
(unless (> new-size 0)
|
||||
(error "Font is too small at %d" new-size))
|
||||
(aset font xlfd-regexp-pixelsize-subnum (number-to-string new-size)))
|
||||
;; Set point size & width to "*", so frame width will adjust to new font size
|
||||
(aset font xlfd-regexp-pointsize-subnum "*")
|
||||
(aset font xlfd-regexp-avgwidth-subnum "*")
|
||||
(setq font (x-compose-font-name font))
|
||||
(unless (x-list-fonts font)
|
||||
(error "Cannot change font size"))
|
||||
(set-frame-parameter frame 'font font)
|
||||
(set-frame-parameter frame 'font-scale (+ zoom-factor increment))
|
||||
(setq success t)))
|
||||
(when success
|
||||
;; Unlike `set-frame-font', `set-frame-parameter' won't trigger this
|
||||
(run-hooks 'after-setting-font-hook)
|
||||
t))))
|
||||
(progn
|
||||
(set-frame-font doom-font 'keep-size t)
|
||||
(setf (alist-get 'font default-frame-alist)
|
||||
(cond ((stringp doom-font) doom-font)
|
||||
((fontp doom-font) (font-xlfd-name doom-font))
|
||||
((signal 'wrong-type-argument (list '(fontp stringp)
|
||||
doom-font)))))
|
||||
t)
|
||||
(let* ((font (frame-parameter nil 'font))
|
||||
(font (doom--font-name font))
|
||||
(increment (* increment doom-font-increment))
|
||||
(zoom-factor (or doom--font-scale 0)))
|
||||
(let ((new-size (+ (string-to-number (aref font xlfd-regexp-pixelsize-subnum))
|
||||
increment)))
|
||||
(unless (> new-size 0)
|
||||
(error "Font is too small at %d" new-size))
|
||||
(aset font xlfd-regexp-pixelsize-subnum (number-to-string new-size)))
|
||||
;; Set point size & width to "*", so frame width will adjust to new font size
|
||||
(aset font xlfd-regexp-pointsize-subnum "*")
|
||||
(aset font xlfd-regexp-avgwidth-subnum "*")
|
||||
(setq font (x-compose-font-name font))
|
||||
(unless (x-list-fonts font)
|
||||
(error "Cannot change font size"))
|
||||
(set-frame-font font 'keep-size t)
|
||||
(setf (alist-get 'font default-frame-alist) font)
|
||||
(setq doom--font-scale (+ zoom-factor increment))
|
||||
;; Unlike `set-frame-font', `set-frame-parameter' won't trigger this
|
||||
(run-hooks 'after-setting-font-hook))))
|
||||
|
||||
|
||||
;;
|
||||
@@ -127,8 +118,13 @@ This uses `doom/increase-font-size' under the hood, and enlargens the font by
|
||||
(unless doom-font
|
||||
(user-error "`doom-font' must be set to a valid font"))
|
||||
(if doom-big-font
|
||||
(set-frame-font (if doom-big-font-mode doom-big-font doom-font)
|
||||
'keep-size (doom--frame-list))
|
||||
(let ((font (if doom-big-font-mode doom-big-font doom-font)))
|
||||
(set-frame-font font 'keep-size t)
|
||||
(setf (alist-get 'font default-frame-alist)
|
||||
(cond ((stringp doom-font) font)
|
||||
((fontp font) (font-xlfd-name font))
|
||||
((signal 'wrong-type-argument (list '(fontp stringp)
|
||||
font))))))
|
||||
(doom-adjust-font-size
|
||||
(and doom-big-font-mode
|
||||
(integerp doom-big-font-increment)
|
||||
|
||||
@@ -1,243 +0,0 @@
|
||||
;;; core/autoload/format.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defvar doom-format-ansi-alist
|
||||
'(;; fx
|
||||
(bold 1 :weight bold)
|
||||
(dark 2)
|
||||
(italic 3 :slant italic)
|
||||
(underscore 4 :underline t)
|
||||
(blink 5)
|
||||
(rapid 6)
|
||||
(contrary 7)
|
||||
(concealed 8)
|
||||
(strike 9 :strike-through t)
|
||||
;; fg
|
||||
(black 30 term-color-black)
|
||||
(red 31 term-color-red)
|
||||
(green 32 term-color-green)
|
||||
(yellow 33 term-color-yellow)
|
||||
(blue 34 term-color-blue)
|
||||
(magenta 35 term-color-magenta)
|
||||
(cyan 36 term-color-cyan)
|
||||
(white 37 term-color-white)
|
||||
;; bg
|
||||
(on-black 40 term-color-black)
|
||||
(on-red 41 term-color-red)
|
||||
(on-green 42 term-color-green)
|
||||
(on-yellow 43 term-color-yellow)
|
||||
(on-blue 44 term-color-blue)
|
||||
(on-magenta 45 term-color-magenta)
|
||||
(on-cyan 46 term-color-cyan)
|
||||
(on-white 47 term-color-white))
|
||||
"An alist of fg/bg/fx names mapped to ansi codes and term-color-* variables.
|
||||
|
||||
This serves as the cipher for converting (COLOR ...) function calls in `print!'
|
||||
and `format!' into colored output, where COLOR is any car of this list.")
|
||||
|
||||
(defvar doom-format-class-alist
|
||||
`((color . doom--format-color)
|
||||
(class . doom--format-class)
|
||||
(indent . doom--format-indent)
|
||||
(autofill . doom--format-autofill)
|
||||
|
||||
(success . (lambda (str &rest args)
|
||||
(apply #'doom--format-color 'green (format "✓ %s" str) args)))
|
||||
(warn . (lambda (str &rest args)
|
||||
(apply #'doom--format-color 'yellow (format "! %s" str) args)))
|
||||
(error . (lambda (str &rest args)
|
||||
(apply #'doom--format-color 'red (format "x %s" str) args)))
|
||||
(info . (lambda (str &rest args)
|
||||
(concat "- " (if args (apply #'format str args) str))))
|
||||
(start . (lambda (str &rest args)
|
||||
(concat "> " (if args (apply #'format str args) str))))
|
||||
(debug . (lambda (str &rest args)
|
||||
(if doom-debug-mode
|
||||
(if args
|
||||
(apply #'format str args)
|
||||
(format "%s" str))
|
||||
"")))
|
||||
(path . abbreviate-file-name)
|
||||
(symbol . symbol-name)
|
||||
(relpath . (lambda (str &optional dir)
|
||||
(if (or (not str)
|
||||
(not (stringp str))
|
||||
(string-empty-p str))
|
||||
str
|
||||
(let ((dir (or dir (file-truename default-directory)))
|
||||
(str (file-truename str)))
|
||||
(if (file-in-directory-p str dir)
|
||||
(file-relative-name str dir)
|
||||
(abbreviate-file-name str))))))
|
||||
(filename . file-name-nondirectory)
|
||||
(dirname . (lambda (path)
|
||||
(unless (file-directory-p path)
|
||||
(setq path (file-name-directory path)))
|
||||
(directory-file-name path))))
|
||||
"An alist of text classes that map to transformation functions.
|
||||
|
||||
Any of these classes can be called like functions from within `format!' and
|
||||
`print!' calls, which will transform their input.")
|
||||
|
||||
(defvar doom-format-indent 0
|
||||
"Level to rigidly indent text returned by `format!' and `print!'.")
|
||||
|
||||
(defvar doom-format-indent-increment 2
|
||||
"Steps in which to increment `doom-format-indent' for consecutive levels.")
|
||||
|
||||
(defvar doom-format-backend
|
||||
(if noninteractive 'ansi 'text-properties)
|
||||
"Determines whether to print colors with ANSI codes or with text properties.
|
||||
|
||||
Accepts 'ansi and 'text-properties. nil means don't render colors.")
|
||||
|
||||
|
||||
;;
|
||||
;;; Library
|
||||
|
||||
;;;###autoload
|
||||
(defun doom--format (output)
|
||||
(if (string-empty-p (string-trim output))
|
||||
""
|
||||
(concat (make-string doom-format-indent 32)
|
||||
(replace-regexp-in-string
|
||||
"\n" (concat "\n" (make-string doom-format-indent 32))
|
||||
output t t))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom--format-print (output)
|
||||
(unless (string-empty-p output)
|
||||
(princ output)
|
||||
(when (or noninteractive (not (eq standard-output t)))
|
||||
(terpri)) ; newline
|
||||
t))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom--format-indent (width text &optional prefix)
|
||||
"Indent TEXT by WIDTH spaces. If ARGS, format TEXT with them."
|
||||
(with-temp-buffer
|
||||
(setq text (format "%s" text))
|
||||
(insert text)
|
||||
(indent-rigidly (point-min) (point-max) width)
|
||||
(when (stringp prefix)
|
||||
(when (> width 2)
|
||||
(goto-char (point-min))
|
||||
(beginning-of-line-text)
|
||||
(delete-char (- (length prefix)))
|
||||
(insert prefix)))
|
||||
(buffer-string)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom--format-autofill (&rest msgs)
|
||||
"Ensure MSG is split into lines no longer than `fill-column'."
|
||||
(with-temp-buffer
|
||||
(let ((fill-column 76))
|
||||
(dolist (line msgs)
|
||||
(when line
|
||||
(insert (format "%s" line))))
|
||||
(fill-region (point-min) (point-max))
|
||||
(buffer-string))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom--format-color (style format &rest args)
|
||||
"Apply STYLE to formatted MESSAGE with ARGS.
|
||||
|
||||
STYLE is a symbol that correlates to `doom-format-ansi-alist'.
|
||||
|
||||
In a noninteractive session, this wraps the result in ansi color codes.
|
||||
Otherwise, it maps colors to a term-color-* face."
|
||||
(let* ((code (cadr (assq style doom-format-ansi-alist)))
|
||||
(format (format "%s" format))
|
||||
(message (if args (apply #'format format args) format)))
|
||||
(unless code
|
||||
(error "%S is an invalid color" style))
|
||||
(pcase doom-format-backend
|
||||
(`ansi
|
||||
(format "\e[%dm%s\e[%dm" code message 0))
|
||||
(`text-properties
|
||||
(require 'term) ; piggyback on term's color faces
|
||||
(propertize
|
||||
message
|
||||
'face
|
||||
(append (get-text-property 0 'face format)
|
||||
(cond ((>= code 40)
|
||||
`(:background ,(caddr (assq style doom-format-ansi-alist))))
|
||||
((>= code 30)
|
||||
`(:foreground ,(face-foreground (caddr (assq style doom-format-ansi-alist)))))
|
||||
((cddr (assq style doom-format-ansi-alist)))))))
|
||||
(_ message))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom--format-class (class format &rest args)
|
||||
"Apply CLASS to formatted format with ARGS.
|
||||
|
||||
CLASS is derived from `doom-format-class-alist', and can contain any arbitrary,
|
||||
transformative logic."
|
||||
(let (fn)
|
||||
(cond ((setq fn (cdr (assq class doom-format-class-alist)))
|
||||
(if (functionp fn)
|
||||
(apply fn format args)
|
||||
(error "%s does not have a function" class)))
|
||||
(args (apply #'format format args))
|
||||
(format))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom--format-apply (forms &optional sub)
|
||||
"Replace color-name functions with calls to `doom--format-color'."
|
||||
(cond ((null forms) nil)
|
||||
((listp forms)
|
||||
(append (cond ((not (symbolp (car forms)))
|
||||
(list (doom--format-apply (car forms))))
|
||||
(sub
|
||||
(list (car forms)))
|
||||
((assq (car forms) doom-format-ansi-alist)
|
||||
`(doom--format-color ',(car forms)))
|
||||
((assq (car forms) doom-format-class-alist)
|
||||
`(doom--format-class ',(car forms)))
|
||||
((list (car forms))))
|
||||
(doom--format-apply (cdr forms) t)
|
||||
nil))
|
||||
(forms)))
|
||||
|
||||
;;;###autoload
|
||||
(defmacro format! (message &rest args)
|
||||
"An alternative to `format' that understands (color ...) and converts them
|
||||
into faces or ANSI codes depending on the type of sesssion we're in."
|
||||
`(doom--format (format ,@(doom--format-apply `(,message ,@args)))))
|
||||
|
||||
;;;###autoload
|
||||
(defmacro print-group! (&rest body)
|
||||
"Indents any `print!' or `format!' output within BODY."
|
||||
`(let ((doom-format-indent (+ doom-format-indent-increment doom-format-indent)))
|
||||
,@body))
|
||||
|
||||
;;;###autoload
|
||||
(defmacro print! (message &rest args)
|
||||
"Uses `message' in interactive sessions and `princ' otherwise (prints to
|
||||
standard out).
|
||||
|
||||
Can be colored using (color ...) blocks:
|
||||
|
||||
(print! \"Hello %s\" (bold (blue \"How are you?\")))
|
||||
(print! \"Hello %s\" (red \"World\"))
|
||||
(print! (green \"Great %s!\") \"success\")
|
||||
|
||||
Uses faces in interactive sessions and ANSI codes otherwise."
|
||||
`(doom--format-print (format! ,message ,@args)))
|
||||
|
||||
;;;###autoload
|
||||
(defmacro insert! (message &rest args)
|
||||
"Like `insert'; the last argument must be format arguments for MESSAGE.
|
||||
|
||||
\(fn MESSAGE... ARGS)"
|
||||
`(insert (format! (concat ,message ,@(butlast args))
|
||||
,@(car (last args)))))
|
||||
|
||||
;;;###autoload
|
||||
(defmacro error! (message &rest args)
|
||||
"Like `error', but with the power of `format!'."
|
||||
`(error (format! ,message ,@args)))
|
||||
|
||||
;;;###autoload
|
||||
(defmacro user-error! (message &rest args)
|
||||
"Like `user-error', but with the power of `format!'."
|
||||
`(user-error (format! ,message ,@args)))
|
||||
@@ -3,9 +3,6 @@
|
||||
(defvar doom--help-major-mode-module-alist
|
||||
'((dockerfile-mode :tools docker)
|
||||
(agda2-mode :lang agda)
|
||||
(haxor-mode :lang assembly)
|
||||
(mips-mode :lang assembly)
|
||||
(nasm-mode :lang assembly)
|
||||
(c-mode :lang cc)
|
||||
(c++-mode :lang cc)
|
||||
(objc++-mode :lang cc)
|
||||
@@ -34,6 +31,7 @@
|
||||
(js2-mode :lang javascript)
|
||||
(rjsx-mode :lang javascript)
|
||||
(typescript-mode :lang javascript)
|
||||
(typescript-tsx-mode :lang javascript)
|
||||
(coffee-mode :lang javascript)
|
||||
(julia-mode :lang julia)
|
||||
(kotlin-mode :lang kotlin)
|
||||
@@ -41,13 +39,14 @@
|
||||
(LaTeX-mode :lang latex)
|
||||
(ledger-mode :lang ledger)
|
||||
(lua-mode :lang lua)
|
||||
(moonscript-mode :lang lua)
|
||||
(markdown-mode :lang markdown)
|
||||
(gfm-mode :lang markdown)
|
||||
(nim-mode :lang nim)
|
||||
(nix-mode :lang nix)
|
||||
(taureg-mode :lang ocaml)
|
||||
(org-mode :lang org)
|
||||
(perl-mode :lang perl)
|
||||
(raku-mode :lang raku)
|
||||
(php-mode :lang php)
|
||||
(hack-mode :lang php)
|
||||
(plantuml-mode :lang plantuml)
|
||||
@@ -55,9 +54,10 @@
|
||||
(python-mode :lang python)
|
||||
(restclient-mode :lang rest)
|
||||
(ruby-mode :lang ruby)
|
||||
(enh-ruby-mode :lang ruby)
|
||||
(rust-mode :lang rust)
|
||||
(rustic-mode :lang rust)
|
||||
(scala-mode :lang scala)
|
||||
(scheme-mode :lang scheme)
|
||||
(sh-mode :lang sh)
|
||||
(swift-mode :lang swift)
|
||||
(web-mode :lang web)
|
||||
@@ -96,7 +96,7 @@ the current major-modea.")
|
||||
"Get information on an active minor mode. Use `describe-minor-mode' for a
|
||||
selection of all minor-modes, active or not."
|
||||
(interactive
|
||||
(list (completing-read "Minor mode: " (doom-active-minor-modes))))
|
||||
(list (completing-read "Describe active mode: " (doom-active-minor-modes))))
|
||||
(let ((symbol
|
||||
(cond ((stringp mode) (intern mode))
|
||||
((symbolp mode) mode)
|
||||
@@ -105,21 +105,6 @@ selection of all minor-modes, active or not."
|
||||
(helpful-function symbol)
|
||||
(helpful-variable symbol))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/describe-symbol (symbol)
|
||||
"Show help for SYMBOL, a variable, function or macro."
|
||||
(interactive
|
||||
(list (helpful--read-symbol "Symbol: " #'helpful--bound-p)))
|
||||
(let* ((sym (intern-soft symbol))
|
||||
(bound (boundp sym))
|
||||
(fbound (fboundp sym)))
|
||||
(cond ((and sym bound (not fbound))
|
||||
(helpful-variable sym))
|
||||
((and sym fbound (not bound))
|
||||
(helpful-callable sym))
|
||||
((apropos (format "^%s\$" symbol)))
|
||||
((apropos (format "%s" symbol))))))
|
||||
|
||||
|
||||
;;
|
||||
;;; Documentation commands
|
||||
@@ -130,7 +115,8 @@ selection of all minor-modes, active or not."
|
||||
(require 'org)
|
||||
(let* ((default-directory doom-docs-dir)
|
||||
(org-agenda-files (mapcar #'expand-file-name (doom-enlist files)))
|
||||
(depth (if (integerp depth) depth)))
|
||||
(depth (if (integerp depth) depth))
|
||||
(org-inhibit-startup t))
|
||||
(message "Loading search results...")
|
||||
(unwind-protect
|
||||
(delq
|
||||
@@ -150,7 +136,8 @@ selection of all minor-modes, active or not."
|
||||
(list (or (+org-get-global-property "TITLE")
|
||||
(file-relative-name (buffer-file-name)))))
|
||||
path
|
||||
(list (replace-regexp-in-string org-link-any-re "\\4" text)))
|
||||
(when text
|
||||
(list (replace-regexp-in-string org-link-any-re "\\4" text))))
|
||||
" > ")
|
||||
tags)
|
||||
" ")
|
||||
@@ -196,7 +183,7 @@ selection of all minor-modes, active or not."
|
||||
(find-file (expand-file-name "index.org" doom-docs-dir)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/help-search (&optional initial-input)
|
||||
(defun doom/help-search-headings (&optional initial-input)
|
||||
"Search Doom's documentation and jump to a headline."
|
||||
(interactive)
|
||||
(doom-completing-read-org-headings
|
||||
@@ -213,7 +200,26 @@ selection of all minor-modes, active or not."
|
||||
(doom--help-modules-list))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/help-news-search (&optional initial-input)
|
||||
(defun doom/help-search (&optional initial-input)
|
||||
"Preform a text search on all of Doom's documentation."
|
||||
(interactive)
|
||||
(funcall (cond ((fboundp '+ivy-file-search)
|
||||
#'+ivy-file-search)
|
||||
((fboundp '+helm-file-search)
|
||||
#'+helm-file-search)
|
||||
((rgrep
|
||||
(read-regexp
|
||||
"Search for" (or initial-input 'grep-tag-default)
|
||||
'grep-regexp-history)
|
||||
"*.org" doom-emacs-dir)
|
||||
#'ignore))
|
||||
:query initial-input
|
||||
:args '("-g" "*.org")
|
||||
:in doom-emacs-dir
|
||||
:prompt "Search documentation for: "))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/help-search-news (&optional initial-input)
|
||||
"Search headlines in Doom's newsletters."
|
||||
(interactive)
|
||||
(doom-completing-read-org-headings
|
||||
@@ -316,13 +322,7 @@ without needing to check if they are available."
|
||||
readme-path)))
|
||||
|
||||
(defun doom--help-current-module-str ()
|
||||
(cond ((and buffer-file-name
|
||||
(eq major-mode 'emacs-lisp-mode)
|
||||
(file-in-directory-p buffer-file-name doom-private-dir)
|
||||
(save-excursion (goto-char (point-min))
|
||||
(re-search-forward "^\\s-*(doom! " nil t))
|
||||
(thing-at-point 'sexp t)))
|
||||
((save-excursion
|
||||
(cond ((save-excursion
|
||||
(require 'smartparens)
|
||||
(ignore-errors
|
||||
(sp-beginning-of-sexp)
|
||||
@@ -341,11 +341,14 @@ without needing to check if they are available."
|
||||
(symbol-name (cadr mod)))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/help-modules (category module)
|
||||
(defun doom/help-modules (category module &optional visit-dir)
|
||||
"Open the documentation for a Doom module.
|
||||
|
||||
CATEGORY is a keyword and MODULE is a symbol. e.g. :editor and 'evil.
|
||||
|
||||
If VISIT-DIR is non-nil, visit the module's directory rather than its
|
||||
documentation.
|
||||
|
||||
Automatically selects a) the module at point (in private init files), b) the
|
||||
module derived from a `featurep!' or `require!' call, c) the module that the
|
||||
current file is in, or d) the module associated with the current major mode (see
|
||||
@@ -354,7 +357,8 @@ current file is in, or d) the module associated with the current major mode (see
|
||||
(mapcar #'intern
|
||||
(split-string
|
||||
(completing-read "Describe module: "
|
||||
(doom--help-modules-list) nil t nil nil
|
||||
(doom--help-modules-list)
|
||||
nil t nil nil
|
||||
(doom--help-current-module-str))
|
||||
" " t)))
|
||||
(cl-check-type category symbol)
|
||||
@@ -362,14 +366,19 @@ current file is in, or d) the module associated with the current major mode (see
|
||||
(cl-destructuring-bind (module-string path)
|
||||
(or (assoc (format "%s %s" category module) (doom--help-modules-list))
|
||||
(user-error "'%s %s' is not a valid module" category module))
|
||||
(setq module-string (substring-no-properties module-string))
|
||||
(unless (file-readable-p path)
|
||||
(error "Can't find or read %S module at %S" module-string path))
|
||||
(if (not (file-directory-p path))
|
||||
(find-file path)
|
||||
(if (y-or-n-p (format "The %S module has no README file. Explore its directory?"
|
||||
module-string))
|
||||
(doom-project-browse path)
|
||||
(user-error "Aborted module lookup")))))
|
||||
(cond ((not (file-directory-p path))
|
||||
(if visit-dir
|
||||
(doom-project-browse (file-name-directory path))
|
||||
(find-file path)))
|
||||
(visit-dir
|
||||
(doom-project-browse path))
|
||||
((y-or-n-p (format "The %S module has no README file. Explore its directory?"
|
||||
module-string))
|
||||
(doom-project-browse (file-name-directory path)))
|
||||
((user-error "Aborted module lookup")))))
|
||||
|
||||
|
||||
;;
|
||||
@@ -419,8 +428,8 @@ If prefix arg is present, refresh the cache."
|
||||
(let ((guess (or (function-called-at-point)
|
||||
(symbol-at-point))))
|
||||
(require 'finder-inf nil t)
|
||||
(require 'core-packages)
|
||||
(doom-initialize-packages)
|
||||
(require 'package)
|
||||
(require 'straight)
|
||||
(let ((packages (delete-dups
|
||||
(append (mapcar #'car package-alist)
|
||||
(mapcar #'car package--builtins)
|
||||
@@ -432,9 +441,9 @@ If prefix arg is present, refresh the cache."
|
||||
(list
|
||||
(intern
|
||||
(completing-read (if guess
|
||||
(format "Select package to search for (default %s): "
|
||||
(format "Select Doom package to search for (default %s): "
|
||||
guess)
|
||||
"Describe package: ")
|
||||
"Describe Doom package: ")
|
||||
packages nil t nil nil
|
||||
(if guess (symbol-name guess))))))))
|
||||
(require 'core-packages)
|
||||
@@ -462,27 +471,44 @@ If prefix arg is present, refresh the cache."
|
||||
(insert (symbol-name package) "\n")
|
||||
|
||||
(package--print-help-section "Source")
|
||||
(insert (or (pcase (doom-package-backend package)
|
||||
(`straight
|
||||
(format! "Straight (%s)\n%s"
|
||||
(let ((default-directory (straight--build-dir (symbol-name package))))
|
||||
(cdr
|
||||
(doom-call-process "git" "log" "-1" "--format=%D %h %ci")))
|
||||
(indent
|
||||
13 (string-trim
|
||||
(pp-to-string
|
||||
(doom-package-build-recipe package))))))
|
||||
(`elpa
|
||||
(format "[M]ELPA %s" (doom--package-url package)))
|
||||
(`builtin "Built-in")
|
||||
(_ (abbreviate-file-name (symbol-file package))))
|
||||
"unknown")
|
||||
"\n")
|
||||
(pcase (doom-package-backend package)
|
||||
(`straight
|
||||
(insert "Straight\n")
|
||||
(package--print-help-section "Pinned")
|
||||
(insert (if-let (pin (plist-get (cdr (assq package doom-packages)) :pin))
|
||||
pin
|
||||
"unpinned")
|
||||
"\n")
|
||||
(package--print-help-section "Build")
|
||||
(insert (let ((default-directory (straight--repos-dir (symbol-name package))))
|
||||
(cdr
|
||||
(doom-call-process "git" "log" "-1" "--format=%D %h %ci")))
|
||||
"\n")
|
||||
(let ((recipe (doom-package-build-recipe package)))
|
||||
(insert (format! "%s\n"
|
||||
(indent 13
|
||||
(string-trim (pp-to-string recipe)))))
|
||||
|
||||
(when (gethash (symbol-name package) straight--build-cache)
|
||||
(package--print-help-section "Homepage")
|
||||
(insert (doom--package-url package))))
|
||||
(`elpa (insert "[M]ELPA " (doom--package-url package)))
|
||||
(`builtin (insert "Built-in"))
|
||||
(`other (insert
|
||||
(abbreviate-file-name
|
||||
(or (symbol-file package)
|
||||
(locate-library (symbol-name package))))))
|
||||
(_ (insert "Not installed")))
|
||||
(insert "\n")
|
||||
|
||||
(when-let
|
||||
(modules
|
||||
(if (gethash (symbol-name package) straight--build-cache)
|
||||
(doom-package-get package :modules)
|
||||
(plist-get (cdr (assq package (doom-package-list 'all)))
|
||||
:modules)))
|
||||
(package--print-help-section "Modules")
|
||||
(insert "Declared by the following Doom modules:\n")
|
||||
(dolist (m (doom-package-get package :modules))
|
||||
(dolist (m modules)
|
||||
(insert indent)
|
||||
(doom--help-package-insert-button
|
||||
(format "%s %s" (car m) (or (cdr m) ""))
|
||||
@@ -512,7 +538,7 @@ If prefix arg is present, refresh the cache."
|
||||
(insert "\n\n")))))
|
||||
|
||||
(defvar doom--package-cache nil)
|
||||
(defun doom--package-list ()
|
||||
(defun doom--package-list (&optional prompt)
|
||||
(let* ((guess (or (function-called-at-point)
|
||||
(symbol-at-point))))
|
||||
(require 'finder-inf nil t)
|
||||
@@ -528,10 +554,11 @@ If prefix arg is present, refresh the cache."
|
||||
(setq doom--package-cache packages)
|
||||
(unless (memq guess packages)
|
||||
(setq guess nil))
|
||||
(intern (completing-read (if guess
|
||||
(format "Select package to search for (default %s): "
|
||||
guess)
|
||||
"Describe package: ")
|
||||
(intern (completing-read (or prompt
|
||||
(if guess
|
||||
(format "Select package to search for (default %s): "
|
||||
guess)
|
||||
"Describe package: "))
|
||||
packages nil t nil nil
|
||||
(if guess (symbol-name guess)))))))
|
||||
|
||||
@@ -578,7 +605,7 @@ If prefix arg is present, refresh the cache."
|
||||
|
||||
This only searches `doom-emacs-dir' (typically ~/.emacs.d) and does not include
|
||||
config blocks in your private config."
|
||||
(interactive (list (doom--package-list)))
|
||||
(interactive (list (doom--package-list "Find package config: ")))
|
||||
(cl-destructuring-bind (file line _match)
|
||||
(split-string
|
||||
(completing-read
|
||||
@@ -592,55 +619,48 @@ config blocks in your private config."
|
||||
(recenter)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/help-package-homepage (package)
|
||||
"Open PACKAGE's repo or homepage in your browser."
|
||||
(interactive (list (doom--package-list)))
|
||||
(browse-url (doom--package-url package)))
|
||||
(defalias 'doom/help-package-homepage #'straight-visit-package-website)
|
||||
|
||||
(defun doom--help-search-prompt (prompt)
|
||||
(let ((query (doom-thing-at-point-or-region)))
|
||||
(if (featurep 'counsel)
|
||||
query
|
||||
(read-string prompt query 'git-grep query))))
|
||||
|
||||
(defvar counsel-rg-base-command)
|
||||
(defun doom--help-search (dirs query prompt)
|
||||
;; REVIEW Replace with deadgrep
|
||||
(unless (executable-find "rg")
|
||||
(user-error "Can't find ripgrep on your system"))
|
||||
(if (fboundp 'counsel-rg)
|
||||
(let ((counsel-rg-base-command (append counsel-rg-base-command dirs)))
|
||||
(counsel-rg query nil "-Lz" prompt))
|
||||
;; TODO Add helm support?
|
||||
(grep-find
|
||||
(string-join
|
||||
(append (list "rg" "-L" "--search-zip" "--no-heading" "--color=never"
|
||||
(shell-quote-argument query))
|
||||
(mapcar #'shell-quote-argument dirs))
|
||||
" "))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/help-search-load-path (query)
|
||||
"Perform a text search on your `load-path'.
|
||||
Uses the symbol at point or the current selection, if available."
|
||||
(interactive
|
||||
(let ((query
|
||||
;; TODO Generalize this later; into something the lookup module and
|
||||
;; project search commands could as well
|
||||
(if (use-region-p)
|
||||
(buffer-substring-no-properties (region-beginning) (region-end))
|
||||
(or (symbol-name (symbol-at-point)) ""))))
|
||||
(list (read-string
|
||||
(format "Search load-path (default: %s): " query)
|
||||
nil 'git-grep query))))
|
||||
;; REVIEW Replace with deadgrep
|
||||
(grep-find
|
||||
(mapconcat
|
||||
#'shell-quote-argument
|
||||
(append (list "rg" "-L" "--search-zip" "--no-heading" "--color=never" query)
|
||||
(cl-remove-if-not #'file-directory-p load-path))
|
||||
" ")))
|
||||
(list (doom--help-search-prompt "Search load-path: ")))
|
||||
(doom--help-search (cl-remove-if-not #'file-directory-p load-path)
|
||||
query "Search load-path: "))
|
||||
|
||||
;; TODO factor our the duplicate code between this and the above
|
||||
;;;###autoload
|
||||
(defun doom/help-search-loaded-files (query)
|
||||
"Perform a text search on your `load-path'.
|
||||
Uses the symbol at point or the current selection, if available."
|
||||
(interactive
|
||||
(let ((query
|
||||
;; TODO Generalize this later; into something the lookup module and
|
||||
;; project search commands could as well.
|
||||
(if (use-region-p)
|
||||
(buffer-substring-no-properties (region-beginning) (region-end))
|
||||
(or (symbol-name (symbol-at-point)) ""))))
|
||||
(list (read-string
|
||||
(format "Search load-path (default: %s): " query)
|
||||
nil 'git-grep query))))
|
||||
(unless (executable-find "rg")
|
||||
(user-error "Can't find ripgrep on your system"))
|
||||
(require 'elisp-refs)
|
||||
;; REVIEW Replace with deadgrep
|
||||
(grep-find
|
||||
(mapconcat
|
||||
#'shell-quote-argument
|
||||
(append (list "rg" "-L" "--search-zip" "--no-heading" "--color=never" query)
|
||||
(cl-remove-if-not #'file-directory-p (elisp-refs--loaded-paths)))
|
||||
" ")))
|
||||
(list (doom--help-search-prompt "Search loaded files: ")))
|
||||
(doom--help-search
|
||||
(cl-loop for (file . _) in (cl-remove-if-not #'stringp load-history :key #'car)
|
||||
for filebase = (file-name-sans-extension file)
|
||||
if (file-exists-p! (format "%s.el" filebase))
|
||||
collect it)
|
||||
query "Search loaded files: "))
|
||||
|
||||
@@ -1,198 +1,5 @@
|
||||
;;; core/autoload/packages.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;
|
||||
;;; Package metadata
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-get (package &optional prop nil-value)
|
||||
"Returns PACKAGE's `package!' recipe from `doom-packages'."
|
||||
(let ((plist (cdr (assq package doom-packages))))
|
||||
(if prop
|
||||
(if (plist-member plist prop)
|
||||
(plist-get plist prop)
|
||||
nil-value)
|
||||
plist)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-recipe (package &optional prop nil-value)
|
||||
"Returns the `straight' recipe PACKAGE was registered with."
|
||||
(let ((plist (gethash (symbol-name package) straight--recipe-cache)))
|
||||
(if prop
|
||||
(if (plist-member plist prop)
|
||||
(plist-get plist prop)
|
||||
nil-value)
|
||||
plist)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-build-recipe (package &optional prop nil-value)
|
||||
"Returns the `straight' recipe PACKAGE was installed with."
|
||||
(let ((plist (nth 2 (gethash (symbol-name package) straight--build-cache))))
|
||||
(if prop
|
||||
(if (plist-member plist prop)
|
||||
(plist-get plist prop)
|
||||
nil-value)
|
||||
plist)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-build-time (package)
|
||||
"TODO"
|
||||
(car (gethash (symbol-name package) straight--build-cache)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-dependencies (package &optional recursive noerror)
|
||||
"Return a list of dependencies for a package."
|
||||
(let ((deps (nth 1 (gethash (symbol-name package) straight--build-cache))))
|
||||
(if recursive
|
||||
(nconc deps (mapcan (lambda (dep) (doom-package-dependencies dep t t))
|
||||
deps))
|
||||
deps)))
|
||||
|
||||
(defun doom-package-depending-on (package &optional noerror)
|
||||
"Return a list of packages that depend on the package named NAME."
|
||||
(cl-check-type name symbol)
|
||||
;; can't get dependencies for built-in packages
|
||||
(unless (or (doom-package-build-recipe name)
|
||||
noerror)
|
||||
(error "Couldn't find %s, is it installed?" name))
|
||||
(cl-loop for pkg in (hash-table-keys straight--build-cache)
|
||||
for deps = (doom-package-dependencies pkg)
|
||||
if (memq package deps)
|
||||
collect pkg
|
||||
and append (doom-package-depending-on pkg t)))
|
||||
|
||||
|
||||
;;
|
||||
;;; Predicate functions
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-built-in-p (package)
|
||||
"Return non-nil if PACKAGE (a symbol) is built-in."
|
||||
(eq (doom-package-build-recipe package :type)
|
||||
'built-in))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-installed-p (package)
|
||||
"Return non-nil if PACKAGE (a symbol) is installed."
|
||||
(file-directory-p (straight--build-dir (symbol-name package))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-registered-p (package)
|
||||
"Return non-nil if PACKAGE (a symbol) has been registered with `package!'.
|
||||
|
||||
Excludes packages that have a non-nil :built-in property."
|
||||
(when-let (plist (doom-package-get package))
|
||||
(not (plist-get plist :ignore))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-private-p (package)
|
||||
"Return non-nil if PACKAGE was installed by the user's private config."
|
||||
(assq :private (doom-package-get package :modules)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-protected-p (package)
|
||||
"Return non-nil if PACKAGE is protected.
|
||||
|
||||
A protected package cannot be deleted and will be auto-installed if missing."
|
||||
(memq package doom-core-packages))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-core-p (package)
|
||||
"Return non-nil if PACKAGE is a core Doom package."
|
||||
(or (doom-package-protected-p package)
|
||||
(assq :core (doom-package-get package :modules))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-backend (package)
|
||||
"Return 'straight, 'builtin, 'elpa or 'other, depending on how PACKAGE is
|
||||
installed."
|
||||
(cond ((gethash (symbol-name package) straight--build-cache)
|
||||
'straight)
|
||||
((or (doom-package-built-in-p package)
|
||||
(assq package package--builtins))
|
||||
'builtin)
|
||||
((assq package package-alist)
|
||||
'elpa)
|
||||
('other)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-different-recipe-p (name)
|
||||
"Return t if a package named NAME (a symbol) has a different recipe than it
|
||||
was installed with."
|
||||
(cl-check-type name symbol)
|
||||
;; TODO
|
||||
;; (when (doom-package-installed-p name)
|
||||
;; (when-let* ((doom-recipe (assq name doom-packages))
|
||||
;; (install-recipe (doom-package-recipe)))
|
||||
;; (not (equal (cdr quelpa-recipe)
|
||||
;; (cdr (plist-get (cdr doom-recipe) :recipe))))))
|
||||
)
|
||||
|
||||
|
||||
;;
|
||||
;;; Package list getters
|
||||
|
||||
(defun doom--read-module-packages-file (file &optional noeval noerror)
|
||||
(with-temp-buffer ; prevent buffer-local settings from propagating
|
||||
(condition-case e
|
||||
(if (not noeval)
|
||||
(load file noerror t t)
|
||||
(when (file-readable-p file)
|
||||
(insert-file-contents file)
|
||||
(delay-mode-hooks (emacs-lisp-mode))
|
||||
(while (search-forward "(package! " nil t)
|
||||
(save-excursion
|
||||
(goto-char (match-beginning 0))
|
||||
(unless (let ((ppss (syntax-ppss)))
|
||||
(or (nth 3 ppss)
|
||||
(nth 4 ppss)))
|
||||
(cl-destructuring-bind (name . plist)
|
||||
(cdr (sexp-at-point))
|
||||
(push (cons
|
||||
name (plist-put
|
||||
plist :modules
|
||||
(list (doom-module-from-path file))))
|
||||
doom-packages)))))))
|
||||
((debug error)
|
||||
(signal 'doom-package-error
|
||||
(list (doom-module-from-path file)
|
||||
e))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-list (&optional all-p)
|
||||
"Retrieve a list of explicitly declared packages from enabled modules.
|
||||
|
||||
This excludes core packages listed in `doom-core-packages'.
|
||||
|
||||
If ALL-P, gather packages unconditionally across all modules, including disabled
|
||||
ones."
|
||||
(let ((doom-interactive-mode t)
|
||||
(doom-modules (doom-modules))
|
||||
doom-packages
|
||||
doom-disabled-packages)
|
||||
(doom--read-module-packages-file
|
||||
(doom-path doom-core-dir "packages.el") all-p t)
|
||||
(let ((private-packages (doom-path doom-private-dir "packages.el")))
|
||||
(unless all-p
|
||||
;; We load the private packages file twice to ensure disabled packages
|
||||
;; are seen ASAP, and a second time to ensure privately overridden
|
||||
;; packages are properly overwritten.
|
||||
(doom--read-module-packages-file private-packages nil t))
|
||||
(if all-p
|
||||
(mapc #'doom--read-module-packages-file
|
||||
(doom-files-in doom-modules-dir
|
||||
:depth 2
|
||||
:match "/packages\\.el$"))
|
||||
(cl-loop for key being the hash-keys of doom-modules
|
||||
for path = (doom-module-path (car key) (cdr key) "packages.el")
|
||||
for doom--current-module = key
|
||||
do (doom--read-module-packages-file path nil t)))
|
||||
(doom--read-module-packages-file private-packages all-p t))
|
||||
(nreverse doom-packages)))
|
||||
|
||||
|
||||
;;
|
||||
;;; Main functions
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/reload-packages ()
|
||||
"Reload `doom-packages', `package' and `quelpa'."
|
||||
@@ -201,3 +8,190 @@ ones."
|
||||
(message "Reloading packages")
|
||||
(doom-initialize-packages t)
|
||||
(message "Reloading packages...DONE"))
|
||||
|
||||
|
||||
;;
|
||||
;;; Bump commands
|
||||
|
||||
(defun doom--package-full-recipe (package plist)
|
||||
(doom-plist-merge
|
||||
(plist-get plist :recipe)
|
||||
(or (cdr (straight-recipes-retrieve package))
|
||||
(plist-get (cdr (assq package doom-packages))
|
||||
:recipe))))
|
||||
|
||||
(defun doom--package-to-bump-string (package plist)
|
||||
"Return a PACKAGE and its PLIST in 'username/repo@commit' format."
|
||||
(format "%s@%s"
|
||||
(plist-get (doom--package-full-recipe package plist) :repo)
|
||||
(substring-no-properties (plist-get plist :pin) 0 7)))
|
||||
|
||||
(defun doom--package-at-point (&optional point)
|
||||
"Return the package and plist from the (package! PACKAGE PLIST...) at point."
|
||||
(save-match-data
|
||||
(save-excursion
|
||||
(and point (goto-char point))
|
||||
(while (and (or (atom (sexp-at-point))
|
||||
(doom-point-in-string-or-comment-p))
|
||||
(search-backward "(" nil t)))
|
||||
(when (eq (car-safe (sexp-at-point)) 'package!)
|
||||
(cl-destructuring-bind (beg . end)
|
||||
(bounds-of-thing-at-point 'sexp)
|
||||
(let* ((doom-packages nil)
|
||||
(buffer-file-name
|
||||
(or buffer-file-name
|
||||
(bound-and-true-p org-src-source-file-name)))
|
||||
(package (eval (sexp-at-point) t)))
|
||||
(list :beg beg
|
||||
:end end
|
||||
:package (car package)
|
||||
:plist (cdr package))))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/bumpify-package-at-point ()
|
||||
"Convert `package!' call at point to a bump string."
|
||||
(interactive)
|
||||
(cl-destructuring-bind (&key package plist beg end)
|
||||
(doom--package-at-point)
|
||||
(when-let (str (doom--package-to-bump-string package plist))
|
||||
(goto-char beg)
|
||||
(delete-region beg end)
|
||||
(insert str))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/bumpify-packages-in-buffer ()
|
||||
"Convert all `package!' calls in buffer into bump strings."
|
||||
(interactive)
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(while (search-forward "(package!" nil t)
|
||||
(unless (doom-point-in-string-or-comment-p)
|
||||
(doom/bumpify-package-at-point)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/bump-package-at-point (&optional select)
|
||||
"Inserts or updates a `:pin' for the `package!' statement at point.
|
||||
Grabs the latest commit id of the package using 'git'."
|
||||
(interactive "P")
|
||||
(doom-initialize-packages)
|
||||
(cl-destructuring-bind (&key package plist beg end)
|
||||
(or (doom--package-at-point)
|
||||
(user-error "Not on a `package!' call"))
|
||||
(let* ((recipe (doom--package-full-recipe package plist))
|
||||
(branch (or (plist-get recipe :branch)
|
||||
straight-vc-git-default-branch))
|
||||
(oldid (or (plist-get plist :pin)
|
||||
(doom-package-get package :pin)))
|
||||
(url (straight-vc-git--destructure recipe (upstream-repo upstream-host)
|
||||
(straight-vc-git--encode-url upstream-repo upstream-host)))
|
||||
(id (or (when url
|
||||
(cdr (doom-call-process
|
||||
"git" "ls-remote" url
|
||||
(unless select
|
||||
(or branch straight-vc-git-default-branch)))))
|
||||
(user-error "Couldn't find a recipe for %s" package)))
|
||||
(id (car (split-string
|
||||
(if select
|
||||
(completing-read "Commit: " (split-string id "\n" t))
|
||||
id)))))
|
||||
(when (and oldid
|
||||
(plist-member plist :pin)
|
||||
(equal oldid id))
|
||||
(user-error "%s: no update necessary" package))
|
||||
(save-excursion
|
||||
(if (re-search-forward ":pin +\"\\([^\"]+\\)\"" end t)
|
||||
(replace-match id t t nil 1)
|
||||
(goto-char (1- end))
|
||||
(insert " :pin " (prin1-to-string id))))
|
||||
(cond ((not oldid)
|
||||
(message "%s: → %s" package (substring id 0 10)))
|
||||
((< (length oldid) (length id))
|
||||
(message "%s: extended to %s..." package id))
|
||||
((message "%s: %s → %s"
|
||||
package
|
||||
(substring oldid 0 10)
|
||||
(substring id 0 10)))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/bump-packages-in-buffer (&optional select)
|
||||
"Inserts or updates a `:pin' for the `package!' statement at point.
|
||||
Grabs the latest commit id of the package using 'git'."
|
||||
(interactive "P")
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(doom-initialize-packages)
|
||||
(let (packages)
|
||||
(while (search-forward "(package! " nil t)
|
||||
(unless (let ((ppss (syntax-ppss)))
|
||||
(or (nth 4 ppss)
|
||||
(nth 3 ppss)
|
||||
(save-excursion
|
||||
(and (goto-char (match-beginning 0))
|
||||
(not (plist-member (sexp-at-point) :pin))))))
|
||||
(condition-case e
|
||||
(push (doom/bump-package-at-point) packages)
|
||||
(user-error (message "%s" (error-message-string e))))))
|
||||
(if packages
|
||||
(message "Updated %d packages\n- %s" (length packages) (string-join packages "\n- "))
|
||||
(message "No packages to update")))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/bump-module (category &optional module select)
|
||||
"Bump packages in CATEGORY MODULE.
|
||||
If SELECT (prefix arg) is non-nil, prompt you to choose a specific commit for
|
||||
each package."
|
||||
(interactive
|
||||
(let* ((module (completing-read
|
||||
"Bump module: "
|
||||
(let ((modules (doom-module-list 'all)))
|
||||
(mapcar (lambda (m)
|
||||
(if (listp m)
|
||||
(format "%s %s" (car m) (cdr m))
|
||||
(format "%s" m)))
|
||||
(append '(:private :core)
|
||||
(delete-dups (mapcar #'car modules))
|
||||
modules)))
|
||||
nil t nil nil))
|
||||
(module (split-string module " " t)))
|
||||
(list (intern (car module))
|
||||
(ignore-errors (intern (cadr module)))
|
||||
current-prefix-arg)))
|
||||
(mapc (fn! ((cat . mod))
|
||||
(if-let (packages-file
|
||||
(pcase cat
|
||||
(:private (doom-glob doom-private-dir "packages.el"))
|
||||
(:core (doom-glob doom-core-dir "packages.el"))
|
||||
(_ (doom-module-locate-path cat mod "packages.el"))))
|
||||
(with-current-buffer
|
||||
(or (get-file-buffer packages-file)
|
||||
(find-file-noselect packages-file))
|
||||
(doom/bump-packages-in-buffer select)
|
||||
(save-buffer))
|
||||
(message "Module %s has no packages.el file" (cons cat mod))))
|
||||
(if module
|
||||
(list (cons category module))
|
||||
(cl-remove-if-not (lambda (m) (eq (car m) category))
|
||||
(append '((:core) (:private))
|
||||
(doom-module-list 'all))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/bump-package (package)
|
||||
"Bump PACKAGE in all modules that install it."
|
||||
(interactive
|
||||
(list (completing-read "Bump package: "
|
||||
(mapcar #'car (doom-package-list 'all)))))
|
||||
(let* ((packages (doom-package-list 'all))
|
||||
(modules (plist-get (alist-get package packages) :modules)))
|
||||
(unless modules
|
||||
(user-error "This package isn't installed by any Doom module"))
|
||||
(dolist (module modules)
|
||||
(when-let (packages-file (doom-module-locate-path (car module) (cdr module)))
|
||||
(doom/bump-module (car module) (cdr module))))))
|
||||
|
||||
|
||||
;;
|
||||
;;; Bump commits
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/commit-bumps ()
|
||||
(interactive))
|
||||
|
||||
@@ -35,24 +35,6 @@ list, the pair is destructured into (CAR . CDR)."
|
||||
"Delete PROP from PLIST in-place."
|
||||
`(setq ,plist (doom-plist-delete ,plist ,prop)))
|
||||
|
||||
;;;###autoload
|
||||
(defmacro with-plist! (plist props &rest body)
|
||||
"With props bound from PLIST to PROPS, evaluate BODY.
|
||||
|
||||
PROPS is a list of symbols. Each one is converted to a keyword and then its
|
||||
value is looked up in the PLIST and bound to the symbol for the duration of
|
||||
BODY."
|
||||
(declare (indent 2))
|
||||
(let ((plist-sym (make-symbol "plist")))
|
||||
`(let* ((,plist-sym ,plist)
|
||||
,@(cl-loop for prop in props
|
||||
collect
|
||||
`(,prop
|
||||
(plist-get
|
||||
,plist-sym
|
||||
,(doom-keyword-intern (symbol-name prop))))))
|
||||
,@body)))
|
||||
|
||||
|
||||
;;
|
||||
;;; Library
|
||||
@@ -66,7 +48,7 @@ BODY."
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-plist-merge (from-plist to-plist)
|
||||
"Destructively merge FROM-PLIST onto TO-PLIST"
|
||||
"Non-destructively merge FROM-PLIST onto TO-PLIST"
|
||||
(let ((plist (copy-sequence from-plist)))
|
||||
(while plist
|
||||
(plist-put! to-plist (pop plist) (pop plist)))
|
||||
@@ -83,11 +65,11 @@ BODY."
|
||||
p))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-plist-delete (plist prop)
|
||||
"Delete PROP from a copy of PLIST."
|
||||
(defun doom-plist-delete (plist &rest props)
|
||||
"Delete PROPS from a copy of PLIST."
|
||||
(let (p)
|
||||
(while plist
|
||||
(if (not (eq prop (car plist)))
|
||||
(if (not (memq (car plist) props))
|
||||
(plist-put! p (car plist) (nth 1 plist)))
|
||||
(setq plist (cddr plist)))
|
||||
p))
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
;;; core/autoload/projects.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defvar projectile-project-root nil)
|
||||
(defvar projectile-enable-caching)
|
||||
(defvar projectile-require-project-root)
|
||||
|
||||
;;;###autoload (autoload 'projectile-relevant-known-projects "projectile")
|
||||
|
||||
@@ -39,8 +41,7 @@ they are absolute."
|
||||
"Preforms `projectile-find-file' in a known project of your choosing."
|
||||
(interactive
|
||||
(list
|
||||
(completing-read "Find file in project: " (projectile-relevant-known-projects)
|
||||
nil nil nil nil (doom-project-root))))
|
||||
(completing-read "Find file in project: " (projectile-relevant-known-projects))))
|
||||
(unless (file-directory-p project-root)
|
||||
(error "Project directory '%s' doesn't exist" project-root))
|
||||
(doom-project-find-file project-root))
|
||||
@@ -50,8 +51,7 @@ they are absolute."
|
||||
"Preforms `find-file' in a known project of your choosing."
|
||||
(interactive
|
||||
(list
|
||||
(completing-read "Browse in project: " (projectile-relevant-known-projects)
|
||||
nil nil nil nil (doom-project-root))))
|
||||
(completing-read "Browse in project: " (projectile-relevant-known-projects))))
|
||||
(unless (file-directory-p project-root)
|
||||
(error "Project directory '%s' doesn't exist" project-root))
|
||||
(doom-project-browse project-root))
|
||||
@@ -99,11 +99,10 @@ If DIR is not a project, it will be indexed (but not cached)."
|
||||
(unless (file-readable-p dir)
|
||||
(error "Directory %S isn't readable" dir))
|
||||
(let* ((default-directory (file-truename (expand-file-name dir)))
|
||||
(project-root (doom-project-root default-directory))
|
||||
(projectile-project-root default-directory)
|
||||
(projectile-project-root (doom-project-root default-directory))
|
||||
(projectile-enable-caching projectile-enable-caching))
|
||||
(cond ((and project-root (file-equal-p project-root projectile-project-root))
|
||||
(unless (doom-project-p projectile-project-root)
|
||||
(cond ((and projectile-project-root (file-equal-p projectile-project-root default-directory))
|
||||
(unless (doom-project-p default-directory)
|
||||
;; Disable caching if this is not a real project; caching
|
||||
;; non-projects easily has the potential to inflate the projectile
|
||||
;; cache beyond reason.
|
||||
|
||||
@@ -8,9 +8,11 @@ Will be saved in `doom-scratch-dir'.")
|
||||
(defvar doom-scratch-dir (concat doom-etc-dir "scratch")
|
||||
"Where to save persistent scratch buffers.")
|
||||
|
||||
(defvar doom-scratch-buffer-major-mode nil
|
||||
"What major mode to use in scratch buffers. This can be one of the
|
||||
following:
|
||||
(defvar doom-scratch-initial-major-mode nil
|
||||
"What major mode to start fresh scratch buffers in.
|
||||
|
||||
Scratch buffers preserve their last major mode, however, so this only affects
|
||||
the first, fresh scratch buffer you create. This accepts:
|
||||
|
||||
t Inherits the major mode of the last buffer you had selected.
|
||||
nil Uses `fundamental-mode'
|
||||
@@ -21,43 +23,56 @@ following:
|
||||
|
||||
(defvar doom-scratch-current-project nil
|
||||
"The name of the project associated with the current scratch buffer.")
|
||||
(put 'doom-scratch-current-project 'permanent-local t)
|
||||
|
||||
(defvar doom-scratch-buffer-hook ()
|
||||
"The hooks to run after a scratch buffer is created.")
|
||||
|
||||
|
||||
(defun doom--load-persistent-scratch-buffer (name)
|
||||
(defun doom--load-persistent-scratch-buffer (project-name)
|
||||
(setq-local doom-scratch-current-project
|
||||
(or name
|
||||
(or project-name
|
||||
doom-scratch-default-file))
|
||||
(let ((scratch-file
|
||||
(expand-file-name doom-scratch-current-project
|
||||
(let ((smart-scratch-file
|
||||
(expand-file-name (concat doom-scratch-current-project ".el")
|
||||
doom-scratch-dir)))
|
||||
(make-directory doom-scratch-dir t)
|
||||
(when (file-readable-p scratch-file)
|
||||
(erase-buffer)
|
||||
(insert-file-contents scratch-file)
|
||||
(set-auto-mode)
|
||||
t)))
|
||||
(when (file-readable-p smart-scratch-file)
|
||||
(message "Reading %s" smart-scratch-file)
|
||||
(cl-destructuring-bind (content point mode)
|
||||
(with-temp-buffer
|
||||
(save-excursion (insert-file-contents smart-scratch-file))
|
||||
(read (current-buffer)))
|
||||
(erase-buffer)
|
||||
(funcall mode)
|
||||
(insert content)
|
||||
(goto-char point)
|
||||
t))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-scratch-buffer (&optional mode directory project-name)
|
||||
(defun doom-scratch-buffer (&optional dont-restore-p mode directory project-name)
|
||||
"Return a scratchpad buffer in major MODE."
|
||||
(with-current-buffer
|
||||
(get-buffer-create (if project-name
|
||||
(format "*doom:scratch (%s)*" project-name)
|
||||
"*doom:scratch*"))
|
||||
(setq default-directory directory)
|
||||
(unless doom-scratch-current-project
|
||||
(doom--load-persistent-scratch-buffer project-name)
|
||||
(when (and (eq major-mode 'fundamental-mode)
|
||||
(functionp mode))
|
||||
(funcall mode)))
|
||||
(cl-pushnew (current-buffer) doom-scratch-buffers)
|
||||
(add-hook 'kill-buffer-hook #'doom-persist-scratch-buffer-h nil 'local)
|
||||
(add-hook 'doom-switch-buffer-hook #'doom-persist-scratch-buffers-after-switch-h)
|
||||
(run-hooks 'doom-scratch-buffer-created-hook)
|
||||
(current-buffer)))
|
||||
(let* ((buffer-name (if project-name
|
||||
(format "*doom:scratch (%s)*" project-name)
|
||||
"*doom:scratch*"))
|
||||
(buffer (get-buffer buffer-name)))
|
||||
(with-current-buffer
|
||||
(or buffer (get-buffer-create buffer-name))
|
||||
(setq default-directory directory)
|
||||
(setq-local so-long--inhibited t)
|
||||
(if dont-restore-p
|
||||
(erase-buffer)
|
||||
(unless buffer
|
||||
(doom--load-persistent-scratch-buffer project-name)
|
||||
(when (and (eq major-mode 'fundamental-mode)
|
||||
(functionp mode))
|
||||
(funcall mode))))
|
||||
(cl-pushnew (current-buffer) doom-scratch-buffers)
|
||||
(add-transient-hook! 'doom-switch-buffer-hook (doom-persist-scratch-buffers-h))
|
||||
(add-transient-hook! 'doom-switch-window-hook (doom-persist-scratch-buffers-h))
|
||||
(add-hook 'kill-buffer-hook #'doom-persist-scratch-buffer-h nil 'local)
|
||||
(run-hooks 'doom-scratch-buffer-created-hook)
|
||||
(current-buffer))))
|
||||
|
||||
|
||||
;;
|
||||
@@ -66,11 +81,18 @@ following:
|
||||
;;;###autoload
|
||||
(defun doom-persist-scratch-buffer-h ()
|
||||
"Save the current buffer to `doom-scratch-dir'."
|
||||
(write-region
|
||||
(point-min) (point-max)
|
||||
(expand-file-name (or doom-scratch-current-project
|
||||
doom-scratch-default-file)
|
||||
doom-scratch-dir)))
|
||||
(let ((content (buffer-substring-no-properties (point-min) (point-max)))
|
||||
(point (point))
|
||||
(mode major-mode))
|
||||
(with-temp-file
|
||||
(expand-file-name (concat (or doom-scratch-current-project
|
||||
doom-scratch-default-file)
|
||||
".el")
|
||||
doom-scratch-dir)
|
||||
(prin1 (list content
|
||||
point
|
||||
mode)
|
||||
(current-buffer)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-persist-scratch-buffers-h ()
|
||||
@@ -89,62 +111,66 @@ following:
|
||||
(remove-hook 'doom-switch-buffer-hook #'doom-persist-scratch-buffers-after-switch-h)))
|
||||
|
||||
;;;###autoload
|
||||
(unless noninteractive
|
||||
(when doom-interactive-p
|
||||
(add-hook 'kill-emacs-hook #'doom-persist-scratch-buffers-h))
|
||||
|
||||
|
||||
;;
|
||||
;;; Commands
|
||||
|
||||
(defvar projectile-enable-caching)
|
||||
;;;###autoload
|
||||
(defun doom/open-scratch-buffer (&optional arg project-p)
|
||||
"Opens the (persistent) scratch buffer in a popup.
|
||||
(defun doom/open-scratch-buffer (&optional arg project-p same-window-p)
|
||||
"Pop up a persistent scratch buffer.
|
||||
|
||||
If passed the prefix ARG, switch to it in the current window.
|
||||
If passed the prefix ARG, do not restore the last scratch buffer.
|
||||
If PROJECT-P is non-nil, open a persistent scratch buffer associated with the
|
||||
current project."
|
||||
(interactive "P")
|
||||
(let (projectile-enable-caching)
|
||||
(funcall
|
||||
(if arg
|
||||
(if same-window-p
|
||||
#'switch-to-buffer
|
||||
#'pop-to-buffer)
|
||||
(doom-scratch-buffer
|
||||
(cond ((eq doom-scratch-buffer-major-mode t)
|
||||
arg
|
||||
(cond ((eq doom-scratch-initial-major-mode t)
|
||||
(unless (or buffer-read-only
|
||||
(derived-mode-p 'special-mode)
|
||||
(string-match-p "^ ?\\*" (buffer-name)))
|
||||
major-mode))
|
||||
((null doom-scratch-buffer-major-mode)
|
||||
((null doom-scratch-initial-major-mode)
|
||||
nil)
|
||||
((symbolp doom-scratch-buffer-major-mode)
|
||||
doom-scratch-buffer-major-mode))
|
||||
((symbolp doom-scratch-initial-major-mode)
|
||||
doom-scratch-initial-major-mode))
|
||||
default-directory
|
||||
(when project-p
|
||||
(doom-project-name))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/switch-to-scratch-buffer (&optional project-p)
|
||||
(defun doom/switch-to-scratch-buffer (&optional arg project-p)
|
||||
"Like `doom/open-scratch-buffer', but switches to it in the current window.
|
||||
|
||||
If passed the prefix arg, open project scratch buffer."
|
||||
If passed the prefix ARG, do not restore the last scratch buffer."
|
||||
(interactive "P")
|
||||
(doom/open-scratch-buffer t project-p))
|
||||
(doom/open-scratch-buffer arg project-p 'same-window))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/open-project-scratch-buffer (&optional current-window)
|
||||
(defun doom/open-project-scratch-buffer (&optional arg same-window-p)
|
||||
"Opens the (persistent) project scratch buffer in a popup.
|
||||
|
||||
If passed the prefix arg, switch to it in the current window."
|
||||
If passed the prefix ARG, do not restore the last scratch buffer."
|
||||
(interactive "P")
|
||||
(doom/open-scratch-buffer current-window 'project))
|
||||
(doom/open-scratch-buffer arg 'project same-window-p))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/switch-to-project-scratch-buffer ()
|
||||
(defun doom/switch-to-project-scratch-buffer (&optional arg)
|
||||
"Like `doom/open-project-scratch-buffer', but switches to it in the current
|
||||
window."
|
||||
(interactive)
|
||||
(doom/open-project-scratch-buffer t))
|
||||
window.
|
||||
|
||||
If passed the prefix ARG, do not restore the last scratch buffer."
|
||||
(interactive "P")
|
||||
(doom/open-project-scratch-buffer arg 'same-window))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/revert-scratch-buffer ()
|
||||
|
||||
@@ -47,10 +47,16 @@
|
||||
"TODO"
|
||||
(setq file (expand-file-name (or file (doom-session-file))))
|
||||
(message "Attempting to load %s" file)
|
||||
(cond ((require 'persp-mode nil t)
|
||||
(cond ((not (file-readable-p file))
|
||||
(message "No session file at %S to read from" file))
|
||||
((require 'persp-mode nil t)
|
||||
(unless persp-mode
|
||||
(persp-mode +1))
|
||||
(persp-load-state-from-file file))
|
||||
(let ((allowed (persp-list-persp-names-in-file file)))
|
||||
(cl-loop for name being the hash-keys of *persp-hash*
|
||||
unless (member name allowed)
|
||||
do (persp-kill name))
|
||||
(persp-load-state-from-file file)))
|
||||
((and (require 'frameset nil t)
|
||||
(require 'restart-emacs nil t))
|
||||
(restart-emacs--restore-frames-using-desktop file))
|
||||
@@ -65,6 +71,9 @@
|
||||
"TODO"
|
||||
(add-hook 'window-setup-hook #'doom-load-session 'append))
|
||||
|
||||
;;;###autoload
|
||||
(add-to-list 'command-switch-alist (cons "--restore" #'doom-restore-session-handler))
|
||||
|
||||
|
||||
;;
|
||||
;;; Commands
|
||||
@@ -124,5 +133,11 @@
|
||||
(interactive "P")
|
||||
(setq doom-autosave-session nil)
|
||||
(doom/quicksave-session)
|
||||
(restart-emacs
|
||||
(delq nil (list (if debug "--debug-init") "--restore"))))
|
||||
(save-some-buffers nil t)
|
||||
(letf! ((#'save-buffers-kill-emacs #'kill-emacs)
|
||||
(confirm-kill-emacs))
|
||||
(restart-emacs
|
||||
(append (if debug (list "--debug-init"))
|
||||
(when (boundp 'chemacs-current-emacs-profile)
|
||||
(list "--with-profile" chemacs-current-emacs-profile))
|
||||
(list "--restore")))))
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
;;; core/autoload/text.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defvar doom-point-in-comment-functions ()
|
||||
"List of functions to run to determine if point is in a comment.
|
||||
|
||||
Each function takes one argument: the position of the point. Stops on the first
|
||||
function to return non-nil. Used by `doom-point-in-comment-p'.")
|
||||
|
||||
(defvar doom-point-in-string-functions ()
|
||||
"List of functions to run to determine if point is in a string.
|
||||
|
||||
Each function takes one argument: the position of the point. Stops on the first
|
||||
function to return non-nil. Used by `doom-point-in-string-p'.")
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-surrounded-p (pair &optional inline balanced)
|
||||
"Returns t if point is surrounded by a brace delimiter: {[(
|
||||
@@ -28,31 +40,18 @@ lines, above and below, with only whitespace in between."
|
||||
;;;###autoload
|
||||
(defun doom-point-in-comment-p (&optional pos)
|
||||
"Return non-nil if POS is in a comment.
|
||||
|
||||
POS defaults to the current position."
|
||||
;; REVIEW Should we cache `syntax-ppss'?
|
||||
(let* ((pos (or pos (point)))
|
||||
(ppss (syntax-ppss pos)))
|
||||
(or (nth 4 ppss)
|
||||
(nth 8 ppss)
|
||||
(and (< pos (point-max))
|
||||
(memq (char-syntax (char-after pos)) '(?< ?>))
|
||||
(not (eq (char-after pos) ?\n)))
|
||||
(when-let (s (car (syntax-after pos)))
|
||||
(or (and (/= 0 (logand (lsh 1 16) s))
|
||||
(nth 4 (doom-syntax-ppss (+ pos 2))))
|
||||
(and (/= 0 (logand (lsh 1 17) s))
|
||||
(nth 4 (doom-syntax-ppss (+ pos 1))))
|
||||
(and (/= 0 (logand (lsh 1 18) s))
|
||||
(nth 4 (doom-syntax-ppss (- pos 1))))
|
||||
(and (/= 0 (logand (lsh 1 19) s))
|
||||
(nth 4 (doom-syntax-ppss (- pos 2)))))))))
|
||||
(let ((pos (or pos (point))))
|
||||
(or (run-hook-with-args-until-success 'doom-point-in-comment-functions pos)
|
||||
(sp-point-in-comment pos))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-point-in-string-p (&optional pos)
|
||||
"Return non-nil if POS is in a string."
|
||||
;; REVIEW Should we cache `syntax-ppss'?
|
||||
(nth 3 (syntax-ppss pos)))
|
||||
(let ((pos (or pos (point))))
|
||||
(or (run-hook-with-args-until-success 'doom-point-in-string-functions pos)
|
||||
(sp-point-in-string pos))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-point-in-string-or-comment-p (&optional pos)
|
||||
@@ -60,74 +59,157 @@ POS defaults to the current position."
|
||||
(or (doom-point-in-string-p pos)
|
||||
(doom-point-in-comment-p pos)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-region-active-p ()
|
||||
"Return non-nil if selection is active.
|
||||
Detects evil visual mode as well."
|
||||
(declare (side-effect-free t))
|
||||
(or (use-region-p)
|
||||
(and (bound-and-true-p evil-local-mode)
|
||||
(evil-visual-state-p))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-region-beginning ()
|
||||
"Return beginning position of selection.
|
||||
Uses `evil-visual-beginning' if available."
|
||||
(declare (side-effect-free t))
|
||||
(if (bound-and-true-p evil-local-mode)
|
||||
evil-visual-beginning
|
||||
(region-beginning)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-region-end ()
|
||||
"Return end position of selection.
|
||||
Uses `evil-visual-end' if available."
|
||||
(declare (side-effect-free t))
|
||||
(if (bound-and-true-p evil-local-mode)
|
||||
evil-visual-end
|
||||
(region-end)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-thing-at-point-or-region (&optional thing prompt)
|
||||
"Grab the current selection, THING at point, or xref identifier at point.
|
||||
|
||||
Returns THING if it is a string. Otherwise, if nothing is found at point and
|
||||
PROMPT is non-nil, prompt for a string (if PROMPT is a string it'll be used as
|
||||
the prompting string). Returns nil if all else fails.
|
||||
|
||||
NOTE: Don't use THING for grabbing symbol-at-point. The xref fallback is smarter
|
||||
in some cases."
|
||||
(declare (side-effect-free t))
|
||||
(cond ((stringp thing)
|
||||
thing)
|
||||
((doom-region-active-p)
|
||||
(buffer-substring-no-properties
|
||||
(doom-region-beginning)
|
||||
(doom-region-end)))
|
||||
(thing
|
||||
(thing-at-point thing t))
|
||||
((require 'xref nil t)
|
||||
;; A little smarter than using `symbol-at-point', though in most cases,
|
||||
;; xref ends up using `symbol-at-point' anyway.
|
||||
(xref-backend-identifier-at-point (xref-find-backend)))
|
||||
(prompt
|
||||
(read-string (if (stringp prompt) prompt "")))))
|
||||
|
||||
|
||||
;;
|
||||
;;; Commands
|
||||
|
||||
(defvar doom--last-backward-pt most-positive-fixnum)
|
||||
(defun doom--bol-bot-eot-eol (&optional pos)
|
||||
(save-mark-and-excursion
|
||||
(when pos
|
||||
(goto-char pos))
|
||||
(let* ((bol (if visual-line-mode
|
||||
(save-excursion
|
||||
(beginning-of-visual-line)
|
||||
(point))
|
||||
(line-beginning-position)))
|
||||
(bot (save-excursion
|
||||
(goto-char bol)
|
||||
(skip-chars-forward " \t\r")
|
||||
(point)))
|
||||
(eol (if visual-line-mode
|
||||
(save-excursion (end-of-visual-line) (point))
|
||||
(line-end-position)))
|
||||
(eot (or (save-excursion
|
||||
(if (not comment-use-syntax)
|
||||
(progn
|
||||
(goto-char bol)
|
||||
(when (re-search-forward comment-start-skip eol t)
|
||||
(or (match-end 1) (match-beginning 0))))
|
||||
(goto-char eol)
|
||||
(while (and (doom-point-in-comment-p)
|
||||
(> (point) bol))
|
||||
(backward-char))
|
||||
(skip-chars-backward " " bol)
|
||||
(unless (or (eq (char-after) 32) (eolp))
|
||||
(forward-char))
|
||||
(point)))
|
||||
eol)))
|
||||
(list bol bot eot eol))))
|
||||
|
||||
(defvar doom--last-backward-pt nil)
|
||||
;;;###autoload
|
||||
(defun doom/backward-to-bol-or-indent ()
|
||||
(defun doom/backward-to-bol-or-indent (&optional point)
|
||||
"Jump between the indentation column (first non-whitespace character) and the
|
||||
beginning of the line. The opposite of
|
||||
`doom/forward-to-last-non-comment-or-eol'."
|
||||
(interactive)
|
||||
(let ((pt (point)))
|
||||
(cl-destructuring-bind (bol . bot)
|
||||
(save-excursion
|
||||
(beginning-of-visual-line)
|
||||
(cons (point)
|
||||
(progn (skip-chars-forward " \t\r")
|
||||
(point))))
|
||||
(interactive "^d")
|
||||
(let ((pt (or point (point))))
|
||||
(cl-destructuring-bind (bol bot _eot _eol)
|
||||
(doom--bol-bot-eot-eol pt)
|
||||
(cond ((> pt bot)
|
||||
(goto-char bot))
|
||||
((= pt bol)
|
||||
(goto-char (min doom--last-backward-pt bot))
|
||||
(setq doom--last-backward-pt most-positive-fixnum))
|
||||
(or (and doom--last-backward-pt
|
||||
(= (line-number-at-pos doom--last-backward-pt)
|
||||
(line-number-at-pos pt)))
|
||||
(setq doom--last-backward-pt nil))
|
||||
(goto-char (or doom--last-backward-pt bot))
|
||||
(setq doom--last-backward-pt nil))
|
||||
((<= pt bot)
|
||||
(setq doom--last-backward-pt pt)
|
||||
(goto-char bol))))))
|
||||
|
||||
(defvar doom--last-forward-pt -1)
|
||||
(defvar doom--last-forward-pt nil)
|
||||
;;;###autoload
|
||||
(defun doom/forward-to-last-non-comment-or-eol ()
|
||||
(defun doom/forward-to-last-non-comment-or-eol (&optional point)
|
||||
"Jumps between the last non-blank, non-comment character in the line and the
|
||||
true end of the line. The opposite of `doom/backward-to-bol-or-indent'."
|
||||
(interactive "^d")
|
||||
(let ((pt (or point (point))))
|
||||
(cl-destructuring-bind (_bol _bot eot eol)
|
||||
(doom--bol-bot-eot-eol pt)
|
||||
(cond ((< pt eot)
|
||||
(goto-char eot))
|
||||
((= pt eol)
|
||||
(goto-char (or doom--last-forward-pt eot))
|
||||
(setq doom--last-forward-pt nil))
|
||||
((>= pt eot)
|
||||
(setq doom--last-backward-pt pt)
|
||||
(goto-char eol))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/backward-kill-to-bol-and-indent ()
|
||||
"Kill line to the first non-blank character. If invoked again afterwards, kill
|
||||
line to beginning of line. Same as `evil-delete-back-to-indentation'."
|
||||
(interactive)
|
||||
(let ((eol (if (not visual-line-mode)
|
||||
(line-end-position)
|
||||
(save-excursion (end-of-visual-line) (point)))))
|
||||
(if (or (and (< (point) eol)
|
||||
(sp-point-in-comment))
|
||||
(not (sp-point-in-comment eol)))
|
||||
(if (= (point) eol)
|
||||
(progn
|
||||
(goto-char doom--last-forward-pt)
|
||||
(setq doom--last-forward-pt -1))
|
||||
(setq doom--last-forward-pt (point))
|
||||
(goto-char eol))
|
||||
(let* ((bol (save-excursion (beginning-of-visual-line) (point)))
|
||||
(boc (or (save-excursion
|
||||
(if (not comment-use-syntax)
|
||||
(progn
|
||||
(goto-char bol)
|
||||
(when (re-search-forward comment-start-skip eol t)
|
||||
(or (match-end 1) (match-beginning 0))))
|
||||
(goto-char eol)
|
||||
(while (and (sp-point-in-comment)
|
||||
(> (point) bol))
|
||||
(backward-char))
|
||||
(skip-chars-backward " " bol)
|
||||
(point)))
|
||||
eol)))
|
||||
(when (> doom--last-forward-pt boc)
|
||||
(setq boc doom--last-forward-pt))
|
||||
(if (or (= eol (point))
|
||||
(> boc (point)))
|
||||
(progn
|
||||
(goto-char boc)
|
||||
(setq doom--last-forward-pt -1))
|
||||
(setq doom--last-forward-pt (point))
|
||||
(goto-char eol))))))
|
||||
(let ((empty-line-p (save-excursion (beginning-of-line)
|
||||
(looking-at-p "[ \t]*$"))))
|
||||
(funcall (if (fboundp 'evil-delete)
|
||||
#'evil-delete
|
||||
#'delete-region)
|
||||
(point-at-bol) (point))
|
||||
(unless empty-line-p
|
||||
(indent-according-to-mode))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/delete-backward-word (arg)
|
||||
"Like `backward-kill-word', but doesn't affect the kill-ring."
|
||||
(interactive "p")
|
||||
(let (kill-ring)
|
||||
(backward-kill-word arg)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/dumb-indent ()
|
||||
@@ -155,20 +237,6 @@ true end of the line. The opposite of `doom/backward-to-bol-or-indent'."
|
||||
tab-width
|
||||
(- tab-width movement)))))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/backward-kill-to-bol-and-indent ()
|
||||
"Kill line to the first non-blank character. If invoked again
|
||||
afterwards, kill line to beginning of line."
|
||||
(interactive)
|
||||
(let ((empty-line-p (save-excursion (beginning-of-line)
|
||||
(looking-at-p "[ \t]*$"))))
|
||||
(funcall (if (fboundp 'evil-delete)
|
||||
#'evil-delete
|
||||
#'delete-region)
|
||||
(point-at-bol) (point))
|
||||
(unless empty-line-p
|
||||
(indent-according-to-mode))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/retab (arg &optional beg end)
|
||||
"Converts tabs-to-spaces or spaces-to-tabs within BEG and END (defaults to
|
||||
@@ -192,15 +260,9 @@ opposite indentation style."
|
||||
|
||||
Respects `require-final-newline'."
|
||||
(interactive)
|
||||
(goto-char (point-max))
|
||||
(skip-chars-backward " \t\n\v")
|
||||
(when (looking-at "\n\\(\n\\|\\'\\)")
|
||||
(forward-char 1))
|
||||
(when require-final-newline
|
||||
(unless (bolp)
|
||||
(insert "\n")))
|
||||
(when (looking-at "\n+")
|
||||
(replace-match "")))
|
||||
(save-excursion
|
||||
(goto-char (point-max))
|
||||
(delete-blank-lines)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/dos2unix ()
|
||||
|
||||
@@ -9,6 +9,13 @@
|
||||
`((,(car spec) ((t ,(cdr spec))))))
|
||||
(`((,(car spec) ,(cdr spec))))))
|
||||
|
||||
;;;###autoload
|
||||
(defconst doom-customize-theme-hook nil)
|
||||
|
||||
(add-hook! 'doom-load-theme-hook :append
|
||||
(defun doom-apply-customized-faces-h ()
|
||||
(run-hooks 'doom-customize-theme-hook)))
|
||||
|
||||
;;;###autoload
|
||||
(defmacro custom-theme-set-faces! (theme &rest specs)
|
||||
"Apply a list of face SPECS as user customizations for THEME.
|
||||
@@ -16,26 +23,27 @@
|
||||
THEME can be a single symbol or list thereof. If nil, apply these settings to
|
||||
all themes. It will apply to all themes once they are loaded."
|
||||
(declare (indent defun))
|
||||
`(let ((fn (gensym "doom--customize-themes-h-")))
|
||||
(fset
|
||||
fn (lambda ()
|
||||
(let (custom--inhibit-theme-enable)
|
||||
(dolist (theme (doom-enlist (or ,theme 'user)))
|
||||
(when (or (eq theme 'user)
|
||||
(custom-theme-enabled-p theme))
|
||||
(apply #'custom-theme-set-faces theme
|
||||
(mapcan #'doom--custom-theme-set-face
|
||||
(list ,@specs))))))))
|
||||
(when (or doom-init-theme-p (null doom-theme))
|
||||
(funcall fn))
|
||||
(add-hook 'doom-load-theme-hook fn 'append)))
|
||||
(let ((fn (gensym "doom--customize-themes-h-")))
|
||||
`(progn
|
||||
(defun ,fn ()
|
||||
(let (custom--inhibit-theme-enable)
|
||||
(dolist (theme (doom-enlist (or ,theme 'user)))
|
||||
(when (or (eq theme 'user)
|
||||
(custom-theme-enabled-p theme))
|
||||
(apply #'custom-theme-set-faces theme
|
||||
(mapcan #'doom--custom-theme-set-face
|
||||
(list ,@specs)))))))
|
||||
(when (or doom-init-theme-p (null doom-theme))
|
||||
(funcall #',fn))
|
||||
(add-hook 'doom-customize-theme-hook #',fn 'append))))
|
||||
|
||||
;;;###autoload
|
||||
(defmacro custom-set-faces! (&rest specs)
|
||||
"Apply a list of face SPECS as user customizations.
|
||||
|
||||
This is a drop-in replacement for `custom-set-face' that allows for a simplified
|
||||
face format."
|
||||
This is a convenience macro alternative to `custom-set-face' which allows for a
|
||||
simplified face format, and takes care of load order issues, so you can use
|
||||
doom-themes' API without worry."
|
||||
(declare (indent defun))
|
||||
`(custom-theme-set-faces! 'user ,@specs))
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
;;; core/autoload/ui.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;
|
||||
;; Public library
|
||||
;;; Public library
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-resize-window (window new-size &optional horizontal force-p)
|
||||
@@ -24,13 +24,23 @@ are open."
|
||||
|
||||
|
||||
;;
|
||||
;; Advice
|
||||
;;; Advice
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-recenter-a (&rest _)
|
||||
"Generic advisor for recentering window (typically :after other functions)."
|
||||
"Generic advice for recentering window (typically :after other functions)."
|
||||
(recenter))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-preserve-window-position-a (orig-fn &rest args)
|
||||
"Generic advice for preserving cursor position on screen after scrolling."
|
||||
(let ((row (cdr (posn-col-row (posn-at-point)))))
|
||||
(prog1 (apply orig-fn args)
|
||||
(save-excursion
|
||||
(let ((target-row (- (line-number-at-pos) row)))
|
||||
(unless (< target-row 0)
|
||||
(evil-scroll-line-to-top target-row)))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-shut-up-a (orig-fn &rest args)
|
||||
"Generic advisor for silencing noisy functions.
|
||||
@@ -43,7 +53,7 @@ In tty Emacs, messages suppressed completely."
|
||||
|
||||
|
||||
;;
|
||||
;; Hooks
|
||||
;;; Hooks
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-apply-ansi-color-to-compilation-buffer-h ()
|
||||
@@ -57,9 +67,17 @@ In tty Emacs, messages suppressed completely."
|
||||
"Turn off `show-paren-mode' buffer-locally."
|
||||
(setq-local show-paren-mode nil))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-enable-line-numbers-h ()
|
||||
(display-line-numbers-mode +1))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-disable-line-numbers-h ()
|
||||
(display-line-numbers-mode -1))
|
||||
|
||||
|
||||
;;
|
||||
;; Commands
|
||||
;;; Commands
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/toggle-line-numbers ()
|
||||
@@ -87,7 +105,7 @@ See `display-line-numbers' for what these values mean."
|
||||
(_ (symbol-name next))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/delete-frame ()
|
||||
(defun doom/delete-frame-with-prompt ()
|
||||
"Delete the current frame, but ask for confirmation if it isn't empty."
|
||||
(interactive)
|
||||
(if (cdr (frame-list))
|
||||
@@ -95,6 +113,7 @@ See `display-line-numbers' for what these values mean."
|
||||
(delete-frame))
|
||||
(save-buffers-kill-emacs)))
|
||||
|
||||
(defvar doom--maximize-last-wconf nil)
|
||||
;;;###autoload
|
||||
(defun doom/window-maximize-buffer ()
|
||||
"Close other windows to focus on this one. Activate again to undo this. If the
|
||||
@@ -102,41 +121,40 @@ window changes before then, the undo expires.
|
||||
|
||||
Alternatively, use `doom/window-enlargen'."
|
||||
(interactive)
|
||||
(if (and (one-window-p)
|
||||
(assq ?_ register-alist))
|
||||
(jump-to-register ?_)
|
||||
(when (and (bound-and-true-p +popup-mode)
|
||||
(+popup-window-p))
|
||||
(user-error "Cannot maximize a popup, use `+popup/raise' first or use `doom/window-enlargen' instead"))
|
||||
(window-configuration-to-register ?_)
|
||||
(delete-other-windows)))
|
||||
(setq doom--maximize-last-wconf
|
||||
(if (and (null (cdr (cl-remove-if #'window-dedicated-p (window-list))))
|
||||
doom--maximize-last-wconf)
|
||||
(ignore (set-window-configuration doom--maximize-last-wconf))
|
||||
(when (and (bound-and-true-p +popup-mode)
|
||||
(+popup-window-p))
|
||||
(user-error "Cannot maximize a popup, use `+popup/raise' first or use `doom/window-enlargen' instead"))
|
||||
(prog1 (current-window-configuration)
|
||||
(delete-other-windows)))))
|
||||
|
||||
(defvar doom--window-enlargened nil)
|
||||
(defvar doom--enlargen-last-wconf nil)
|
||||
;;;###autoload
|
||||
(defun doom/window-enlargen ()
|
||||
"Enlargen the current window to focus on this one. Does not close other
|
||||
windows (unlike `doom/window-maximize-buffer') Activate again to undo."
|
||||
windows (unlike `doom/window-maximize-buffer'). Activate again to undo."
|
||||
(interactive)
|
||||
(setq doom--window-enlargened
|
||||
(if (and doom--window-enlargened
|
||||
(assq ?_ register-alist))
|
||||
(ignore (ignore-errors (jump-to-register ?_)))
|
||||
(window-configuration-to-register ?_)
|
||||
(let* ((window (selected-window))
|
||||
(dedicated-p (window-dedicated-p window))
|
||||
(preserved-p (window-parameter window 'window-preserved-size))
|
||||
(ignore-window-parameters t))
|
||||
(unwind-protect
|
||||
(progn
|
||||
(when dedicated-p
|
||||
(set-window-dedicated-p window nil))
|
||||
(when preserved-p
|
||||
(set-window-parameter window 'window-preserved-size nil))
|
||||
(maximize-window window))
|
||||
(set-window-dedicated-p window dedicated-p)
|
||||
(when preserved-p
|
||||
(set-window-parameter window 'window-preserved-size preserved-p)))
|
||||
t))))
|
||||
(setq doom--enlargen-last-wconf
|
||||
(if doom--enlargen-last-wconf
|
||||
(ignore (set-window-configuration doom--enlargen-last-wconf))
|
||||
(prog1 (current-window-configuration)
|
||||
(let* ((window (selected-window))
|
||||
(dedicated-p (window-dedicated-p window))
|
||||
(preserved-p (window-parameter window 'window-preserved-size))
|
||||
(ignore-window-parameters t))
|
||||
(unwind-protect
|
||||
(progn
|
||||
(when dedicated-p
|
||||
(set-window-dedicated-p window nil))
|
||||
(when preserved-p
|
||||
(set-window-parameter window 'window-preserved-size nil))
|
||||
(maximize-window window))
|
||||
(set-window-dedicated-p window dedicated-p)
|
||||
(when preserved-p
|
||||
(set-window-parameter window 'window-preserved-size preserved-p))))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/window-maximize-horizontally ()
|
||||
|
||||
@@ -1,407 +1,225 @@
|
||||
;;; core/cli/autoloads.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defvar doom-autoload-excluded-packages '("gh")
|
||||
"Packages that have silly or destructive autoload files that try to load
|
||||
(defvar doom-autoloads-excluded-packages '("gh")
|
||||
"What packages whose autoloads file we won't index.
|
||||
|
||||
These packages have silly or destructive autoload files that try to load
|
||||
everyone in the universe and their dog, causing errors that make babies cry. No
|
||||
one wants that.")
|
||||
|
||||
;; externs
|
||||
(defvar doom-autoloads-cached-vars
|
||||
'(doom-modules
|
||||
doom-disabled-packages
|
||||
load-path
|
||||
auto-mode-alist
|
||||
interpreter-mode-alist
|
||||
Info-directory-list)
|
||||
"A list of variables to be cached in `doom-autoload-file'.")
|
||||
|
||||
(defvar doom-autoloads-files ()
|
||||
"A list of additional files or file globs to scan for autoloads.")
|
||||
|
||||
|
||||
;;
|
||||
;;; Library
|
||||
|
||||
(defun doom-autoloads-reload (&optional file)
|
||||
"Regenerates Doom's autoloads and writes them to FILE."
|
||||
(unless file
|
||||
(setq file doom-autoload-file))
|
||||
(print! (start "(Re)generating autoloads file..."))
|
||||
(print-group!
|
||||
(cl-check-type file string)
|
||||
(doom-initialize-packages)
|
||||
(and (print! (start "Generating autoloads file..."))
|
||||
(doom-autoloads--write
|
||||
file
|
||||
`((unless (equal emacs-major-version ,emacs-major-version)
|
||||
(signal 'doom-error
|
||||
(list "The installed version of Emacs has changed since last 'doom sync' ran"
|
||||
"Run 'doom sync && doom build' to bring Doom up to speed")))
|
||||
(unless (equal doom-version ,doom-version)
|
||||
(signal 'doom-error
|
||||
(list "The installed version of Doom has changed since last 'doom sync' ran"
|
||||
"Run 'doom sync' to bring Doom up to speed"))))
|
||||
(mapcar (lambda (var) `(set ',var ',(symbol-value var)))
|
||||
doom-autoloads-cached-vars)
|
||||
(doom-autoloads--scan
|
||||
(append (cl-loop for dir
|
||||
in (append (list doom-core-dir)
|
||||
(cdr (doom-module-load-path 'all-p))
|
||||
(list doom-private-dir))
|
||||
if (doom-glob dir "autoload.el") collect it
|
||||
if (doom-glob dir "autoload/*.el") append it)
|
||||
(mapcan #'doom-glob doom-autoloads-files)))
|
||||
(doom-autoloads--scan
|
||||
(mapcar #'straight--autoloads-file
|
||||
(seq-difference (hash-table-keys straight--build-cache)
|
||||
doom-autoloads-excluded-packages))
|
||||
'literal))
|
||||
(print! (start "Byte-compiling autoloads file..."))
|
||||
(doom-autoloads--compile-file file)
|
||||
(print! (success "Generated %s")
|
||||
(relpath (byte-compile-dest-file file)
|
||||
doom-emacs-dir)))))
|
||||
|
||||
(defun doom-autoloads--write (file &rest forms)
|
||||
(make-directory (file-name-directory file) 'parents)
|
||||
(condition-case-unless-debug e
|
||||
(with-temp-file file
|
||||
(setq-local coding-system-for-write 'utf-8)
|
||||
(let ((standard-output (current-buffer))
|
||||
(print-quoted t)
|
||||
(print-level nil)
|
||||
(print-length nil))
|
||||
(insert ";; -*- lexical-binding: t; coding: utf-8; -*-\n"
|
||||
";; This file is autogenerated by 'doom sync', DO NOT EDIT IT!!\n")
|
||||
(dolist (form (delq nil forms))
|
||||
(mapc #'prin1 form))
|
||||
t))
|
||||
(error (delete-file file)
|
||||
(signal 'doom-autoload-error (list file e)))))
|
||||
|
||||
(defun doom-autoloads--compile-file (file)
|
||||
(condition-case-unless-debug e
|
||||
(let ((byte-compile-warnings (if doom-debug-p byte-compile-warnings)))
|
||||
(and (byte-compile-file file)
|
||||
(load (byte-compile-dest-file file) nil t)))
|
||||
(error
|
||||
(delete-file (byte-compile-dest-file file))
|
||||
(signal 'doom-autoload-error (list file e)))))
|
||||
|
||||
(defun doom-autoloads--cleanup-form (form &optional expand)
|
||||
(let ((func (car-safe form)))
|
||||
(cond ((memq func '(provide custom-autoload))
|
||||
nil)
|
||||
((and (eq func 'add-to-list)
|
||||
(memq (doom-unquote (cadr form))
|
||||
doom-autoloads-cached-vars))
|
||||
nil)
|
||||
((not (eq func 'autoload))
|
||||
form)
|
||||
((and expand (not (file-name-absolute-p (nth 2 form))))
|
||||
(defvar doom--autoloads-path-cache nil)
|
||||
(setf (nth 2 form)
|
||||
(let ((path (nth 2 form)))
|
||||
(or (cdr (assoc path doom--autoloads-path-cache))
|
||||
(when-let* ((libpath (locate-library path))
|
||||
(libpath (file-name-sans-extension libpath))
|
||||
(libpath (abbreviate-file-name libpath)))
|
||||
(push (cons path libpath) doom--autoloads-path-cache)
|
||||
libpath)
|
||||
path)))
|
||||
form)
|
||||
(form))))
|
||||
|
||||
(defun doom-autoloads--scan-autodefs (file buffer module &optional module-enabled-p)
|
||||
(with-temp-buffer
|
||||
(insert-file-contents file)
|
||||
(while (re-search-forward "^;;;###autodef *\\([^\n]+\\)?\n" nil t)
|
||||
(let* ((standard-output buffer)
|
||||
(form (read (current-buffer)))
|
||||
(altform (match-string 1))
|
||||
(definer (car-safe form))
|
||||
(symbol (doom-unquote (cadr form))))
|
||||
(cond ((and (not module-enabled-p) altform)
|
||||
(print (read altform)))
|
||||
((memq definer '(defun defmacro cl-defun cl-defmacro))
|
||||
(if module-enabled-p
|
||||
(print (make-autoload form file))
|
||||
(cl-destructuring-bind (_ _ arglist &rest body) form
|
||||
(print
|
||||
(if altform
|
||||
(read altform)
|
||||
(append
|
||||
(list (pcase definer
|
||||
(`defun 'defmacro)
|
||||
(`cl-defun `cl-defmacro)
|
||||
(_ type))
|
||||
symbol arglist
|
||||
(format "THIS FUNCTION DOES NOTHING BECAUSE %s IS DISABLED\n\n%s"
|
||||
module
|
||||
(if (stringp (car body))
|
||||
(pop body)
|
||||
"No documentation.")))
|
||||
(cl-loop for arg in arglist
|
||||
if (and (symbolp arg)
|
||||
(not (keywordp arg))
|
||||
(not (memq arg cl--lambda-list-keywords)))
|
||||
collect arg into syms
|
||||
else if (listp arg)
|
||||
collect (car arg) into syms
|
||||
finally return (if syms `((ignore ,@syms)))))))))
|
||||
(print `(put ',symbol 'doom-module ',module)))
|
||||
((eq definer 'defalias)
|
||||
(cl-destructuring-bind (_ _ target &optional docstring) form
|
||||
(unless module-enabled-p
|
||||
(setq target #'ignore
|
||||
docstring
|
||||
(format "THIS FUNCTION DOES NOTHING BECAUSE %s IS DISABLED\n\n%s"
|
||||
module docstring)))
|
||||
(print `(put ',symbol 'doom-module ',module))
|
||||
(print `(defalias ',symbol #',(doom-unquote target) ,docstring))))
|
||||
(module-enabled-p (print form)))))))
|
||||
|
||||
(defvar autoload-timestamps)
|
||||
(defvar generated-autoload-load-name)
|
||||
(defvar generated-autoload-file)
|
||||
|
||||
|
||||
;;
|
||||
;;; Helpers
|
||||
|
||||
(defun doom--cli-delete-autoloads-file (file)
|
||||
"Delete FILE (an autoloads file) and accompanying *.elc file, if any."
|
||||
(cl-check-type file string)
|
||||
(when (file-exists-p file)
|
||||
(when-let (buf (find-buffer-visiting file))
|
||||
(with-current-buffer buf
|
||||
(set-buffer-modified-p nil))
|
||||
(kill-buffer buf))
|
||||
(delete-file file)
|
||||
(ignore-errors (delete-file (byte-compile-dest-file file)))
|
||||
t))
|
||||
|
||||
(defun doom--cli-warn-refresh-session-h ()
|
||||
(message "Restart or reload Doom Emacs for changes to take effect:\n")
|
||||
(message " M-x doom/restart-and-restore")
|
||||
(message " M-x doom/restart")
|
||||
(message " M-x doom/reload"))
|
||||
|
||||
(defun doom--cli-byte-compile-file (file)
|
||||
(let ((byte-compile-warnings (if doom-debug-mode byte-compile-warnings))
|
||||
(byte-compile-dynamic t)
|
||||
(byte-compile-dynamic-docstrings t))
|
||||
(condition-case-unless-debug e
|
||||
(when (byte-compile-file file)
|
||||
(unless doom-interactive-mode
|
||||
(add-hook 'doom-cli-post-success-execute-hook #'doom--cli-warn-refresh-session-h))
|
||||
(let (noninteractive)
|
||||
(load file 'noerror 'nomessage 'nosuffix)))
|
||||
((debug error)
|
||||
(let ((backup-file (concat file ".bk")))
|
||||
(print! (warn "Copied backup to %s") (relpath backup-file))
|
||||
(copy-file file backup-file 'overwrite))
|
||||
(doom--cli-delete-autoloads-file file)
|
||||
(signal 'doom-autoload-error (list file e))))))
|
||||
|
||||
(defun doom-cli-reload-autoloads (&optional file force-p)
|
||||
"Reloads FILE (an autoload file), if it needs reloading.
|
||||
|
||||
FILE should be one of `doom-autoload-file' or `doom-package-autoload-file'. If
|
||||
it is nil, it will try to reload both. If FORCE-P (universal argument) do it
|
||||
even if it doesn't need reloading!"
|
||||
(or (null file)
|
||||
(stringp file)
|
||||
(signal 'wrong-type-argument (list 'stringp file)))
|
||||
(if (stringp file)
|
||||
(cond ((file-equal-p file doom-autoload-file)
|
||||
(doom-cli-reload-core-autoloads force-p))
|
||||
((file-equal-p file doom-package-autoload-file)
|
||||
(doom-cli-reload-package-autoloads force-p))
|
||||
((error "Invalid autoloads file: %s" file)))
|
||||
(doom-cli-reload-core-autoloads force-p)
|
||||
(doom-cli-reload-package-autoloads force-p)))
|
||||
|
||||
|
||||
;;
|
||||
;;; Doom autoloads
|
||||
|
||||
(defun doom--cli-generate-header (func)
|
||||
(goto-char (point-min))
|
||||
(insert ";; -*- lexical-binding:t; -*-\n"
|
||||
";; This file is autogenerated by `" (symbol-name func) "', DO NOT EDIT !!\n\n"))
|
||||
|
||||
(defun doom--cli-generate-autoloads (targets)
|
||||
(let ((n 0))
|
||||
(dolist (file targets)
|
||||
(insert
|
||||
(with-temp-buffer
|
||||
(cond ((not (doom-file-cookie-p file "if" t))
|
||||
(print! (debug "Ignoring %s") (relpath file)))
|
||||
|
||||
((let ((generated-autoload-load-name (file-name-sans-extension file))
|
||||
;; Prevent `autoload-find-file' from firing file hooks,
|
||||
;; e.g. adding to recentf.
|
||||
find-file-hook
|
||||
write-file-functions
|
||||
;; Prevent a possible source of crashes when there's a
|
||||
;; syntax error in the autoloads file
|
||||
debug-on-error)
|
||||
(quiet! (autoload-generate-file-autoloads file (current-buffer))))
|
||||
(print! (debug "Nothing in %s") (relpath file)))
|
||||
|
||||
((cl-incf n)
|
||||
(print! (debug "Scanning %s...") (relpath file))))
|
||||
(buffer-string))))
|
||||
(print! (class (if (> n 0) 'success 'info)
|
||||
"Scanned %d file(s)")
|
||||
n)))
|
||||
|
||||
(defun doom--cli-expand-autoload-paths (&optional allow-internal-paths)
|
||||
(let ((load-path
|
||||
;; NOTE With `doom-private-dir' in `load-path', Doom autoloads files
|
||||
;; will be unable to declare autoloads for the built-in autoload.el
|
||||
;; Emacs package, should $DOOMDIR/autoload.el exist. Not sure why
|
||||
;; they'd want to though, so it's an acceptable compromise.
|
||||
(append (list doom-private-dir)
|
||||
doom-modules-dirs
|
||||
(straight--directory-files (straight--build-dir) nil t)
|
||||
load-path)))
|
||||
(defvar doom--autoloads-path-cache nil)
|
||||
(while (re-search-forward "^\\s-*(\\(?:custom-\\)?autoload\\s-+'[^ ]+\\s-+\"\\([^\"]*\\)\"" nil t)
|
||||
(let ((path (match-string 1)))
|
||||
(replace-match
|
||||
(or (cdr (assoc path doom--autoloads-path-cache))
|
||||
(when-let* ((libpath (or (and allow-internal-paths
|
||||
(locate-library path nil (cons doom-emacs-dir doom-modules-dirs)))
|
||||
(locate-library path)))
|
||||
(libpath (file-name-sans-extension libpath))
|
||||
(libpath (abbreviate-file-name libpath)))
|
||||
(push (cons path libpath) doom--autoloads-path-cache)
|
||||
libpath)
|
||||
path)
|
||||
t t nil 1)))))
|
||||
|
||||
(defun doom--cli-generate-autodefs-1 (path &optional member-p)
|
||||
(let (forms)
|
||||
(while (re-search-forward "^;;;###autodef *\\([^\n]+\\)?\n" nil t)
|
||||
(let* ((sexp (sexp-at-point))
|
||||
(alt-sexp (match-string 1))
|
||||
(type (car sexp))
|
||||
(name (doom-unquote (cadr sexp)))
|
||||
(origin (doom-module-from-path path)))
|
||||
(cond
|
||||
((and (not member-p)
|
||||
alt-sexp)
|
||||
(push (read alt-sexp) forms))
|
||||
|
||||
((memq type '(defun defmacro cl-defun cl-defmacro))
|
||||
(cl-destructuring-bind (_ _name arglist &rest body) sexp
|
||||
(appendq!
|
||||
forms
|
||||
(list (if member-p
|
||||
(make-autoload sexp path)
|
||||
(let ((docstring
|
||||
(format "THIS FUNCTION DOES NOTHING BECAUSE %s IS DISABLED\n\n%s"
|
||||
origin
|
||||
(if (stringp (car body))
|
||||
(pop body)
|
||||
"No documentation."))))
|
||||
(condition-case-unless-debug e
|
||||
(if alt-sexp
|
||||
(read alt-sexp)
|
||||
(append
|
||||
(list (pcase type
|
||||
(`defun 'defmacro)
|
||||
(`cl-defun `cl-defmacro)
|
||||
(_ type))
|
||||
name arglist docstring)
|
||||
(cl-loop for arg in arglist
|
||||
if (and (symbolp arg)
|
||||
(not (keywordp arg))
|
||||
(not (memq arg cl--lambda-list-keywords)))
|
||||
collect arg into syms
|
||||
else if (listp arg)
|
||||
collect (car arg) into syms
|
||||
finally return (if syms `((ignore ,@syms))))))
|
||||
('error
|
||||
(print! "- Ignoring autodef %s (%s)" name e)
|
||||
nil))))
|
||||
`(put ',name 'doom-module ',origin)))))
|
||||
|
||||
((eq type 'defalias)
|
||||
(cl-destructuring-bind (_type name target &optional docstring) sexp
|
||||
(let ((name (doom-unquote name))
|
||||
(target (doom-unquote target)))
|
||||
(unless member-p
|
||||
(setq target #'ignore
|
||||
docstring
|
||||
(format "THIS FUNCTION DOES NOTHING BECAUSE %s IS DISABLED\n\n%s"
|
||||
origin docstring)))
|
||||
(appendq! forms `((put ',name 'doom-module ',origin)
|
||||
(defalias ',name #',target ,docstring))))))
|
||||
|
||||
(member-p (push sexp forms)))))
|
||||
forms))
|
||||
|
||||
(defun doom--cli-generate-autodefs (targets enabled-targets)
|
||||
(goto-char (point-max))
|
||||
(search-backward ";;;***" nil t)
|
||||
(save-excursion (insert "\n"))
|
||||
(dolist (path targets)
|
||||
(insert
|
||||
(with-temp-buffer
|
||||
(insert-file-contents path)
|
||||
(if-let (forms (doom--cli-generate-autodefs-1 path (member path enabled-targets)))
|
||||
(concat (mapconcat #'prin1-to-string (nreverse forms) "\n")
|
||||
"\n")
|
||||
"")))))
|
||||
|
||||
(defun doom--cli-cleanup-autoloads ()
|
||||
(goto-char (point-min))
|
||||
(when (re-search-forward "^;;\\(;[^\n]*\\| no-byte-compile: t\\)\n" nil t)
|
||||
(replace-match "" t t)))
|
||||
|
||||
(defun doom-cli-reload-core-autoloads (&optional force-p)
|
||||
"Refreshes `doom-autoload-file', if necessary (or if FORCE-P is non-nil).
|
||||
|
||||
It scans and reads autoload cookies (;;;###autoload) in core/autoload/*.el,
|
||||
modules/*/*/autoload.el and modules/*/*/autoload/*.el, and generates
|
||||
`doom-autoload-file'.
|
||||
|
||||
Run this whenever your `doom!' block, or a module autoload file, is modified."
|
||||
(require 'autoload)
|
||||
(let* ((default-directory doom-emacs-dir)
|
||||
(doom-modules (doom-modules))
|
||||
|
||||
(defun doom-autoloads--scan-file (file)
|
||||
(let* (;; Prevent `autoload-find-file' from firing file hooks, e.g. adding
|
||||
;; to recentf.
|
||||
find-file-hook
|
||||
write-file-functions
|
||||
;; Prevent a possible source of crashes when there's a syntax error
|
||||
;; in the autoloads file
|
||||
debug-on-error
|
||||
;; The following bindings are in `package-generate-autoloads'.
|
||||
;; Presumably for a good reason, so I just copied them
|
||||
(backup-inhibited t)
|
||||
(version-control 'never)
|
||||
(case-fold-search nil) ; reduce magic
|
||||
(autoload-timestamps nil)
|
||||
case-fold-search ; reduce magic
|
||||
autoload-timestamps ; reduce noise in generated files
|
||||
;; Needed for `autoload-generate-file-autoloads'
|
||||
(generated-autoload-load-name (file-name-sans-extension file))
|
||||
(target-buffer (current-buffer))
|
||||
(module (doom-module-from-path file))
|
||||
(module-enabled-p (and (or (memq (car module) '(:core :private))
|
||||
(doom-module-p (car module) (cdr module)))
|
||||
(doom-file-cookie-p file "if" t))))
|
||||
(save-excursion
|
||||
(when module-enabled-p
|
||||
(quiet! (autoload-generate-file-autoloads file target-buffer)))
|
||||
(doom-autoloads--scan-autodefs
|
||||
file target-buffer module module-enabled-p))))
|
||||
|
||||
;; Where we'll store the files we'll scan for autoloads. This should
|
||||
;; contain *all* autoload files, even in disabled modules, so we can
|
||||
;; scan those for autodefs. We start with the core libraries.
|
||||
(targets (doom-glob doom-core-dir "autoload/*.el"))
|
||||
;; A subset of `targets' in enabled modules
|
||||
(active-targets (copy-sequence targets)))
|
||||
|
||||
(dolist (path (doom-module-load-path 'all-p))
|
||||
(when-let* ((files (cons (doom-glob path "autoload.el")
|
||||
(doom-files-in (doom-path path "autoload")
|
||||
:match "\\.el$")))
|
||||
(files (delq nil files)))
|
||||
(appendq! targets files)
|
||||
(when (or (doom-module-from-path path 'enabled-only)
|
||||
(file-equal-p path doom-private-dir))
|
||||
(appendq! active-targets files))))
|
||||
|
||||
(print! (start "Checking core autoloads file"))
|
||||
(print-group!
|
||||
(if (and (not force-p)
|
||||
(file-exists-p doom-autoload-file)
|
||||
(not (file-newer-than-file-p doom-emacs-dir doom-autoload-file))
|
||||
(not (cl-loop for dir
|
||||
in (append (doom-glob doom-private-dir "init.el*")
|
||||
targets)
|
||||
if (file-newer-than-file-p dir doom-autoload-file)
|
||||
return t)))
|
||||
(ignore
|
||||
(print! (success "Skipping core autoloads, they are up-to-date"))
|
||||
(doom-load-autoloads-file doom-autoload-file))
|
||||
(if (doom--cli-delete-autoloads-file doom-autoload-file)
|
||||
(print! (success "Deleted old %s") (filename doom-autoload-file))
|
||||
(make-directory (file-name-directory doom-autoload-file) t))
|
||||
|
||||
(print! (start "Regenerating core autoloads file"))
|
||||
(print-group!
|
||||
(with-temp-file doom-autoload-file
|
||||
(doom--cli-generate-header 'doom-cli-reload-core-autoloads)
|
||||
(save-excursion
|
||||
(doom--cli-generate-autoloads active-targets)
|
||||
(print! (success "Generated new autoloads.el")))
|
||||
;; Replace autoload paths (only for module autoloads) with absolute
|
||||
;; paths for faster resolution during load and simpler `load-path'
|
||||
(save-excursion
|
||||
(doom--cli-expand-autoload-paths 'allow-internal-paths)
|
||||
(print! (success "Expanded module autoload paths")))
|
||||
;; Generates stub definitions for functions/macros defined in disabled
|
||||
;; modules, so that you will never get a void-function when you use
|
||||
;; them.
|
||||
(save-excursion
|
||||
(doom--cli-generate-autodefs targets (reverse active-targets))
|
||||
(print! (success "Generated autodefs")))
|
||||
;; Remove byte-compile-inhibiting file variables so we can byte-compile
|
||||
;; the file, and autoload comments.
|
||||
(doom--cli-cleanup-autoloads)
|
||||
(print! (success "Cleaned up autoloads"))))
|
||||
;; Byte compile it to give the file a chance to reveal errors (and buy us a
|
||||
;; few marginal performance boosts)
|
||||
(print! "> Byte-compiling %s..." (relpath doom-autoload-file))
|
||||
(when (doom--cli-byte-compile-file doom-autoload-file)
|
||||
(print-group!
|
||||
(print! (success "Compiled %s") (relpath doom-autoload-file)))))
|
||||
t)))
|
||||
|
||||
|
||||
;;
|
||||
;;; Package autoloads
|
||||
|
||||
(defun doom--generate-package-autoloads ()
|
||||
"Concatenates package autoload files, let-binds `load-file-name' around
|
||||
them,and remove unnecessary `provide' statements or blank links."
|
||||
(dolist (pkg (hash-table-keys straight--build-cache))
|
||||
(unless (member pkg doom-autoload-excluded-packages)
|
||||
(let ((file (straight--autoloads-file pkg)))
|
||||
(when (file-exists-p file)
|
||||
(insert-file-contents file)
|
||||
(save-excursion
|
||||
(while (re-search-forward "\\(?:\\_<load-file-name\\|#\\$\\)\\_>" nil t)
|
||||
;; `load-file-name' is meaningless in a concatenated
|
||||
;; mega-autoloads file, so we replace references to it and #$ with
|
||||
;; the file they came from.
|
||||
(unless (doom-point-in-string-or-comment-p)
|
||||
(replace-match (prin1-to-string (abbreviate-file-name file))
|
||||
t t))))
|
||||
(while (re-search-forward "^\\(?:;;\\(.*\n\\)\\|\n\\|(provide '[^\n]+\\)" nil t)
|
||||
(unless (doom-point-in-string-p)
|
||||
(replace-match "" t t)))
|
||||
(unless (bolp) (insert "\n")))))))
|
||||
|
||||
(defun doom--generate-var-cache ()
|
||||
"Print a `setq' form for expensive-to-initialize variables, so we can cache
|
||||
them in Doom's autoloads file."
|
||||
(doom-initialize-packages)
|
||||
(prin1 `(setq load-path ',load-path
|
||||
auto-mode-alist ',auto-mode-alist
|
||||
Info-directory-list ',Info-directory-list
|
||||
doom-disabled-packages ',doom-disabled-packages)
|
||||
(current-buffer)))
|
||||
|
||||
(defun doom--cleanup-package-autoloads ()
|
||||
"Remove (some) forms that modify `load-path' or `auto-mode-alist'.
|
||||
|
||||
These variables are cached all at once and at later, so these removed statements
|
||||
served no purpose but to waste cycles."
|
||||
(while (re-search-forward "^\\s-*\\((\\(?:add-to-list\\|\\(?:when\\|if\\) (boundp\\)\\s-+'\\(?:load-path\\|auto-mode-alist\\)\\)" nil t)
|
||||
(goto-char (match-beginning 1))
|
||||
(kill-sexp)))
|
||||
|
||||
(defun doom-cli-reload-package-autoloads (&optional force-p)
|
||||
"Compiles `doom-package-autoload-file' from the autoloads files of all
|
||||
installed packages. It also caches `load-path', `Info-directory-list',
|
||||
`doom-disabled-packages', `package-activated-list' and `auto-mode-alist'.
|
||||
|
||||
Will do nothing if none of your installed packages have been modified. If
|
||||
FORCE-P (universal argument) is non-nil, regenerate it anyway.
|
||||
|
||||
This should be run whenever your `doom!' block or update your packages."
|
||||
(defun doom-autoloads--scan (files &optional literal)
|
||||
(require 'autoload)
|
||||
(print! (start "Checking package autoloads file"))
|
||||
(print-group!
|
||||
(if (and (not force-p)
|
||||
(file-exists-p doom-package-autoload-file)
|
||||
(not (file-newer-than-file-p package-user-dir doom-package-autoload-file))
|
||||
(not (cl-loop for dir in (straight--directory-files (straight--build-dir))
|
||||
if (cl-find-if
|
||||
(lambda (dir)
|
||||
(file-newer-than-file-p dir doom-package-autoload-file))
|
||||
(doom-glob (straight--build-dir dir) "*.el"))
|
||||
return t))
|
||||
(not (cl-loop with doom-modules = (doom-modules)
|
||||
for key being the hash-keys of doom-modules
|
||||
for path = (doom-module-path (car key) (cdr key) "packages.el")
|
||||
if (file-newer-than-file-p path doom-package-autoload-file)
|
||||
return t)))
|
||||
(ignore
|
||||
(print! (success "Skipping package autoloads, they are up-to-date"))
|
||||
(doom-load-autoloads-file doom-package-autoload-file))
|
||||
(let (;; The following bindings are in `package-generate-autoloads'.
|
||||
;; Presumably for a good reason, so I just copied them
|
||||
(backup-inhibited t)
|
||||
(version-control 'never)
|
||||
(case-fold-search nil) ; reduce magic
|
||||
(autoload-timestamps nil))
|
||||
|
||||
(if (doom--cli-delete-autoloads-file doom-package-autoload-file)
|
||||
(print! (success "Deleted old %s") (filename doom-package-autoload-file))
|
||||
(make-directory (file-name-directory doom-autoload-file) t))
|
||||
|
||||
(print! (start "Regenerating package autoloads file"))
|
||||
(print-group!
|
||||
(with-temp-file doom-package-autoload-file
|
||||
(doom--cli-generate-header 'doom-cli-reload-package-autoloads)
|
||||
|
||||
(save-excursion
|
||||
;; Cache important and expensive-to-initialize state here.
|
||||
(doom--generate-var-cache)
|
||||
(print! (success "Cached package state"))
|
||||
;; Concatenate the autoloads of all installed packages.
|
||||
(doom--generate-package-autoloads)
|
||||
(print! (success "Package autoloads included")))
|
||||
|
||||
;; Replace autoload paths (only for module autoloads) with absolute
|
||||
;; paths for faster resolution during load and simpler `load-path'
|
||||
(save-excursion
|
||||
(doom--cli-expand-autoload-paths)
|
||||
(print! (success "Expanded module autoload paths")))
|
||||
|
||||
;; Remove `load-path' and `auto-mode-alist' modifications (most of them,
|
||||
;; at least); they are cached later, so all those membership checks are
|
||||
;; unnecessary overhead.
|
||||
(doom--cleanup-package-autoloads)
|
||||
(print! (success "Removed load-path/auto-mode-alist entries"))))
|
||||
;; Byte compile it to give the file a chance to reveal errors (and buy us a
|
||||
;; few marginal performance boosts)
|
||||
(print! (start "Byte-compiling %s...") (relpath doom-package-autoload-file))
|
||||
(when (doom--cli-byte-compile-file doom-package-autoload-file)
|
||||
(print-group!
|
||||
(print! (success "Compiled %s") (relpath doom-package-autoload-file))))))
|
||||
t))
|
||||
(let (autoloads)
|
||||
(dolist (file
|
||||
(seq-filter #'file-readable-p files)
|
||||
(nreverse (delq nil autoloads)))
|
||||
(with-temp-buffer
|
||||
(print! (debug "- Scanning %s") (relpath file doom-emacs-dir))
|
||||
(if literal
|
||||
(insert-file-contents file)
|
||||
(doom-autoloads--scan-file file))
|
||||
(save-excursion
|
||||
(let ((filestr (prin1-to-string file)))
|
||||
(while (re-search-forward "\\_<load-file-name\\_>" nil t)
|
||||
;; `load-file-name' is meaningless in a concatenated
|
||||
;; mega-autoloads file, so we replace references to it with the
|
||||
;; file they came from.
|
||||
(let ((ppss (save-excursion (syntax-ppss))))
|
||||
(or (nth 3 ppss)
|
||||
(nth 4 ppss)
|
||||
(replace-match filestr t t))))))
|
||||
(let ((load-file-name file)
|
||||
(load-path
|
||||
(append (list doom-private-dir)
|
||||
doom-modules-dirs
|
||||
load-path)))
|
||||
(condition-case _
|
||||
(while t
|
||||
(push (doom-autoloads--cleanup-form (read (current-buffer))
|
||||
(not literal))
|
||||
autoloads))
|
||||
(end-of-file)))))))
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
(defcli! (compile c)
|
||||
((recompile-p ["-r" "--recompile"])
|
||||
&rest targets)
|
||||
(core-p ["-c" "--core"])
|
||||
(private-p ["-p" "--private"])
|
||||
(verbose-p ["-v" "--verbose"]))
|
||||
"Byte-compiles your config or selected modules.
|
||||
|
||||
compile [TARGETS...]
|
||||
@@ -11,8 +13,23 @@
|
||||
|
||||
Accepts :core and :private as special arguments, which target Doom's core files
|
||||
and your private config files, respectively. To recompile your packages, use
|
||||
'doom rebuild' instead."
|
||||
(doom-cli-byte-compile targets recompile-p))
|
||||
'doom build' instead."
|
||||
(doom-cli-byte-compile
|
||||
(if (or core-p private-p)
|
||||
(append (when core-p
|
||||
(list (doom-glob doom-emacs-dir "init.el")
|
||||
doom-core-dir))
|
||||
(when private-p
|
||||
(list doom-private-dir)))
|
||||
(append (list (doom-glob doom-emacs-dir "init.el")
|
||||
doom-core-dir)
|
||||
(cl-remove-if-not
|
||||
;; Only compile Doom's modules
|
||||
(lambda (path) (file-in-directory-p path doom-emacs-dir))
|
||||
;; Omit `doom-private-dir', which is always first
|
||||
(cdr (doom-module-load-path)))))
|
||||
recompile-p
|
||||
verbose-p))
|
||||
|
||||
(defcli! clean ()
|
||||
"Delete all *.elc files."
|
||||
@@ -25,16 +42,20 @@ and your private config files, respectively. To recompile your packages, use
|
||||
|
||||
(defun doom--byte-compile-ignore-file-p (path)
|
||||
(let ((filename (file-name-nondirectory path)))
|
||||
(or (string-prefix-p "." filename)
|
||||
(or (not (equal (file-name-extension path) "el"))
|
||||
(member filename (list "packages.el" "doctor.el"))
|
||||
(string-prefix-p "." filename)
|
||||
(string-prefix-p "test-" filename)
|
||||
(not (equal (file-name-extension path) "el"))
|
||||
(member filename (list "packages.el" "doctor.el")))))
|
||||
(string-prefix-p "flycheck_" filename)
|
||||
(string-suffix-p ".example.el" filename))))
|
||||
|
||||
(cl-defun doom-cli-byte-compile (&optional modules recompile-p)
|
||||
(cl-defun doom-cli-byte-compile (&optional targets recompile-p verbose-p)
|
||||
"Byte compiles your emacs configuration.
|
||||
|
||||
init.el is always byte-compiled by this.
|
||||
|
||||
If TARGETS is specified, as a list of direcotries
|
||||
|
||||
If MODULES is specified (a list of module strings, e.g. \"lang/php\"), those are
|
||||
byte-compiled. Otherwise, all enabled modules are byte-compiled, including Doom
|
||||
core. It always ignores unit tests and files with `no-byte-compile' enabled.
|
||||
@@ -47,138 +68,109 @@ Use `doom-clean-byte-compiled-files' or `make clean' to reverse
|
||||
byte-compilation.
|
||||
|
||||
If RECOMPILE-P is non-nil, only recompile out-of-date files."
|
||||
(let ((default-directory doom-emacs-dir)
|
||||
(doom-modules (doom-modules))
|
||||
(byte-compile-verbose doom-debug-mode)
|
||||
(byte-compile-warnings '(not free-vars unresolved noruntime lexical make-local))
|
||||
|
||||
;; In case it is changed during compile-time
|
||||
(auto-mode-alist auto-mode-alist)
|
||||
(noninteractive t)
|
||||
|
||||
targets)
|
||||
|
||||
(let (target-dirs)
|
||||
(dolist (module (delete-dups modules))
|
||||
(pcase module
|
||||
(":core"
|
||||
(push (doom-glob doom-emacs-dir "init.el") targets)
|
||||
(push doom-core-dir target-dirs))
|
||||
(":private"
|
||||
(push doom-private-dir target-dirs))
|
||||
((pred file-directory-p)
|
||||
(push module target-dirs))
|
||||
((pred (string-match "^\\([^/]+\\)/\\([^/]+\\)$"))
|
||||
(push (doom-module-locate-path
|
||||
(doom-keyword-intern (match-string 1 module))
|
||||
(intern (match-string 2 module)))
|
||||
target-dirs))
|
||||
(_ (user-error "%S is not a valid target" module))))
|
||||
|
||||
(and (or (null modules) (member ":private" modules))
|
||||
(not recompile-p)
|
||||
(not (or doom-auto-accept
|
||||
(y-or-n-p
|
||||
(concat "Warning: byte compiling is for advanced users. It will interfere with your\n"
|
||||
"efforts to debug issues. It is not recommended you do it if you frequently\n"
|
||||
"tinker with your Emacs config.\n\n"
|
||||
"Alternatively, use `bin/doom compile :core` instead to byte-compile only the\n"
|
||||
"Doom core files, as these don't change often.\n\n"
|
||||
"If you have issues, please make sure byte-compilation isn't the cause by using\n"
|
||||
"`bin/doom clean` to clear out your *.elc files.\n\n"
|
||||
"Byte-compile anyway?"))))
|
||||
(user-error "Aborting"))
|
||||
(let* ((default-directory doom-emacs-dir)
|
||||
(targets (nreverse (delete-dups targets)))
|
||||
;; In case it is changed during compile-time
|
||||
(auto-mode-alist auto-mode-alist)
|
||||
kill-emacs-hook kill-buffer-query-functions)
|
||||
|
||||
(let ((after-load-functions
|
||||
(if (null targets)
|
||||
after-load-functions
|
||||
;; Assemble el files we want to compile, and preserve in the order
|
||||
;; they are loaded in, so we don't run into any scary catch-22s
|
||||
;; while byte-compiling, like missing macros.
|
||||
(cons (let ((target-dirs (cl-remove-if-not #'file-directory-p targets)))
|
||||
(lambda (path)
|
||||
(and (not (doom--byte-compile-ignore-file-p path))
|
||||
(cl-find-if (doom-partial #'file-in-directory-p path)
|
||||
target-dirs)
|
||||
(cl-pushnew path targets))))
|
||||
after-load-functions))))
|
||||
(doom-log "Reloading Doom in preparation for byte-compilation")
|
||||
;; But first we must be sure that Doom and your private config have been
|
||||
;; fully loaded. Which usually aren't so in an noninteractive session.
|
||||
(let ((doom-interactive-mode 'byte-compile))
|
||||
(doom-initialize)
|
||||
(doom-initialize-packages)
|
||||
(doom-initialize-core))
|
||||
(let ((load-prefer-newer t)
|
||||
(noninteractive t)
|
||||
doom-interactive-p)
|
||||
(doom-initialize 'force)
|
||||
(quiet! (doom-initialize-packages))))
|
||||
|
||||
;;
|
||||
(unless target-dirs
|
||||
(push (doom-glob doom-emacs-dir "init.el") targets)
|
||||
;; If no targets were supplied, then we use your module list.
|
||||
(appendq! target-dirs
|
||||
(list doom-core-dir)
|
||||
(nreverse
|
||||
(cl-remove-if-not
|
||||
(lambda (path) (file-in-directory-p path doom-emacs-dir))
|
||||
;; Omit `doom-private-dir', which is always first
|
||||
(cdr (doom-module-load-path))))))
|
||||
(if (null targets)
|
||||
(print! (info "No targets to %scompile" (if recompile-p "re" "")))
|
||||
(print! (start "%scompiling your config...")
|
||||
(if recompile-p "Re" "Byte-"))
|
||||
|
||||
;; Assemble el files we want to compile; taking into account that MODULES
|
||||
;; may be a list of MODULE/SUBMODULE strings from the command line.
|
||||
(appendq! targets
|
||||
(doom-files-in target-dirs
|
||||
:match "\\.el$"
|
||||
:filter #'doom--byte-compile-ignore-file-p)))
|
||||
(dolist (dir
|
||||
(cl-remove-if-not #'file-directory-p targets)
|
||||
(setq targets (cl-remove-if #'file-directory-p targets)))
|
||||
(prependq! targets
|
||||
(doom-files-in
|
||||
dir :match "\\.el" :filter #'doom--byte-compile-ignore-file-p)))
|
||||
|
||||
(unless targets
|
||||
(print!
|
||||
(if targets
|
||||
(warn "Couldn't find any valid targets")
|
||||
(info "No targets to %scompile" (if recompile-p "re" ""))))
|
||||
(cl-return nil))
|
||||
|
||||
(print!
|
||||
(start (if recompile-p
|
||||
"Recompiling stale elc files..."
|
||||
"Byte-compiling your config (may take a while)...")))
|
||||
(print-group!
|
||||
(require 'use-package)
|
||||
(condition-case e
|
||||
(let ((total-ok 0)
|
||||
(total-fail 0)
|
||||
(total-noop 0)
|
||||
(use-package-defaults use-package-defaults)
|
||||
(use-package-expand-minimally t)
|
||||
kill-emacs-hook kill-buffer-query-functions)
|
||||
;; Prevent packages from being loaded at compile time if they
|
||||
;; don't meet their own predicates.
|
||||
(push (list :no-require t
|
||||
(lambda (_name args)
|
||||
(or (when-let (pred (or (plist-get args :if)
|
||||
(plist-get args :when)))
|
||||
(not (eval pred t)))
|
||||
(when-let (pred (plist-get args :unless))
|
||||
(eval pred t)))))
|
||||
use-package-defaults)
|
||||
|
||||
(unless recompile-p
|
||||
(doom-clean-byte-compiled-files))
|
||||
|
||||
(dolist (target (delete-dups (delq nil targets)))
|
||||
(cl-incf
|
||||
(if (not (or (not recompile-p)
|
||||
(let ((elc-file (byte-compile-dest-file target)))
|
||||
(and (file-exists-p elc-file)
|
||||
(file-newer-than-file-p target elc-file)))))
|
||||
total-noop
|
||||
(pcase (if (doom-file-cookie-p target "if" t)
|
||||
(byte-compile-file target)
|
||||
'no-byte-compile)
|
||||
(`no-byte-compile
|
||||
(print! (info "Ignored %s") (relpath target))
|
||||
total-noop)
|
||||
(`nil
|
||||
(print! (error "Failed to compile %s") (relpath target))
|
||||
total-fail)
|
||||
(_
|
||||
(print! (success "Compiled %s") (relpath target))
|
||||
(load target t t)
|
||||
total-ok)))))
|
||||
(print! (class (if (= total-fail 0) 'success 'error)
|
||||
"%s %d/%d file(s) (%d ignored)")
|
||||
(if recompile-p "Recompiled" "Compiled")
|
||||
total-ok (- (length targets) total-noop)
|
||||
total-noop)
|
||||
t)
|
||||
((debug error)
|
||||
(print! (error "\nThere were breaking errors.\n\n%s")
|
||||
"Reverting changes...")
|
||||
(signal 'doom-error (list 'byte-compile e)))))))
|
||||
(print-group!
|
||||
(require 'use-package)
|
||||
(condition-case-unless-debug e
|
||||
(let* ((total-ok 0)
|
||||
(total-fail 0)
|
||||
(total-noop 0)
|
||||
(byte-compile-verbose nil)
|
||||
(byte-compile-warnings '(not free-vars unresolved noruntime lexical make-local))
|
||||
(byte-compile-dynamic-docstrings t)
|
||||
(use-package-compute-statistics nil)
|
||||
(use-package-defaults use-package-defaults)
|
||||
(use-package-expand-minimally t)
|
||||
(targets (delete-dups targets))
|
||||
(modules (seq-group-by #'doom-module-from-path targets))
|
||||
(total-files (length targets))
|
||||
(total-modules (length modules))
|
||||
(i 0)
|
||||
last-module)
|
||||
;; Prevent packages from being loaded at compile time if they
|
||||
;; don't meet their own predicates.
|
||||
(push (list :no-require t
|
||||
(lambda (_name args)
|
||||
(or (when-let (pred (or (plist-get args :if)
|
||||
(plist-get args :when)))
|
||||
(not (eval pred t)))
|
||||
(when-let (pred (plist-get args :unless))
|
||||
(eval pred t)))))
|
||||
use-package-defaults)
|
||||
(dolist (module-files modules)
|
||||
(cl-incf i)
|
||||
(dolist (target (cdr module-files))
|
||||
(let ((elc-file (byte-compile-dest-file target)))
|
||||
(cl-incf
|
||||
(if (and recompile-p (not (file-newer-than-file-p target elc-file)))
|
||||
total-noop
|
||||
(pcase (if (not (doom-file-cookie-p target "if" t))
|
||||
'no-byte-compile
|
||||
(unless (equal last-module (car module-files))
|
||||
(print! (success "(% 3d/%d) Compiling %s %s module...")
|
||||
i total-modules (caar module-files) (cdar module-files))
|
||||
(setq last-module (car module-files)))
|
||||
(if verbose-p
|
||||
(byte-compile-file target)
|
||||
(quiet! (byte-compile-file target))))
|
||||
(`no-byte-compile
|
||||
(print! (debug "(% 3d/%d) Ignored %s")
|
||||
i total-modules (relpath target))
|
||||
total-noop)
|
||||
(`nil
|
||||
(print! (error "(% 3d/%d) Failed to compile %s")
|
||||
i total-modules (relpath target))
|
||||
total-fail)
|
||||
(_ total-ok)))))))
|
||||
(print! (class (if (= total-fail 0) 'success 'warn)
|
||||
"%s %d/%d file(s) (%d ignored)")
|
||||
(if recompile-p "Recompiled" "Byte-compiled")
|
||||
total-ok total-files
|
||||
total-noop)
|
||||
(= total-fail 0))
|
||||
((debug error)
|
||||
(print! (error "There were breaking errors.\n\n%s")
|
||||
"Reverting changes...")
|
||||
(signal 'doom-error (list 'byte-compile e))))))))
|
||||
|
||||
(defun doom-clean-byte-compiled-files ()
|
||||
"Delete all the compiled elc files in your Emacs configuration and private
|
||||
@@ -187,7 +179,8 @@ module. This does not include your byte-compiled, third party packages.'"
|
||||
(print! (start "Cleaning .elc files"))
|
||||
(print-group!
|
||||
(cl-loop with default-directory = doom-emacs-dir
|
||||
with success = nil
|
||||
with success = 0
|
||||
with esc = (if doom-debug-p "" "\033[1A")
|
||||
for path
|
||||
in (append (doom-glob doom-emacs-dir "*.elc")
|
||||
(doom-files-in doom-private-dir :match "\\.elc$" :depth 1)
|
||||
@@ -195,10 +188,10 @@ module. This does not include your byte-compiled, third party packages.'"
|
||||
(doom-files-in doom-modules-dirs :match "\\.elc$" :depth 4))
|
||||
if (file-exists-p path)
|
||||
do (delete-file path)
|
||||
and do (print! (success "Deleted %s") (relpath path))
|
||||
and do (setq success t)
|
||||
and do (print! (success "\033[KDeleted %s%s") (relpath path) esc)
|
||||
and do (cl-incf success)
|
||||
finally do
|
||||
(print! (if success
|
||||
(success "All elc files deleted")
|
||||
(info "No elc files to clean"))))
|
||||
(print! (if (> success 0)
|
||||
(success "\033[K%d elc files deleted" success)
|
||||
(info "\033[KNo elc files to clean"))))
|
||||
t))
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
;;; core/cli/debug.el -*- lexical-binding: t; -*-
|
||||
|
||||
(load! "autoload/debug" doom-core-dir)
|
||||
|
||||
;;
|
||||
;;; Commands
|
||||
|
||||
(defcli! info
|
||||
((format ["--json" "--md" "--lisp"] "What format to dump info into"))
|
||||
((format ["--json" "--md" "--lisp"] "What format to dump info into"))
|
||||
"Output system info in markdown for bug reports."
|
||||
(pcase format
|
||||
("--json"
|
||||
@@ -24,6 +26,5 @@
|
||||
|
||||
(defcli! (version v) ()
|
||||
"Show version information for Doom & Emacs."
|
||||
:bare t
|
||||
(doom/version)
|
||||
nil)
|
||||
|
||||
@@ -48,8 +48,8 @@ in."
|
||||
|
||||
;; REVIEW Refactor me
|
||||
(print! (start "Checking your Emacs version..."))
|
||||
(when EMACS27+
|
||||
(warn! "Emacs %s detected. Emacs HEAD is unstable and may cause errors."
|
||||
(when EMACS28+
|
||||
(warn! "Emacs %s detected. Doom doesn't support Emacs 28/HEAD. It is unstable and may cause errors."
|
||||
emacs-version))
|
||||
|
||||
(print! (start "Checking for Emacs config conflicts..."))
|
||||
@@ -79,9 +79,8 @@ in."
|
||||
(print! (start "Checking Doom Emacs..."))
|
||||
(condition-case-unless-debug ex
|
||||
(print-group!
|
||||
(let ((doom-interactive-mode 'doctor))
|
||||
(let ((doom-interactive-p 'doctor))
|
||||
(doom-initialize 'force)
|
||||
(doom-initialize-core)
|
||||
(doom-initialize-modules))
|
||||
|
||||
(print! (success "Initialized Doom Emacs %s") doom-version)
|
||||
@@ -100,13 +99,14 @@ in."
|
||||
(when-let (size (ignore-errors (doom-file-size file doom-cache-dir)))
|
||||
(when (> size 1048576) ; larger than 1mb
|
||||
(warn! "%s is too large (%.02fmb). This may cause freezes or odd startup delays"
|
||||
file (/ size 1024))
|
||||
file (/ size 1024 1024.0))
|
||||
(explain! "Consider deleting it from your system (manually)"))))
|
||||
|
||||
(unless (executable-find "rg")
|
||||
(error! "Couldn't find the `rg' binary; this a hard dependecy for Doom, file searches may not work at all"))
|
||||
|
||||
(unless (ignore-errors (executable-find doom-projectile-fd-binary))
|
||||
(warn! "Couldn't find the `fd' binary; project file searches will be slightly slower")
|
||||
(unless (executable-find "rg")
|
||||
(warn! "Couldn't find the `rg' binary either; project file searches will be even slower")))
|
||||
(warn! "Couldn't find the `fd' binary; project file searches will be slightly slower"))
|
||||
|
||||
(require 'projectile)
|
||||
(when (projectile-project-root "~")
|
||||
@@ -123,11 +123,8 @@ in."
|
||||
"both is rarely intentional; you should one or the other."))
|
||||
|
||||
;; Check for fonts
|
||||
(if (not (fboundp 'find-font))
|
||||
(progn
|
||||
(warn! "Warning: unable to detect font")
|
||||
(explain! "The `find-font' function is missing. This could indicate the incorrect "
|
||||
"version of Emacs is being used!"))
|
||||
(if (not (executable-find "fc-list"))
|
||||
(warn! "Warning: unable to detect fonts because fontconfig isn't installed")
|
||||
;; all-the-icons fonts
|
||||
(when (and (pcase system-type
|
||||
(`gnu/linux (concat (or (getenv "XDG_DATA_HOME")
|
||||
@@ -136,14 +133,21 @@ in."
|
||||
(`darwin "~/Library/Fonts/"))
|
||||
(require 'all-the-icons nil t))
|
||||
(with-temp-buffer
|
||||
(insert (cdr (doom-call-process "fc-list")))
|
||||
(dolist (font all-the-icons-font-names)
|
||||
(if (save-excursion (re-search-backward font nil t))
|
||||
(success! "Found font %s" font)
|
||||
(print! (warn "Warning: couldn't find %S font") font)
|
||||
(explain! "You can install it by running `M-x all-the-icons-install-fonts' within Emacs.\n\n"
|
||||
"This could also mean you've installed them in non-standard locations, in which "
|
||||
"case feel free to ignore this warning.")))))))
|
||||
(let ((errors 0))
|
||||
(cl-destructuring-bind (status . output)
|
||||
(doom-call-process "fc-list" "" "file")
|
||||
(if (not (zerop status))
|
||||
(print! (error "There was an error running `fc-list'. Is fontconfig installed correctly?"))
|
||||
(insert (cdr (doom-call-process "fc-list" "" "file")))
|
||||
(dolist (font all-the-icons-font-names)
|
||||
(if (save-excursion (re-search-backward font nil t))
|
||||
(success! "Found font %s" font)
|
||||
(print! (warn "Warning: couldn't find %S font") font)))
|
||||
(when (> errors 0)
|
||||
(explain! "Some all-the-icons fonts were missing.\n\n"
|
||||
"You can install them by running `M-x all-the-icons-install-fonts' within Emacs.\n"
|
||||
"This could also mean you've installed them in non-standard locations, in which "
|
||||
"case feel free to ignore this warning.")))))))))
|
||||
|
||||
(print! (start "Checking for stale elc files in your DOOMDIR..."))
|
||||
(when (file-directory-p doom-private-dir)
|
||||
@@ -161,15 +165,17 @@ in."
|
||||
(condition-case-unless-debug ex
|
||||
(let ((doctor-file (doom-module-path (car key) (cdr key) "doctor.el"))
|
||||
(packages-file (doom-module-path (car key) (cdr key) "packages.el")))
|
||||
(cl-loop for name in (let (doom-packages
|
||||
(cl-loop with doom-output-indent = 6
|
||||
for name in (let (doom-packages
|
||||
doom-disabled-packages)
|
||||
(load packages-file 'noerror 'nomessage)
|
||||
(mapcar #'car doom-packages))
|
||||
unless (or (doom-package-get name :disable)
|
||||
(eval (doom-package-get name :ignore))
|
||||
(plist-member (doom-package-get name :recipe) :local-repo)
|
||||
(doom-package-built-in-p name)
|
||||
(doom-package-installed-p name))
|
||||
do (print! (error "%s is not installed") name))
|
||||
do (print! (error "Missing emacs package: %S") name))
|
||||
(let ((inhibit-message t))
|
||||
(load doctor-file 'noerror 'nomessage)))
|
||||
(file-missing (error! "%s" (error-message-string ex)))
|
||||
|
||||
@@ -1,26 +1,28 @@
|
||||
;;; core/cli/env.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defcli! env
|
||||
((clear-p ["-c" "--clear"] "Clear and delete your envvar file")
|
||||
(outputfile ["-o" PATH]
|
||||
"Generate the envvar file at PATH. Note that envvar files that aren't in
|
||||
`doom-env-file' won't be loaded automatically at startup. You will need to
|
||||
load them manually from your private config with the `doom-load-envvars-file'
|
||||
((allow ["-a" "--allow" regexp] "An envvar whitelist regexp")
|
||||
(reject ["-r" "--reject" regexp] "An envvar blacklist regexp")
|
||||
(clear-p ["-c" "--clear"] "Clear and delete your envvar file")
|
||||
(outputfile ["-o" path]
|
||||
"Generate the envvar file at PATH. Envvar files that aren't in
|
||||
`doom-env-file' won't be loaded automatically at startup. You will need to load
|
||||
them manually from your private config with the `doom-load-envvars-file'
|
||||
function."))
|
||||
"Creates or regenerates your envvars file.
|
||||
|
||||
The envvars file is created by scraping your (interactive) shell environment
|
||||
into newline-delimited KEY=VALUE pairs. Typically by running '$SHELL -ic env'
|
||||
(or '$SHELL -c set' on windows). Doom loads this file at startup (if it exists)
|
||||
to ensure Emacs mirrors your shell environment (particularly to ensure PATH and
|
||||
The envvars file is created by scraping the current shell environment into
|
||||
newline-delimited KEY=VALUE pairs. Typically by running '$SHELL -ic env' (or
|
||||
'$SHELL -c set' on windows). Doom loads this file at startup (if it exists) to
|
||||
ensure Emacs mirrors your shell environment (particularly to ensure PATH and
|
||||
SHELL are correctly set).
|
||||
|
||||
This is useful in cases where you cannot guarantee that Emacs (or the daemon)
|
||||
will be launched from the correct environment (e.g. on MacOS or through certain
|
||||
app launchers on Linux).
|
||||
|
||||
This file is automatically regenerated when you run this command or 'doom
|
||||
refresh'. However, 'doom refresh' will only regenerate this file if it exists.
|
||||
This file is automatically regenerated when you run this command or 'doom sync'.
|
||||
However, 'doom sync' will only regenerate this file if it exists.
|
||||
|
||||
Why this over exec-path-from-shell?
|
||||
|
||||
@@ -36,96 +38,91 @@ Why this over exec-path-from-shell?
|
||||
|
||||
I'd rather it inherit your shell environment /correctly/ (and /completely/)
|
||||
or not at all. It frontloads the debugging process rather than hiding it
|
||||
until it you least want to deal with it."
|
||||
until you least want to deal with it."
|
||||
(let ((env-file (expand-file-name (or outputfile doom-env-file))))
|
||||
(cond (clear-p
|
||||
(unless (file-exists-p env-file)
|
||||
(user-error! "%S does not exist to be cleared"
|
||||
(path env-file)))
|
||||
(delete-file env-file)
|
||||
(print! (success "Successfully deleted %S")
|
||||
(path env-file)))
|
||||
|
||||
(args
|
||||
(user-error "I don't understand 'doom env %s'"
|
||||
(string-join args " ")))
|
||||
|
||||
((doom-cli-reload-env-file 'force env-file)))))
|
||||
(if (null clear-p)
|
||||
(doom-cli-reload-env-file
|
||||
'force env-file (list allow) (list reject))
|
||||
(unless (file-exists-p env-file)
|
||||
(user-error! "%S does not exist to be cleared"
|
||||
(path env-file)))
|
||||
(delete-file env-file)
|
||||
(print! (success "Successfully deleted %S")
|
||||
(path env-file)))))
|
||||
|
||||
|
||||
;;
|
||||
;; Helpers
|
||||
|
||||
(defvar doom-env-ignored-vars
|
||||
(defvar doom-env-blacklist
|
||||
'("^DBUS_SESSION_BUS_ADDRESS$"
|
||||
"^GPG_AGENT_INFO$"
|
||||
"^GPG_TTY$"
|
||||
"^HOME$"
|
||||
"^PS1$"
|
||||
"^PWD$"
|
||||
"^R?PROMPT$"
|
||||
"^SSH_AGENT_PID$"
|
||||
"^SSH_AUTH_SOCK$"
|
||||
"^TERM$"
|
||||
"^GPG_AGENT_INFO$" "^\\(SSH\\|GPG\\)_TTY$"
|
||||
"^SSH_\\(AUTH_SOCK\\|AGENT_PID\\)$"
|
||||
"^HOME$" "^PWD$" "^PS1$" "^R?PROMPT$" "^TERM$"
|
||||
;; Doom envvars
|
||||
"^DEBUG$"
|
||||
"^INSECURE$"
|
||||
"^YES$"
|
||||
"^__")
|
||||
"^DEBUG$" "^INSECURE$" "^YES$" "^__")
|
||||
"Environment variables to not save in `doom-env-file'.
|
||||
|
||||
Each string is a regexp, matched against variable names to omit from
|
||||
`doom-env-file'.")
|
||||
|
||||
(defun doom-cli-reload-env-file (&optional force-p env-file)
|
||||
(defvar doom-env-whitelist '()
|
||||
"A whitelist for envvars to save in `doom-env-file'.
|
||||
|
||||
This overrules `doom-env-ignored-vars'. Each string is a regexp, matched against
|
||||
variable names to omit from `doom-env-file'.")
|
||||
|
||||
(defun doom-cli-reload-env-file (&optional force-p env-file whitelist blacklist)
|
||||
"Generates `doom-env-file', if it doesn't exist (or if FORCE-P).
|
||||
|
||||
This scrapes the variables from your shell environment by running
|
||||
`doom-env-executable' through `shell-file-name' with `doom-env-switches'. By
|
||||
default, on Linux, this is '$SHELL -ic /usr/bin/env'. Variables in
|
||||
`doom-env-ignored-vars' are removed."
|
||||
(let ((env-file (if env-file
|
||||
(expand-file-name env-file)
|
||||
doom-env-file)))
|
||||
(let ((env-file (if env-file (expand-file-name env-file) doom-env-file))
|
||||
(process-environment doom--initial-process-environment))
|
||||
(when (or force-p (not (file-exists-p env-file)))
|
||||
(with-temp-file env-file
|
||||
(setq-local coding-system-for-write 'utf-8)
|
||||
(print! (start "%s envvars file at %S")
|
||||
(if (file-exists-p env-file)
|
||||
"Regenerating"
|
||||
"Generating")
|
||||
(path env-file))
|
||||
(let ((process-environment doom--initial-process-environment))
|
||||
(print! (info "Scraping shell environment"))
|
||||
(print-group!
|
||||
(when doom-interactive-mode
|
||||
(user-error "'doom env' must be run on the command line, not an interactive session"))
|
||||
(goto-char (point-min))
|
||||
(insert
|
||||
(concat
|
||||
"# -*- mode: dotenv -*-\n"
|
||||
(format "# Generated from a %s shell environent\n" shell-file-name)
|
||||
"# ---------------------------------------------------------------------------\n"
|
||||
"# This file was auto-generated by `doom env'. It contains a list of environment\n"
|
||||
"# variables scraped from your default shell (excluding variables blacklisted\n"
|
||||
"# in doom-env-ignored-vars).\n"
|
||||
"#\n"
|
||||
(if (file-equal-p env-file doom-env-file)
|
||||
(concat "# It is NOT safe to edit this file. Changes will be overwritten next time you\n"
|
||||
"# run 'doom refresh'. To create a safe-to-edit envvar file use:\n#\n"
|
||||
"# doom env -o ~/.doom.d/myenv\n#\n"
|
||||
"# And load it with (doom-load-envvars-file \"~/.doom.d/myenv\").\n")
|
||||
(concat "# This file is safe to edit by hand, but needs to be loaded manually with:\n#\n"
|
||||
"# (doom-load-envvars-file \"path/to/this/file\")\n#\n"
|
||||
"# Use 'doom env -o path/to/this/file' to regenerate it."))
|
||||
"# ---------------------------------------------------------------------------\n\n"))
|
||||
;; We assume that this noninteractive session was spawned from the
|
||||
;; user's interactive shell, therefore we just dump
|
||||
;; `process-environment' to a file.
|
||||
(dolist (env process-environment)
|
||||
(if (cl-find-if (doom-rpartial #'string-match-p (car (split-string env "=")))
|
||||
doom-env-ignored-vars)
|
||||
(print! (info "Ignoring %s") env)
|
||||
(insert env "\n")))
|
||||
(print! (success "Successfully generated %S")
|
||||
(path env-file))
|
||||
t))))))
|
||||
(print-group!
|
||||
(when doom-interactive-p
|
||||
(user-error "'doom env' must be run on the command line, not an interactive session"))
|
||||
(goto-char (point-min))
|
||||
(insert
|
||||
(concat
|
||||
"# -*- mode: sh -*-\n"
|
||||
"# ---------------------------------------------------------------------------\n"
|
||||
"# This file was auto-generated by `doom env'. It contains a list of environment\n"
|
||||
"# variables scraped from your default shell (excluding variables blacklisted\n"
|
||||
"# in doom-env-ignored-vars).\n"
|
||||
"#\n"
|
||||
(if (file-equal-p env-file doom-env-file)
|
||||
(concat "# It is NOT safe to edit this file. Changes will be overwritten next time you\n"
|
||||
"# run 'doom sync'. To create a safe-to-edit envvar file use:\n#\n"
|
||||
"# doom env -o ~/.doom.d/myenv\n#\n"
|
||||
"# And load it with (doom-load-envvars-file \"~/.doom.d/myenv\").\n")
|
||||
(concat "# This file is safe to edit by hand, but remember to preserve the null bytes at\n"
|
||||
"# the end of each line! needs to be loaded manually with:\n#\n"
|
||||
"# (doom-load-envvars-file \"path/to/this/file\")\n#\n"
|
||||
"# Use 'doom env -o path/to/this/file' to regenerate it."))
|
||||
"# ---------------------------------------------------------------------------\n\0\n"))
|
||||
;; We assume that this noninteractive session was spawned from the
|
||||
;; user's interactive shell, therefore we just dump
|
||||
;; `process-environment' to a file.
|
||||
(dolist (env process-environment)
|
||||
(if (cl-find-if (doom-rpartial #'string-match-p (car (split-string env "=")))
|
||||
(remq nil (append blacklist doom-env-blacklist)))
|
||||
(if (not (cl-find-if (doom-rpartial #'string-match-p (car (split-string env "=")))
|
||||
(remq nil (append whitelist doom-env-whitelist))))
|
||||
(print! (info "Ignoring %s") env)
|
||||
(print! (info "Whitelisted %s") env)
|
||||
(insert env "\0\n"))
|
||||
(insert env "\0\n")))
|
||||
(print! (success "Successfully generated %S")
|
||||
(path env-file))
|
||||
t)))))
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
((noconfig-p ["--no-config"] "Don't create DOOMDIR or dummy files therein")
|
||||
(noenv-p ["--no-env"] "Don't generate an envvars file (see 'doom help env')")
|
||||
(noinstall-p ["--no-install"] "Don't auto-install packages")
|
||||
(nofonts-p ["--no-fonts"] "Don't install (or prompt to install) all-the-icons fonts")
|
||||
&rest _args)
|
||||
(nofonts-p ["--no-fonts"] "Don't install (or prompt to install) all-the-icons fonts"))
|
||||
"Installs and sets up Doom Emacs for the first time.
|
||||
|
||||
This command does the following:
|
||||
@@ -24,7 +23,6 @@ DOOMDIR environment variable. e.g.
|
||||
|
||||
doom -p ~/.config/doom install
|
||||
DOOMDIR=~/.config/doom doom install"
|
||||
:bare t
|
||||
(print! (green "Installing Doom Emacs!\n"))
|
||||
(let ((default-directory (doom-path "~")))
|
||||
;; Create `doom-private-dir'
|
||||
@@ -37,34 +35,20 @@ DOOMDIR environment variable. e.g.
|
||||
|
||||
;; Create init.el, config.el & packages.el
|
||||
(mapc (lambda (file)
|
||||
(cl-destructuring-bind (filename . fn) file
|
||||
(cl-destructuring-bind (filename . template) file
|
||||
(if (file-exists-p! filename doom-private-dir)
|
||||
(print! (warn "%s already exists, skipping") filename)
|
||||
(print! (info "Creating %s%s") (relpath doom-private-dir) filename)
|
||||
(with-temp-file (doom-path doom-private-dir filename)
|
||||
(funcall fn))
|
||||
(insert-file-contents template))
|
||||
(print! (success "Done!")))))
|
||||
'(("init.el" .
|
||||
(lambda ()
|
||||
(insert-file-contents (doom-path doom-emacs-dir "init.example.el"))))
|
||||
("config.el" .
|
||||
(lambda ()
|
||||
(insert! ";;; %sconfig.el -*- lexical-binding: t; -*-\n\n"
|
||||
";; Place your private configuration here\n"
|
||||
((relpath doom-private-dir)))))
|
||||
("packages.el" .
|
||||
(lambda ()
|
||||
(insert! ";; -*- no-byte-compile: t; -*-\n;;; %spackages.el\n\n"
|
||||
";;; Examples:\n"
|
||||
";; (package! some-package)\n"
|
||||
";; (package! another-package :recipe (:host github :repo \"username/repo\"))\n"
|
||||
";; (package! builtin-package :disable t)\n"
|
||||
((relpath doom-private-dir))))))))
|
||||
`(("init.el" . ,(doom-path doom-emacs-dir "init.example.el"))
|
||||
("config.el" . ,(doom-path doom-core-dir "templates/config.example.el"))
|
||||
("packages.el" . ,(doom-path doom-core-dir "templates/packages.example.el")))))
|
||||
|
||||
;; In case no init.el was present the first time `doom-initialize-modules' was
|
||||
;; called in core.el (e.g. on first install)
|
||||
(doom-initialize 'force 'noerror)
|
||||
(doom-initialize-modules)
|
||||
(doom-initialize-modules 'force 'no-config)
|
||||
|
||||
;; Ask if user would like an envvar file generated
|
||||
(if noenv-p
|
||||
@@ -72,7 +56,7 @@ DOOMDIR environment variable. e.g.
|
||||
(if (file-exists-p doom-env-file)
|
||||
(print! (info "Envvar file already exists, skipping"))
|
||||
(when (or doom-auto-accept
|
||||
(y-or-n-p "Generate an env file? (see `doom help env` for details)"))
|
||||
(y-or-n-p "Generate an envvar file? (see `doom help env` for details)"))
|
||||
(doom-cli-reload-env-file 'force-p))))
|
||||
|
||||
;; Install Doom packages
|
||||
@@ -82,21 +66,29 @@ DOOMDIR environment variable. e.g.
|
||||
(doom-cli-packages-install))
|
||||
|
||||
(print! "Regenerating autoloads files")
|
||||
(doom-cli-reload-autoloads nil 'force-p)
|
||||
(doom-autoloads-reload)
|
||||
|
||||
(if nofonts-p
|
||||
(print! (warn "Not installing fonts, as requested"))
|
||||
(when (or doom-auto-accept
|
||||
(y-or-n-p "Download and install all-the-icon's fonts?"))
|
||||
(require 'all-the-icons)
|
||||
(let ((window-system (cond (IS-MAC 'ns)
|
||||
(IS-LINUX 'x))))
|
||||
(all-the-icons-install-fonts 'yes))))
|
||||
(cond (nofonts-p)
|
||||
(IS-WINDOWS
|
||||
(print! (warn "Doom cannot install all-the-icons' fonts on Windows!\n"))
|
||||
(print-group!
|
||||
(print!
|
||||
(concat "You'll have to do so manually:\n\n"
|
||||
" 1. Launch Doom Emacs\n"
|
||||
" 2. Execute 'M-x all-the-icons-install-fonts' to download the fonts\n"
|
||||
" 3. Open the download location in windows explorer\n"
|
||||
" 4. Open each font file to install them"))))
|
||||
((or doom-auto-accept
|
||||
(y-or-n-p "Download and install all-the-icon's fonts?"))
|
||||
(require 'all-the-icons)
|
||||
(let ((window-system (cond (IS-MAC 'ns)
|
||||
(IS-LINUX 'x))))
|
||||
(all-the-icons-install-fonts 'yes))))
|
||||
|
||||
(when (file-exists-p "~/.emacs")
|
||||
(print! (warn "A ~/.emacs file was detected. This conflicts with Doom and should be deleted!")))
|
||||
|
||||
(print! (success "\nFinished! Doom is ready to go!\n"))
|
||||
(with-temp-buffer
|
||||
(doom-template-insert "QUICKSTART_INTRO")
|
||||
(print! (buffer-string)))))
|
||||
(insert-file-contents (doom-glob doom-core-dir "templates/QUICKSTART_INTRO"))
|
||||
(print! "%s" (buffer-string)))))
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
;; -*- no-byte-compile: t; -*-
|
||||
;;; core/cli/packages.el
|
||||
|
||||
(defcli! (update u) ()
|
||||
(defcli! (update u)
|
||||
((discard-p ["--discard"] "All local changes to packages are discarded"))
|
||||
"Updates packages.
|
||||
|
||||
This works by fetching all installed package repos and checking the distance
|
||||
@@ -10,10 +11,10 @@ between HEAD and FETCH_HEAD. This can take a while.
|
||||
This excludes packages whose `package!' declaration contains a non-nil :freeze
|
||||
or :ignore property."
|
||||
(straight-check-all)
|
||||
(doom-cli-reload-core-autoloads)
|
||||
(when (doom-cli-packages-update)
|
||||
(doom-cli-reload-package-autoloads 'force-p))
|
||||
t)
|
||||
(let ((doom-auto-discard discard-p))
|
||||
(when (doom-cli-packages-update)
|
||||
(doom-autoloads-reload))
|
||||
t))
|
||||
|
||||
(defcli! (build b)
|
||||
((rebuild-p ["-r"] "Only rebuild packages that need rebuilding"))
|
||||
@@ -23,7 +24,7 @@ This ensures that all needed files are symlinked from their package repo and
|
||||
their elisp files are byte-compiled. This is especially necessary if you upgrade
|
||||
Emacs (as byte-code is generally not forward-compatible)."
|
||||
(when (doom-cli-packages-build (not rebuild-p))
|
||||
(doom-cli-reload-package-autoloads 'force-p))
|
||||
(doom-autoloads-reload))
|
||||
t)
|
||||
|
||||
(defcli! (purge p)
|
||||
@@ -46,7 +47,7 @@ list remains lean."
|
||||
(not norepos-p)
|
||||
(not nobuilds-p)
|
||||
regraft-p)
|
||||
(doom-cli-reload-package-autoloads 'force-p))
|
||||
(doom-autoloads-reload))
|
||||
t)
|
||||
|
||||
;; (defcli! rollback () ; TODO doom rollback
|
||||
@@ -57,144 +58,248 @@ list remains lean."
|
||||
;;
|
||||
;;; Library
|
||||
|
||||
(defun doom--same-commit-p (abbrev-ref ref)
|
||||
(and (stringp abbrev-ref)
|
||||
(stringp ref)
|
||||
(string-match-p (concat "^" (regexp-quote abbrev-ref))
|
||||
ref)))
|
||||
|
||||
(defun doom--abbrev-commit (commit &optional full)
|
||||
(if full commit (substring commit 0 7)))
|
||||
|
||||
(defun doom--commit-log-between (start-ref end-ref)
|
||||
(and (straight--call
|
||||
"git" "log" "--oneline" "--no-merges"
|
||||
"-n" "25" end-ref (concat "^" (regexp-quote start-ref)))
|
||||
(straight--process-get-output)))
|
||||
|
||||
(defun doom--barf-if-incomplete-packages ()
|
||||
(let ((straight-safe-mode t))
|
||||
(condition-case _ (straight-check-all)
|
||||
(error (user-error "Package state is incomplete. Run 'doom sync' first")))))
|
||||
|
||||
(defmacro doom--with-package-recipes (recipes binds &rest body)
|
||||
(declare (indent 2))
|
||||
(let ((recipe-var (make-symbol "recipe"))
|
||||
(recipes-var (make-symbol "recipes")))
|
||||
`(let* ((,recipes-var ,recipes)
|
||||
(built ())
|
||||
(straight-use-package-pre-build-functions
|
||||
(cons (lambda (pkg &rest _) (cl-pushnew pkg built :test #'equal))
|
||||
straight-use-package-pre-build-functions)))
|
||||
(dolist (,recipe-var ,recipes-var (nreverse built))
|
||||
(cl-block nil
|
||||
(straight--with-plist (append (list :recipe ,recipe-var) ,recipe-var)
|
||||
,(doom-enlist binds)
|
||||
,@body))))))
|
||||
|
||||
(defvar doom--cli-updated-recipes nil)
|
||||
(defun doom--cli-recipes-update ()
|
||||
"Updates straight and recipe repos."
|
||||
(unless doom--cli-updated-recipes
|
||||
(straight--make-build-cache-available)
|
||||
(print! (start "Updating recipe repos..."))
|
||||
(print-group!
|
||||
(doom--with-package-recipes
|
||||
(delq
|
||||
nil (mapcar (doom-rpartial #'gethash straight--repo-cache)
|
||||
(mapcar #'symbol-name straight-recipe-repositories)))
|
||||
(recipe package type local-repo)
|
||||
(let ((esc (unless doom-debug-p "\033[1A"))
|
||||
(ref (straight-vc-get-commit type local-repo))
|
||||
newref output)
|
||||
(print! (start "\033[KUpdating recipes for %s...%s") package esc)
|
||||
(when (straight-vc-fetch-from-remote recipe)
|
||||
(setq output (straight--process-get-output))
|
||||
(straight-merge-package package)
|
||||
(unless (equal ref (setq newref (straight-vc-get-commit type local-repo)))
|
||||
(print! (success "\033[K%s updated (%s -> %s)")
|
||||
package
|
||||
(doom--abbrev-commit ref)
|
||||
(doom--abbrev-commit newref))
|
||||
(unless (string-empty-p output)
|
||||
(print-group! (print! (info "%s" output)))))))))
|
||||
(setq straight--recipe-lookup-cache (make-hash-table :test #'eq)
|
||||
doom--cli-updated-recipes t)))
|
||||
|
||||
|
||||
(defun doom-cli-packages-install ()
|
||||
"Installs missing packages.
|
||||
|
||||
This function will install any primary package (i.e. a package with a `package!'
|
||||
declaration) or dependency thereof that hasn't already been."
|
||||
(print! (start "Installing & building packages..."))
|
||||
(print-group!
|
||||
(let ((n 0))
|
||||
(dolist (package (hash-table-keys straight--recipe-cache))
|
||||
(straight--with-plist (gethash package straight--recipe-cache)
|
||||
(local-repo)
|
||||
(let ((existed-p (file-directory-p (straight--repos-dir package))))
|
||||
(condition-case-unless-debug e
|
||||
(and (straight-use-package (intern package) nil nil (make-string (1- (or doom-format-indent 1)) 32))
|
||||
(not existed-p)
|
||||
(file-directory-p (straight--repos-dir package))
|
||||
(cl-incf n))
|
||||
(error
|
||||
(signal 'doom-package-error
|
||||
(list e (straight--process-get-output))))))))
|
||||
(if (= n 0)
|
||||
(ignore (print! (success "No packages need to be installed")))
|
||||
(print! (success "Installed & built %d packages") n)
|
||||
t))))
|
||||
(doom-initialize-packages)
|
||||
(print! (start "Installing packages..."))
|
||||
(let ((pinned (doom-package-pinned-list)))
|
||||
(print-group!
|
||||
(if-let (built
|
||||
(doom--with-package-recipes (doom-package-recipe-list)
|
||||
(recipe package type local-repo)
|
||||
(unless (file-directory-p (straight--repos-dir local-repo))
|
||||
(doom--cli-recipes-update))
|
||||
(condition-case-unless-debug e
|
||||
(let ((straight-use-package-pre-build-functions
|
||||
(cons (lambda (pkg &rest _)
|
||||
(when-let (commit (cdr (assoc pkg pinned)))
|
||||
(print! (info "Checked out %s") commit)))
|
||||
straight-use-package-pre-build-functions)))
|
||||
(straight-use-package (intern package)))
|
||||
(error
|
||||
(signal 'doom-package-error (list package e))))))
|
||||
(print! (success "Installed %d packages")
|
||||
(length built))
|
||||
(print! (info "No packages need to be installed"))
|
||||
nil))))
|
||||
|
||||
|
||||
(defun doom-cli-packages-build (&optional force-p)
|
||||
"(Re)build all packages."
|
||||
(doom-initialize-packages)
|
||||
(print! (start "(Re)building %spackages...") (if force-p "all " ""))
|
||||
(print-group!
|
||||
(let ((n 0))
|
||||
(if force-p
|
||||
(let ((straight--packages-to-rebuild :all)
|
||||
(straight--packages-not-to-rebuild (make-hash-table :test #'equal)))
|
||||
(dolist (package (hash-table-keys straight--recipe-cache))
|
||||
(straight-use-package
|
||||
(intern package) nil (lambda (_) (cl-incf n) nil)
|
||||
(make-string (1- (or doom-format-indent 1)) 32))))
|
||||
(dolist (recipe (hash-table-values straight--recipe-cache))
|
||||
(straight--with-plist recipe (package local-repo no-build)
|
||||
(unless (or no-build (null local-repo))
|
||||
;; REVIEW We do these modification checks manually because
|
||||
;; Straight's checks seem to miss stale elc files. Need
|
||||
;; more tests to confirm this.
|
||||
(when (or (ignore-errors
|
||||
(gethash package straight--packages-to-rebuild))
|
||||
(gethash package straight--cached-package-modifications)
|
||||
(not (file-directory-p (straight--build-dir package)))
|
||||
(cl-loop for file
|
||||
in (doom-files-in (straight--build-dir package)
|
||||
:match "\\.el$"
|
||||
:full t)
|
||||
for elc-file = (byte-compile-dest-file file)
|
||||
if (and (file-exists-p elc-file)
|
||||
(file-newer-than-file-p file elc-file))
|
||||
return t))
|
||||
(let ((straight-use-package-pre-build-functions
|
||||
straight-use-package-pre-build-functions))
|
||||
(add-hook 'straight-use-package-pre-build-functions
|
||||
(lambda (&rest _) (cl-incf n)))
|
||||
(let ((straight--packages-to-rebuild :all)
|
||||
(straight--packages-not-to-rebuild (make-hash-table :test #'equal)))
|
||||
(straight-use-package
|
||||
(intern package) nil nil
|
||||
(make-string (or doom-format-indent 0) 32)))
|
||||
(straight--byte-compile-package recipe)
|
||||
(dolist (dep (straight--get-dependencies package))
|
||||
(when-let (recipe (gethash dep straight--recipe-cache))
|
||||
(straight--byte-compile-package recipe)))))))))
|
||||
(if (= n 0)
|
||||
(ignore (print! (success "No packages need rebuilding")))
|
||||
(doom--finalize-straight)
|
||||
(print! (success "Rebuilt %d package(s)" n))
|
||||
t))))
|
||||
(let ((straight-check-for-modifications
|
||||
(when (file-directory-p (straight--modified-dir))
|
||||
'(find-when-checking)))
|
||||
(straight--allow-find
|
||||
(and straight-check-for-modifications
|
||||
(executable-find straight-find-executable)
|
||||
t))
|
||||
(straight--packages-not-to-rebuild
|
||||
(or straight--packages-not-to-rebuild (make-hash-table :test #'equal)))
|
||||
(straight--packages-to-rebuild
|
||||
(or (if force-p :all straight--packages-to-rebuild)
|
||||
(make-hash-table :test #'equal)))
|
||||
(recipes (doom-package-recipe-list)))
|
||||
(unless force-p
|
||||
(straight--make-build-cache-available))
|
||||
(if-let (built
|
||||
(doom--with-package-recipes recipes (package local-repo recipe)
|
||||
(unless force-p
|
||||
;; Ensure packages with outdated files/bytecode are rebuilt
|
||||
(let ((build-dir (straight--build-dir package))
|
||||
(repo-dir (straight--repos-dir local-repo)))
|
||||
(and (or (file-newer-than-file-p repo-dir build-dir)
|
||||
(file-exists-p (straight--modified-dir (or local-repo package)))
|
||||
;; Doesn't make sense to compare el and elc files
|
||||
;; when the former isn't a symlink to their source.
|
||||
(when straight-use-symlinks
|
||||
(cl-loop for file
|
||||
in (doom-files-in build-dir :match "\\.el$" :full t)
|
||||
for elc-file = (byte-compile-dest-file file)
|
||||
if (and (file-exists-p elc-file)
|
||||
(file-newer-than-file-p file elc-file))
|
||||
return t)))
|
||||
(not (plist-get recipe :no-build))
|
||||
(puthash package t straight--packages-to-rebuild))))
|
||||
(straight-use-package (intern package))))
|
||||
(print! (success "Rebuilt %d package(s)") (length built))
|
||||
(print! (success "No packages need rebuilding"))
|
||||
nil))))
|
||||
|
||||
|
||||
(defun doom-cli-packages-update ()
|
||||
"Updates packages."
|
||||
(print! (start "Updating packages (this may take a while)..."))
|
||||
;; TODO Refactor me
|
||||
(let ((straight--repos-dir (straight--repos-dir))
|
||||
(straight--packages-to-rebuild (make-hash-table :test #'equal))
|
||||
(total (hash-table-count straight--repo-cache))
|
||||
(i 1)
|
||||
errors)
|
||||
(print-group!
|
||||
(dolist (recipe (hash-table-values straight--repo-cache))
|
||||
(straight--with-plist recipe (package type local-repo)
|
||||
(doom-initialize-packages)
|
||||
(doom--barf-if-incomplete-packages)
|
||||
(let* ((repo-dir (straight--repos-dir))
|
||||
(pinned (doom-package-pinned-list))
|
||||
(recipes (doom-package-recipe-list))
|
||||
(packages-to-rebuild (make-hash-table :test 'equal))
|
||||
(repos-to-rebuild (make-hash-table :test 'equal))
|
||||
(total (length recipes))
|
||||
(esc (unless doom-debug-p "\033[1A"))
|
||||
(i 0)
|
||||
errors)
|
||||
(when recipes
|
||||
(doom--cli-recipes-update))
|
||||
(print! (start "Updating packages (this may take a while)..."))
|
||||
(doom--with-package-recipes recipes (recipe package type local-repo)
|
||||
(cl-incf i)
|
||||
(print-group!
|
||||
(unless (straight--repository-is-available-p recipe)
|
||||
(print! (error "(%d/%d) Couldn't find local repo for %s") i total package)
|
||||
(cl-return))
|
||||
(when (gethash local-repo repos-to-rebuild)
|
||||
(puthash package t packages-to-rebuild)
|
||||
(print! (success "(%d/%d) %s was updated indirectly (with %s)") i total package local-repo)
|
||||
(cl-return))
|
||||
(let ((default-directory (straight--repos-dir local-repo)))
|
||||
(unless (file-in-directory-p default-directory repo-dir)
|
||||
(print! (warn "(%d/%d) Skipping %s because it is local") i total package)
|
||||
(cl-return))
|
||||
(when (eq type 'git)
|
||||
(unless (file-exists-p ".git")
|
||||
(error "%S is not a valid repository" package)))
|
||||
(condition-case-unless-debug e
|
||||
(let ((default-directory (straight--repos-dir local-repo)))
|
||||
(if (not (file-in-directory-p default-directory straight--repos-dir))
|
||||
(print! (warn "[%d/%d] Skipping %s because it is local")
|
||||
i total package)
|
||||
(let ((commit (straight-vc-get-commit type local-repo)))
|
||||
(if (not (straight-vc-fetch-from-remote recipe))
|
||||
(print! (warn "\033[K(%d/%d) Failed to fetch %s" i total package))
|
||||
(let ((output (straight--process-get-output)))
|
||||
(let ((ref (straight-vc-get-commit type local-repo))
|
||||
(target-ref
|
||||
(cdr (or (assoc local-repo pinned)
|
||||
(assoc package pinned))))
|
||||
output)
|
||||
(or (cond
|
||||
((not (stringp target-ref))
|
||||
(print! (start "\033[K(%d/%d) Fetching %s...%s") i total package esc)
|
||||
(when (straight-vc-fetch-from-remote recipe)
|
||||
(setq output (straight--process-get-output))
|
||||
(straight-merge-package package)
|
||||
(let ((newcommit (straight-vc-get-commit type local-repo)))
|
||||
(if (string= commit newcommit)
|
||||
(print! (start "\033[K(%d/%d) %s is up-to-date\033[1A") i total package)
|
||||
(ignore-errors
|
||||
(delete-directory (straight--build-dir package) 'recursive))
|
||||
(puthash package t straight--packages-to-rebuild)
|
||||
(print! (info "\033[K(%d/%d) Updating %s...") i total package)
|
||||
(unless (string-empty-p output)
|
||||
(print-group!
|
||||
(print! (info "%s") output)
|
||||
(when (eq type 'git)
|
||||
(straight--call "git" "log" "--oneline" newcommit (concat "^" commit))
|
||||
(print-group!
|
||||
(print! "%s" (straight--process-get-output))))))
|
||||
(print! (success "(%d/%d) %s updated (%s -> %s)") i total package
|
||||
(substring commit 0 7)
|
||||
(substring newcommit 0 7))))))))
|
||||
(cl-incf i))
|
||||
(setq target-ref (straight-vc-get-commit type local-repo))
|
||||
(or (not (doom--same-commit-p target-ref ref))
|
||||
(cl-return))))
|
||||
|
||||
((doom--same-commit-p target-ref ref)
|
||||
(print! (info "\033[K(%d/%d) %s is up-to-date...%s") i total package esc)
|
||||
(cl-return))
|
||||
|
||||
((if (straight-vc-commit-present-p recipe target-ref)
|
||||
(print! (start "\033[K(%d/%d) Checking out %s (%s)...%s")
|
||||
i total package (doom--abbrev-commit target-ref) esc)
|
||||
(print! (start "\033[K(%d/%d) Fetching %s...%s") i total package esc)
|
||||
(and (straight-vc-fetch-from-remote recipe)
|
||||
(straight-vc-commit-present-p recipe target-ref)))
|
||||
(straight-vc-check-out-commit recipe target-ref)
|
||||
(or (not (eq type 'git))
|
||||
(setq output (doom--commit-log-between ref target-ref)))
|
||||
(doom--same-commit-p target-ref (straight-vc-get-commit type local-repo)))
|
||||
|
||||
((print! (start "\033[K(%d/%d) Re-cloning %s...") i total local-repo esc)
|
||||
(let ((repo (straight--repos-dir local-repo))
|
||||
(straight-vc-git-default-clone-depth 'full))
|
||||
(delete-directory repo 'recursive)
|
||||
(print-group!
|
||||
(straight-use-package (intern package) nil 'no-build))
|
||||
(prog1 (file-directory-p repo)
|
||||
(or (not (eq type 'git))
|
||||
(setq output (doom--commit-log-between ref target-ref)))))))
|
||||
(progn
|
||||
(print! (warn "\033[K(%d/%d) Failed to fetch %s")
|
||||
i total local-repo)
|
||||
(unless (string-empty-p output)
|
||||
(print-group! (print! (info "%s" output))))
|
||||
(cl-return)))
|
||||
(puthash local-repo t repos-to-rebuild)
|
||||
(puthash package t packages-to-rebuild)
|
||||
(unless (string-empty-p output)
|
||||
(print! (start "\033[K(%d/%d) Updating %s...") i total local-repo)
|
||||
(print-group! (print! "%s" (indent 2 output))))
|
||||
(print! (success "\033[K(%d/%d) %s updated (%s -> %s)")
|
||||
i total local-repo
|
||||
(doom--abbrev-commit ref)
|
||||
(doom--abbrev-commit target-ref)))
|
||||
(user-error
|
||||
(signal 'user-error (error-message-string e)))
|
||||
(error
|
||||
(print! (warn "(%d/%d) Encountered error with %s" i total package))
|
||||
(print-group!
|
||||
(print! (error "%s" e))
|
||||
(print-group! (print! (info "%s" (straight--process-get-output)))))
|
||||
(push package errors)))))
|
||||
(signal 'doom-package-error (list package e)))))))
|
||||
(print-group!
|
||||
(princ "\033[K")
|
||||
(when errors
|
||||
(print! (error "There were %d errors, the offending packages are: %s")
|
||||
(length errors) (string-join errors ", ")))
|
||||
(if (hash-table-empty-p straight--packages-to-rebuild)
|
||||
(ignore
|
||||
(print! (success "All %d packages are up-to-date")
|
||||
(hash-table-count straight--repo-cache)))
|
||||
(let ((count (hash-table-count straight--packages-to-rebuild))
|
||||
(packages (hash-table-keys straight--packages-to-rebuild)))
|
||||
(sort packages #'string-lessp)
|
||||
(doom--finalize-straight)
|
||||
(doom-cli-packages-build)
|
||||
(print! (success "Updated %d package(s)") count))
|
||||
(if (hash-table-empty-p packages-to-rebuild)
|
||||
(ignore (print! (success "All %d packages are up-to-date") total))
|
||||
(straight--transaction-finalize)
|
||||
(let ((default-directory (straight--build-dir)))
|
||||
(mapc (doom-rpartial #'delete-directory 'recursive)
|
||||
(hash-table-keys packages-to-rebuild)))
|
||||
(print! (success "Updated %d package(s)")
|
||||
(hash-table-count packages-to-rebuild))
|
||||
(doom-cli-packages-build)
|
||||
t))))
|
||||
|
||||
|
||||
@@ -209,30 +314,38 @@ declaration) or dependency thereof that hasn't already been."
|
||||
|
||||
(defun doom--cli-packages-purge-builds (builds)
|
||||
(if (not builds)
|
||||
(progn (print! (info "No builds to purge"))
|
||||
0)
|
||||
(length
|
||||
(delq nil (mapcar #'doom--cli-packages-purge-build builds)))))
|
||||
(prog1 0
|
||||
(print! (info "No builds to purge")))
|
||||
(print! (start "Purging straight builds..." (length builds)))
|
||||
(print-group!
|
||||
(length
|
||||
(delq nil (mapcar #'doom--cli-packages-purge-build builds))))))
|
||||
|
||||
(defun doom--cli-packages-regraft-repo (repo)
|
||||
(cl-defun doom--cli-packages-regraft-repo (repo)
|
||||
(let ((default-directory (straight--repos-dir repo)))
|
||||
(if (not (file-directory-p ".git"))
|
||||
(ignore (print! (warn "\033[Krepos/%s is not a git repo, skipping" repo)))
|
||||
(let ((before-size (doom-directory-size default-directory)))
|
||||
(straight--call "git" "reset" "--hard")
|
||||
(straight--call "git" "clean" "-ffd")
|
||||
(if (not (car (straight--call "git" "replace" "--graft" "HEAD")))
|
||||
(print! (info "\033[Krepos/%s is already compact\033[1A" repo))
|
||||
(straight--call "git" "gc")
|
||||
(print! (success "\033[KRegrafted repos/%s (from %0.1fKB to %0.1fKB)")
|
||||
repo before-size (doom-directory-size default-directory))
|
||||
(print-group! (print! "%s" (straight--process-get-output)))))
|
||||
(unless (file-directory-p ".git")
|
||||
(print! (warn "\033[Krepos/%s is not a git repo, skipping" repo))
|
||||
(cl-return))
|
||||
(unless (file-in-directory-p default-directory straight-base-dir)
|
||||
(print! (warn "\033[KSkipping repos/%s because it is local" repo))
|
||||
(cl-return))
|
||||
(let ((before-size (doom-directory-size default-directory)))
|
||||
(straight--call "git" "reset" "--hard")
|
||||
(straight--call "git" "clean" "-ffd")
|
||||
(if (not (car (straight--call "git" "replace" "--graft" "HEAD")))
|
||||
(print! (info "\033[Krepos/%s is already compact\033[1A" repo))
|
||||
(straight--call "git" "reflog" "expire" "--expire=all" "--all")
|
||||
(straight--call "git" "gc" "--prune=now")
|
||||
(print! (success "\033[KRegrafted repos/%s (from %0.1fKB to %0.1fKB)")
|
||||
repo before-size (doom-directory-size default-directory))
|
||||
(print-group! (print! "%s" (straight--process-get-output))))
|
||||
t)))
|
||||
|
||||
(defun doom--cli-packages-regraft-repos (repos)
|
||||
(if (not repos)
|
||||
(progn (print! (info "No repos to regraft"))
|
||||
0)
|
||||
(prog1 0
|
||||
(print! (info "No repos to regraft")))
|
||||
(print! (start "Regrafting %d repos..." (length repos)))
|
||||
(let ((before-size (doom-directory-size (straight--repos-dir))))
|
||||
(print-group!
|
||||
(prog1 (delq nil (mapcar #'doom--cli-packages-regraft-repo repos))
|
||||
@@ -245,8 +358,7 @@ declaration) or dependency thereof that hasn't already been."
|
||||
(defun doom--cli-packages-purge-repo (repo)
|
||||
(let ((repo-dir (straight--repos-dir repo)))
|
||||
(delete-directory repo-dir 'recursive)
|
||||
(ignore-errors
|
||||
(delete-file (straight--modified-file repo)))
|
||||
(delete-file (straight--modified-file repo))
|
||||
(if (file-directory-p repo-dir)
|
||||
(ignore (print! (error "Failed to purge repos/%s" repo)))
|
||||
(print! (success "Purged repos/%s" repo))
|
||||
@@ -254,24 +366,31 @@ declaration) or dependency thereof that hasn't already been."
|
||||
|
||||
(defun doom--cli-packages-purge-repos (repos)
|
||||
(if (not repos)
|
||||
(progn (print! (info "No repos to purge"))
|
||||
0)
|
||||
(length
|
||||
(delq nil (mapcar #'doom--cli-packages-purge-repo repos)))))
|
||||
(prog1 0
|
||||
(print! (info "No repos to purge")))
|
||||
(print! (start "Purging straight repositories..."))
|
||||
(print-group!
|
||||
(length
|
||||
(delq nil (mapcar #'doom--cli-packages-purge-repo repos))))))
|
||||
|
||||
(defun doom--cli-packages-purge-elpa ()
|
||||
(unless (bound-and-true-p package--initialized)
|
||||
(package-initialize))
|
||||
(let ((packages (cl-loop for (package desc) in package-alist
|
||||
for dir = (package-desc-dir desc)
|
||||
if (file-in-directory-p dir package-user-dir)
|
||||
collect (cons package dir))))
|
||||
(if (not package-alist)
|
||||
(progn (print! (info "No ELPA packages to purge"))
|
||||
0)
|
||||
(mapc (doom-rpartial #'delete-directory 'recursive)
|
||||
(mapcar #'cdr packages))
|
||||
(length packages))))
|
||||
(require 'core-packages)
|
||||
(let ((dirs (doom-files-in package-user-dir :type t :depth 0)))
|
||||
(if (not dirs)
|
||||
(prog1 0
|
||||
(print! (info "No ELPA packages to purge")))
|
||||
(print! (start "Purging ELPA packages..."))
|
||||
(dolist (path dirs (length dirs))
|
||||
(condition-case e
|
||||
(print-group!
|
||||
(if (file-directory-p path)
|
||||
(delete-directory path 'recursive)
|
||||
(delete-file path))
|
||||
(print! (success "Deleted %s") (filename path)))
|
||||
(error
|
||||
(print! (error "Failed to delete %s because: %s")
|
||||
(filename path)
|
||||
e)))))))
|
||||
|
||||
(defun doom-cli-packages-purge (&optional elpa-p builds-p repos-p regraft-repos-p)
|
||||
"Auto-removes orphaned packages and repos.
|
||||
@@ -282,36 +401,35 @@ a `package!' declaration) or isn't depended on by another primary package.
|
||||
If BUILDS-P, include straight package builds.
|
||||
If REPOS-P, include straight repos.
|
||||
If ELPA-P, include packages installed with package.el (M-x package-install)."
|
||||
(print! (start "Searching for orphaned packages to purge (for the emperor)..."))
|
||||
(doom-initialize-packages)
|
||||
(doom--barf-if-incomplete-packages)
|
||||
(print! (start "Purging orphaned packages (for the emperor)..."))
|
||||
(cl-destructuring-bind (&optional builds-to-purge repos-to-purge repos-to-regraft)
|
||||
(let ((rdirs (straight--directory-files (straight--repos-dir) nil nil 'sort))
|
||||
(bdirs (straight--directory-files (straight--build-dir) nil nil 'sort)))
|
||||
(list (cl-remove-if (doom-rpartial #'gethash straight--profile-cache)
|
||||
bdirs)
|
||||
(cl-remove-if (doom-rpartial #'straight--checkhash straight--repo-cache)
|
||||
rdirs)
|
||||
(cl-remove-if-not (doom-rpartial #'straight--checkhash straight--repo-cache)
|
||||
rdirs)))
|
||||
(let (success)
|
||||
(print-group!
|
||||
(if (not builds-p)
|
||||
(print! (info "Skipping builds"))
|
||||
(and (/= 0 (doom--cli-packages-purge-builds builds-to-purge))
|
||||
(setq success t)
|
||||
(straight-prune-build-cache)))
|
||||
(if (not elpa-p)
|
||||
(print! (info "Skipping elpa packages"))
|
||||
(and (/= 0 (doom--cli-packages-purge-elpa))
|
||||
(setq success t)))
|
||||
(if (not repos-p)
|
||||
(print! (info "Skipping repos"))
|
||||
(and (/= 0 (doom--cli-packages-purge-repos repos-to-purge))
|
||||
(setq success t)))
|
||||
(if (not regraft-repos-p)
|
||||
(print! (info "Skipping regrafting"))
|
||||
(print! (start "Regrafting %d repos..." (length repos-to-regraft)))
|
||||
(and (doom--cli-packages-regraft-repos repos-to-regraft)
|
||||
(setq success t)))
|
||||
(when success
|
||||
(doom--finalize-straight)
|
||||
t)))))
|
||||
(let ((rdirs
|
||||
(and (or repos-p regraft-repos-p)
|
||||
(straight--directory-files (straight--repos-dir) nil nil 'sort))))
|
||||
(list (when builds-p
|
||||
(seq-remove (doom-rpartial #'gethash straight--profile-cache)
|
||||
(straight--directory-files (straight--build-dir) nil nil 'sort)))
|
||||
(when repos-p
|
||||
(seq-remove (doom-rpartial #'straight--checkhash straight--repo-cache)
|
||||
rdirs))
|
||||
(when regraft-repos-p
|
||||
(seq-filter (doom-rpartial #'straight--checkhash straight--repo-cache)
|
||||
rdirs))))
|
||||
(print-group!
|
||||
(delq
|
||||
nil (list
|
||||
(if (not builds-p)
|
||||
(ignore (print! (info "Skipping builds")))
|
||||
(and (/= 0 (doom--cli-packages-purge-builds builds-to-purge))
|
||||
(straight-prune-build-cache)))
|
||||
(if (not elpa-p)
|
||||
(ignore (print! (info "Skipping elpa packages")))
|
||||
(/= 0 (doom--cli-packages-purge-elpa)))
|
||||
(if (not repos-p)
|
||||
(ignore (print! (info "Skipping repos")))
|
||||
(/= 0 (doom--cli-packages-purge-repos repos-to-purge)))
|
||||
(if (not regraft-repos-p)
|
||||
(ignore (print! (info "Skipping regrafting")))
|
||||
(doom--cli-packages-regraft-repos repos-to-regraft)))))))
|
||||
|
||||
@@ -50,9 +50,9 @@
|
||||
(require 'core-cli)
|
||||
(doom-initialize 'force 'noerror)
|
||||
(doom-initialize-modules)
|
||||
(doom-cli-reload-core-autoloads 'force)
|
||||
(doom-cli-reload-core-autoloads)
|
||||
(when (doom-cli-packages-install)
|
||||
(doom-cli-reload-package-autoloads 'force)))))
|
||||
(doom-cli-reload-package-autoloads)))))
|
||||
(unless (zerop status)
|
||||
(error "Failed to bootstrap unit tests"))))
|
||||
(with-temp-buffer
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
;;; core/cli/upgrade.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defcli! (upgrade up)
|
||||
((force-p ["-f" "--force"]))
|
||||
((force-p ["-f" "--force"] "Discard local changes to Doom and packages, and upgrade anyway")
|
||||
(packages-only-p ["-p" "--packages"] "Only upgrade packages, not Doom"))
|
||||
"Updates Doom and packages.
|
||||
|
||||
This requires that ~/.emacs.d is a git repo, and is the equivalent of the
|
||||
@@ -10,18 +11,22 @@ following shell commands:
|
||||
cd ~/.emacs.d
|
||||
git pull --rebase
|
||||
bin/doom clean
|
||||
bin/doom refresh
|
||||
bin/doom sync
|
||||
bin/doom update"
|
||||
:bare t
|
||||
(if (delq
|
||||
nil (list
|
||||
(doom-cli-upgrade doom-auto-accept force-p)
|
||||
(doom-cli-execute "refresh")
|
||||
(when (doom-cli-packages-update)
|
||||
(doom-cli-reload-package-autoloads 'force)
|
||||
t)))
|
||||
(print! (success "Done! Restart Emacs for changes to take effect."))
|
||||
(print! "Nothing to do. Doom is up-to-date!")))
|
||||
(let ((doom-auto-discard force-p))
|
||||
(cond
|
||||
(packages-only-p
|
||||
(doom-cli-execute "sync" '("-u"))
|
||||
(print! (success "Finished upgrading Doom Emacs")))
|
||||
|
||||
((doom-cli-upgrade doom-auto-accept doom-auto-discard)
|
||||
;; Reload Doom's CLI & libraries, in case there were any upstream changes.
|
||||
;; Major changes will still break, however
|
||||
(print! (info "Reloading Doom Emacs"))
|
||||
(doom-cli-execute-after "doom" "upgrade" "-p" (if force-p "-f")))
|
||||
|
||||
((print! "Nothing to do. Doom is up-to-date!")))))
|
||||
|
||||
|
||||
;;
|
||||
@@ -47,7 +52,13 @@ following shell commands:
|
||||
process-file-side-effects)
|
||||
(print! (start "Preparing to upgrade Doom Emacs and its packages..."))
|
||||
|
||||
(let* ((branch (vc-git--symbolic-ref doom-emacs-dir))
|
||||
(let* (;; git name-rev may return BRANCH~X for detached HEADs and fully
|
||||
;; qualified refs in some other cases, so an effort to strip out all
|
||||
;; but the branch name is necessary. git symbolic-ref (or
|
||||
;; `vc-git--symbolic-ref') won't work; it can't deal with submodules.
|
||||
(branch (replace-regexp-in-string
|
||||
"^\\(?:[^/]+/[^/]+/\\)?\\(.+\\)\\(?:~[0-9]+\\)?$" "\\1"
|
||||
(cdr (doom-call-process "git" "name-rev" "--name-only" "HEAD"))))
|
||||
(target-remote (format "%s/%s" doom-repo-remote branch)))
|
||||
(unless branch
|
||||
(error! (if (file-exists-p! ".git" doom-emacs-dir)
|
||||
@@ -103,11 +114,10 @@ following shell commands:
|
||||
(print! (start "Upgrading Doom Emacs..."))
|
||||
(print-group!
|
||||
(doom-clean-byte-compiled-files)
|
||||
(if (and (zerop (car (doom-call-process "git" "reset" "--hard" target-remote)))
|
||||
(equal (vc-git--rev-parse "HEAD") new-rev))
|
||||
(print! (info "%s") (cdr result))
|
||||
(unless (and (zerop (car (doom-call-process "git" "reset" "--hard" target-remote)))
|
||||
(equal (vc-git--rev-parse "HEAD") new-rev))
|
||||
(error "Failed to check out %s" (substring new-rev 0 10)))
|
||||
(print! (success "Finished upgrading Doom Emacs")))
|
||||
t)))))
|
||||
(print! (info "%s") (cdr result))
|
||||
t))))))
|
||||
(ignore-errors
|
||||
(doom-call-process "git" "remote" "remove" doom-repo-remote))))))
|
||||
|
||||
@@ -2,14 +2,21 @@
|
||||
|
||||
(require 'seq)
|
||||
|
||||
;; Eagerly load these libraries because we may be in a session that hasn't been
|
||||
;; fully initialized (e.g. where autoloads files haven't been generated or
|
||||
;; `load-path' populated).
|
||||
(load! "autoload/cli")
|
||||
(load! "autoload/debug")
|
||||
(load! "autoload/files")
|
||||
(load! "autoload/format")
|
||||
(load! "autoload/process")
|
||||
(load! "autoload/plist")
|
||||
(load! "autoload/files")
|
||||
(load! "autoload/output")
|
||||
|
||||
;; Create all our core directories to quell file errors
|
||||
(mapc (doom-rpartial #'make-directory 'parents)
|
||||
(list doom-local-dir
|
||||
doom-etc-dir
|
||||
doom-cache-dir))
|
||||
|
||||
;; Ensure straight and the bare minimum is ready to go
|
||||
(require 'core-modules)
|
||||
(require 'core-packages)
|
||||
(doom-initialize-core-packages)
|
||||
|
||||
|
||||
;;
|
||||
@@ -20,7 +27,16 @@
|
||||
commands like `doom-cli-packages-install', `doom-cli-packages-update' and
|
||||
`doom-packages-autoremove'.")
|
||||
|
||||
(defvar doom--cli-p nil)
|
||||
(defvar doom-auto-discard (getenv "FORCE")
|
||||
"If non-nil, discard all local changes while updating.")
|
||||
|
||||
(defvar doom-cli-file "cli"
|
||||
"The basename of CLI config files for modules.
|
||||
|
||||
These are loaded when a Doom's CLI starts up. There users and modules can define
|
||||
additional CLI commands, or reconfigure existing ones to better suit their
|
||||
purpose.")
|
||||
|
||||
(defvar doom--cli-commands (make-hash-table :test 'equal))
|
||||
(defvar doom--cli-groups (make-hash-table :test 'equal))
|
||||
(defvar doom--cli-group nil)
|
||||
@@ -63,9 +79,10 @@ commands like `doom-cli-packages-install', `doom-cli-packages-update' and
|
||||
(defun doom--cli-process (cli args)
|
||||
(let* ((args (copy-sequence args))
|
||||
(arglist (copy-sequence (doom-cli-arglist cli)))
|
||||
(expected (or (cl-position-if (doom-rpartial #'memq cl--lambda-list-keywords)
|
||||
arglist)
|
||||
(length arglist)))
|
||||
(expected
|
||||
(or (cl-position-if (doom-rpartial #'memq cl--lambda-list-keywords)
|
||||
arglist)
|
||||
(length arglist)))
|
||||
(got 0)
|
||||
restvar
|
||||
rest
|
||||
@@ -146,9 +163,27 @@ Executes a cli defined with `defcli!' with the name or alias specified by
|
||||
COMMAND, and passes ARGS to it."
|
||||
(if-let (cli (doom-cli-get command))
|
||||
(funcall (doom-cli-fn cli)
|
||||
(doom--cli-process cli args))
|
||||
(doom--cli-process cli (remq nil args)))
|
||||
(user-error "Couldn't find any %S command" command)))
|
||||
|
||||
(defun doom-cli-execute-after (&rest args)
|
||||
"Execute shell command ARGS after this CLI session quits.
|
||||
|
||||
This is particularly useful when the capabilities of Emacs' batch terminal are
|
||||
insufficient (like opening an instance of Emacs, or reloading Doom after a 'doom
|
||||
upgrade')."
|
||||
(let ((post-script (concat doom-local-dir ".doom.sh")))
|
||||
(with-temp-file post-script
|
||||
(insert "#!/usr/bin/env sh\n"
|
||||
"rm -f " (prin1-to-string post-script) "\n"
|
||||
"exec " (mapconcat #'shell-quote-argument (remq nil args) " ")
|
||||
"\n"))
|
||||
(let* ((current-mode (file-modes post-script))
|
||||
(add-mode (logand ?\111 (default-file-modes))))
|
||||
(or (/= (logand ?\111 current-mode) 0)
|
||||
(zerop add-mode)
|
||||
(set-file-modes post-script (logior current-mode add-mode))))))
|
||||
|
||||
(defmacro defcli! (name speclist &optional docstring &rest body)
|
||||
"Defines a CLI command.
|
||||
|
||||
@@ -195,10 +230,6 @@ BODY will be run when this dispatcher is called."
|
||||
for optsym = (if (listp opt) (car opt) opt)
|
||||
unless (memq optsym cl--lambda-list-keywords)
|
||||
collect (list optsym `(cdr (assq ',optsym --alist--))))
|
||||
,@(unless (plist-get plist :bare)
|
||||
'((unless doom-init-p
|
||||
(doom-initialize 'force 'noerror)
|
||||
(doom-initialize-modules))))
|
||||
,@body)))
|
||||
doom--cli-commands)
|
||||
(when aliases
|
||||
@@ -213,19 +244,142 @@ BODY will be run when this dispatcher is called."
|
||||
,@body))
|
||||
|
||||
|
||||
;;
|
||||
;;; straight.el hacks
|
||||
|
||||
;; Straight was designed primarily for interactive use, in an interactive Emacs
|
||||
;; session, but Doom does its package management in the terminal. Some things
|
||||
;; must be modified get straight to behave and improve its UX for our users.
|
||||
|
||||
(defvar doom--straight-discard-options
|
||||
'(("has diverged from"
|
||||
. "^Reset [^ ]+ to branch")
|
||||
("but recipe specifies a URL of"
|
||||
. "Delete remote \"[^\"]+\", re-create it with correct URL")
|
||||
("has a merge conflict:"
|
||||
. "^Abort merge$")
|
||||
("has a dirty worktree:"
|
||||
. "^Discard changes$")
|
||||
("^In repository "
|
||||
. "^Reset branch \\|^Delete remote [^,]+, re-create it with correct URL"))
|
||||
"A list of regexps, mapped to regexps.
|
||||
|
||||
Their CAR is tested against the prompt, and CDR is tested against the presented
|
||||
option, and is used by `straight-vc-git--popup-raw' to select which option to
|
||||
recommend.
|
||||
|
||||
It may not be obvious to users what they should do for some straight prompts,
|
||||
so Doom will recommend the one that reverts a package back to its (or target)
|
||||
original state.")
|
||||
|
||||
|
||||
;; HACK Remove dired & magit options from prompt, since they're inaccessible in
|
||||
;; noninteractive sessions.
|
||||
(advice-add #'straight-vc-git--popup-raw :override #'straight--popup-raw)
|
||||
|
||||
;; HACK Replace GUI popup prompts (which hang indefinitely in tty Emacs) with
|
||||
;; simple prompts.
|
||||
(defadvice! doom--straight-fallback-to-y-or-n-prompt-a (orig-fn &optional prompt)
|
||||
:around #'straight-are-you-sure
|
||||
(or doom-auto-accept
|
||||
(if doom-interactive-p
|
||||
(funcall orig-fn prompt)
|
||||
(y-or-n-p (format! "%s" (or prompt ""))))))
|
||||
|
||||
(defun doom--straight-recommended-option-p (prompt option)
|
||||
(cl-loop for (prompt-re . opt-re) in doom--straight-discard-options
|
||||
if (string-match-p prompt-re prompt)
|
||||
return (string-match-p opt-re option)))
|
||||
|
||||
(defadvice! doom--straight-fallback-to-tty-prompt-a (orig-fn prompt actions)
|
||||
"Modifies straight to prompt on the terminal when in noninteractive sessions."
|
||||
:around #'straight--popup-raw
|
||||
(if doom-interactive-p
|
||||
(funcall orig-fn prompt actions)
|
||||
(let ((doom--straight-discard-options doom--straight-discard-options))
|
||||
;; We can't intercept C-g, so no point displaying any options for this key
|
||||
;; when C-c is the proper way to abort batch Emacs.
|
||||
(delq! "C-g" actions 'assoc)
|
||||
;; HACK These are associated with opening dired or magit, which isn't
|
||||
;; possible in tty Emacs, so...
|
||||
(delq! "e" actions 'assoc)
|
||||
(delq! "g" actions 'assoc)
|
||||
(if doom-auto-discard
|
||||
(cl-loop with doom-auto-accept = t
|
||||
for (_key desc func) in actions
|
||||
when desc
|
||||
when (doom--straight-recommended-option-p prompt desc)
|
||||
return (funcall func))
|
||||
(print! (start "%s") (red prompt))
|
||||
(print-group!
|
||||
(terpri)
|
||||
(let (options)
|
||||
(print-group!
|
||||
(print! " 1) Abort")
|
||||
(cl-loop for (_key desc func) in actions
|
||||
when desc
|
||||
do (push func options)
|
||||
and do
|
||||
(print! "%2s) %s" (1+ (length options))
|
||||
(if (doom--straight-recommended-option-p prompt desc)
|
||||
(progn
|
||||
(setq doom--straight-discard-options nil)
|
||||
(green (concat desc " (Recommended)")))
|
||||
desc))))
|
||||
(terpri)
|
||||
(let* ((options
|
||||
(cons (lambda ()
|
||||
(let ((doom-output-indent 0))
|
||||
(terpri)
|
||||
(print! (warn "Aborted")))
|
||||
(kill-emacs 1))
|
||||
(nreverse options)))
|
||||
(prompt
|
||||
(format! "How to proceed? (%s) "
|
||||
(mapconcat #'number-to-string
|
||||
(number-sequence 1 (length options))
|
||||
", ")))
|
||||
answer fn)
|
||||
(while (null (nth (setq answer (1- (read-number prompt)))
|
||||
options))
|
||||
(print! (warn "%s is not a valid answer, try again.")
|
||||
answer))
|
||||
(funcall (nth answer options)))))))))
|
||||
|
||||
(defadvice! doom--straight-respect-print-indent-a (args)
|
||||
"Indent straight progress messages to respect `doom-output-indent', so we
|
||||
don't have to pass whitespace to `straight-use-package's fourth argument
|
||||
everywhere we use it (and internally)."
|
||||
:filter-args #'straight-use-package
|
||||
(cl-destructuring-bind
|
||||
(melpa-style-recipe &optional no-clone no-build cause interactive)
|
||||
args
|
||||
(list melpa-style-recipe no-clone no-build
|
||||
(if (and (not cause)
|
||||
(boundp 'doom-output-indent)
|
||||
(> doom-output-indent 0))
|
||||
(make-string (1- (or doom-output-indent 1)) 32)
|
||||
cause)
|
||||
interactive)))
|
||||
|
||||
|
||||
;;
|
||||
;;; CLI Commands
|
||||
|
||||
(load! "cli/help")
|
||||
(load! "cli/install")
|
||||
|
||||
(defcligroup! "Maintenance"
|
||||
"For managing your config and packages"
|
||||
(defcli! (refresh re sync)
|
||||
((if-necessary-p ["-n" "--if-necessary"] "Only regenerate autoloads files if necessary")
|
||||
(inhibit-envvar-p ["-e"] "Don't regenerate the envvar file")
|
||||
(prune-p ["-p" "--prune"] "Purge orphaned packages & regraft repos"))
|
||||
"Ensure Doom is properly set up.
|
||||
(defcli! (refresh re) ()
|
||||
"Deprecated for 'doom sync'"
|
||||
:hidden t
|
||||
(user-error "'doom refresh' has been replaced with 'doom sync'. Use that instead"))
|
||||
|
||||
(defcli! (sync s)
|
||||
((inhibit-envvar-p ["-e"] "Don't regenerate the envvar file")
|
||||
(inhibit-elc-p ["-c"] "Don't recompile config")
|
||||
(update-p ["-u"] "Update installed packages after syncing")
|
||||
(prune-p ["-p" "--prune"] "Purge orphaned package repos & regraft them"))
|
||||
"Synchronize your config with Doom Emacs.
|
||||
|
||||
This is the equivalent of running autoremove, install, autoloads, then
|
||||
recompile. Run this whenever you:
|
||||
@@ -238,53 +392,47 @@ recompile. Run this whenever you:
|
||||
It will ensure that unneeded packages are removed, all needed packages are
|
||||
installed, autoloads files are up-to-date and no byte-compiled files have gone
|
||||
stale."
|
||||
:bare t
|
||||
(print! (start "Initiating a refresh of Doom Emacs..."))
|
||||
(print-group!
|
||||
(let (success)
|
||||
(when (and (not inhibit-envvar-p)
|
||||
(file-exists-p doom-env-file))
|
||||
(doom-cli-reload-env-file 'force))
|
||||
(print! (start "Synchronizing your config with Doom Emacs..."))
|
||||
(print-group!
|
||||
(delete-file doom-autoload-file)
|
||||
(when (and (not inhibit-envvar-p)
|
||||
(file-exists-p doom-env-file))
|
||||
(doom-cli-reload-env-file 'force))
|
||||
(run-hooks 'doom-sync-pre-hook)
|
||||
(doom-cli-packages-install)
|
||||
(doom-cli-packages-build)
|
||||
(when update-p
|
||||
(doom-cli-packages-update))
|
||||
(doom-cli-packages-purge prune-p 'builds-p prune-p prune-p)
|
||||
(run-hooks 'doom-sync-post-hook)
|
||||
(when (doom-autoloads-reload)
|
||||
(print! (info "Restart Emacs or use 'M-x doom/reload' for changes to take effect")))
|
||||
t))
|
||||
|
||||
;; Ensures that no pre-existing state pollutes the generation of the new
|
||||
;; autoloads files.
|
||||
(mapc #'doom--cli-delete-autoloads-file
|
||||
(list doom-autoload-file
|
||||
doom-package-autoload-file))
|
||||
(doom-initialize 'force 'noerror)
|
||||
(doom-initialize-modules)
|
||||
|
||||
(doom-cli-reload-core-autoloads (not if-necessary-p))
|
||||
(unwind-protect
|
||||
(progn
|
||||
(and (doom-cli-packages-install)
|
||||
(setq success t))
|
||||
(and (doom-cli-packages-build)
|
||||
(setq success t))
|
||||
(and (doom-cli-packages-purge prune-p 'builds-p prune-p prune-p)
|
||||
(setq success t)))
|
||||
(doom-cli-reload-package-autoloads (or success (not if-necessary-p)))
|
||||
(doom-cli-byte-compile nil 'recompile))
|
||||
t)))
|
||||
|
||||
(load! "cli/env")
|
||||
(load! "cli/upgrade")
|
||||
(load! "cli/packages")
|
||||
(load! "cli/autoloads"))
|
||||
(load! "cli/env")
|
||||
(load! "cli/upgrade")
|
||||
(load! "cli/packages")
|
||||
(load! "cli/autoloads")
|
||||
|
||||
(defcligroup! "Diagnostics"
|
||||
"For troubleshooting and diagnostics"
|
||||
(load! "cli/doctor")
|
||||
(load! "cli/debug")
|
||||
(load! "cli/test"))
|
||||
|
||||
;; Our tests are broken at the moment. Working on fixing them, but for now we
|
||||
;; disable them:
|
||||
;; (load! "cli/test")
|
||||
)
|
||||
|
||||
|
||||
(defcligroup! "Compilation"
|
||||
"For compiling Doom and your config"
|
||||
(load! "cli/byte-compile"))
|
||||
|
||||
|
||||
(defcligroup! "Utilities"
|
||||
"Conveniences for interacting with Doom externally"
|
||||
(defcli! run ()
|
||||
(defcli! run (&rest args)
|
||||
"Run Doom Emacs from bin/doom's parent directory.
|
||||
|
||||
All arguments are passed on to Emacs.
|
||||
@@ -294,11 +442,9 @@ All arguments are passed on to Emacs.
|
||||
|
||||
WARNING: this command exists for convenience and testing. Doom will suffer
|
||||
additional overhead by being started this way. For the best performance, it is
|
||||
best to run Doom out of ~/.emacs.d and ~/.doom.d.")
|
||||
|
||||
;; (load! "cli/batch")
|
||||
;; (load! "cli/org")
|
||||
)
|
||||
best to run Doom out of ~/.emacs.d and ~/.doom.d."
|
||||
(apply #'doom-cli-execute-after invocation-name args)
|
||||
nil))
|
||||
|
||||
(provide 'core-cli)
|
||||
;;; core-cli.el ends here
|
||||
|
||||
@@ -12,8 +12,8 @@ successfully sets indent_style/indent_size.")
|
||||
(defvar-local doom-large-file-p nil)
|
||||
(put 'doom-large-file-p 'permanent-local t)
|
||||
|
||||
(defvar doom-large-file-size-alist '((t . 1.0))
|
||||
"An alist mapping major mode to filesize thresholds.
|
||||
(defvar doom-large-file-size-alist '(("." . 1.0))
|
||||
"An alist mapping regexps (like `auto-mode-alist') to filesize thresholds.
|
||||
|
||||
If a file is opened and discovered to be larger than the threshold, Doom
|
||||
performs emergency optimizations to prevent Emacs from hanging, crashing or
|
||||
@@ -42,15 +42,17 @@ possible."
|
||||
(if (setq doom-large-file-p
|
||||
(and buffer-file-name
|
||||
(not doom-large-file-p)
|
||||
(file-readable-p buffer-file-name)
|
||||
(> (nth 7 (file-attributes buffer-file-name))
|
||||
(* 1024 1024
|
||||
(cdr (or (assq major-mode doom-large-file-size-alist)
|
||||
(assq 't doom-large-file-size-alist)))))))
|
||||
(file-exists-p buffer-file-name)
|
||||
(ignore-errors
|
||||
(> (nth 7 (file-attributes buffer-file-name))
|
||||
(* 1024 1024
|
||||
(assoc-default buffer-file-name doom-large-file-size-alist
|
||||
#'string-match-p))))))
|
||||
(prog1 (apply orig-fn args)
|
||||
(if (memq major-mode doom-large-file-excluded-modes)
|
||||
(setq doom-large-file-p nil)
|
||||
(so-long-minor-mode +1)
|
||||
(when (fboundp 'so-long-minor-mode) ; in case the user disabled it
|
||||
(so-long-minor-mode +1))
|
||||
(message "Large file detected! Cutting a few corners to improve performance...")))
|
||||
(apply orig-fn args)))
|
||||
|
||||
@@ -77,68 +79,94 @@ possible."
|
||||
t))))))
|
||||
|
||||
;; Don't autosave files or create lock/history/backup files. We don't want
|
||||
;; copies of potentially sensitive material floating around, and we'll rely on
|
||||
;; git and our own good fortune instead. Fingers crossed!
|
||||
;; copies of potentially sensitive material floating around or polluting our
|
||||
;; filesystem. We rely on git and our own good fortune instead. Fingers crossed!
|
||||
(setq auto-save-default nil
|
||||
create-lockfiles nil
|
||||
make-backup-files nil
|
||||
;; But have a place to store them in case we do use them...
|
||||
auto-save-list-file-name (concat doom-cache-dir "autosave")
|
||||
backup-directory-alist `(("." . ,(concat doom-cache-dir "backup/"))))
|
||||
;; auto-save-list-file-name (concat doom-cache-dir "autosave")
|
||||
auto-save-list-file-prefix (concat doom-cache-dir "autosave/")
|
||||
auto-save-file-name-transforms `((".*" ,auto-save-list-file-prefix t))
|
||||
backup-directory-alist `((".*" . ,(concat doom-cache-dir "backup/"))))
|
||||
|
||||
(after! tramp
|
||||
(add-to-list 'backup-directory-alist (cons tramp-file-name-regexp nil)))
|
||||
|
||||
(add-hook! 'after-save-hook
|
||||
(defun doom-guess-mode-h ()
|
||||
"Guess mode when saving a file in `fundamental-mode'."
|
||||
(and (eq major-mode 'fundamental-mode)
|
||||
(buffer-file-name (buffer-base-buffer))
|
||||
(eq (current-buffer) (window-buffer (selected-window))) ; only visible buffers
|
||||
(set-auto-mode))))
|
||||
(when (eq major-mode 'fundamental-mode)
|
||||
(let ((buffer (or (buffer-base-buffer) (current-buffer))))
|
||||
(and (buffer-file-name buffer)
|
||||
(eq buffer (window-buffer (selected-window))) ; only visible buffers
|
||||
(set-auto-mode))))))
|
||||
|
||||
|
||||
;;
|
||||
;;; Formatting
|
||||
|
||||
;; Indentation
|
||||
(setq-default tab-width 4
|
||||
tab-always-indent t
|
||||
indent-tabs-mode nil
|
||||
fill-column 80)
|
||||
;; Favor spaces over tabs. Pls dun h8, but I think spaces (and 4 of them) is a
|
||||
;; more consistent default than 8-space tabs. It can be changed on a per-mode
|
||||
;; basis anyway (and is, where tabs are the canonical style, like go-mode).
|
||||
(setq-default indent-tabs-mode nil
|
||||
tab-width 4)
|
||||
|
||||
;; Word wrapping
|
||||
(setq-default word-wrap t
|
||||
truncate-lines t
|
||||
truncate-partial-width-windows nil)
|
||||
;; Make `tabify' and `untabify' only affect indentation. Not tabs/spaces in the
|
||||
;; middle of a line.
|
||||
(setq tabify-regexp "^\t* [ \t]+")
|
||||
|
||||
(setq sentence-end-double-space nil
|
||||
delete-trailing-lines nil
|
||||
require-final-newline t
|
||||
tabify-regexp "^\t* [ \t]+") ; for :retab
|
||||
;; An archaic default in the age of widescreen 4k displays? I disagree. We still
|
||||
;; frequently split our terminals and editor frames, or have them side-by-side,
|
||||
;; using up more of that newly available horizontal real-estate.
|
||||
(setq-default fill-column 80)
|
||||
|
||||
;; Favor hard-wrapping in text modes
|
||||
(add-hook 'text-mode-hook #'auto-fill-mode)
|
||||
;; Continue wrapped words at whitespace, rather than in the middle of a word.
|
||||
(setq-default word-wrap t)
|
||||
;; ...but don't do any wrapping by default. It's expensive. Enable
|
||||
;; `visual-line-mode' if you want soft line-wrapping. `auto-fill-mode' for hard
|
||||
;; line-wrapping.
|
||||
(setq-default truncate-lines t)
|
||||
;; If enabled (and `truncate-lines' was disabled), soft wrapping no longer
|
||||
;; occurs when that window is less than `truncate-partial-width-windows'
|
||||
;; characters wide. We don't need this, and it's extra work for Emacs otherwise,
|
||||
;; so off it goes.
|
||||
(setq truncate-partial-width-windows nil)
|
||||
|
||||
;; This was a widespread practice in the days of typewriters. I actually prefer
|
||||
;; it when writing prose with monospace fonts, but it is obsolete otherwise.
|
||||
(setq sentence-end-double-space nil)
|
||||
|
||||
;; The POSIX standard defines a line is "a sequence of zero or more non-newline
|
||||
;; characters followed by a terminating newline", so files should end in a
|
||||
;; newline. Windows doesn't respect this (because it's Windows), but we should,
|
||||
;; since programmers' tools tend to be POSIX compliant.
|
||||
(setq require-final-newline t)
|
||||
|
||||
;; Default to soft line-wrapping in text modes. It is more sensibile for text
|
||||
;; modes, even if hard wrapping is more performant.
|
||||
(add-hook 'text-mode-hook #'visual-line-mode)
|
||||
|
||||
|
||||
;;
|
||||
;;; Clipboard / kill-ring
|
||||
|
||||
;; Eliminate duplicates in the kill ring. That is, if you kill the same thing
|
||||
;; twice, you won't have to use M-y twice to get past it to older entries in the
|
||||
;; kill ring.
|
||||
;; Cull duplicates in the kill ring to reduce bloat and make the kill ring
|
||||
;; easier to peruse (with `counsel-yank-pop' or `helm-show-kill-ring'.
|
||||
(setq kill-do-not-save-duplicates t)
|
||||
|
||||
;;
|
||||
;; Allow UTF or composed text from the clipboard, even in the terminal or on
|
||||
;; non-X systems (like Windows or macOS), where only `STRING' is used.
|
||||
(setq x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING))
|
||||
|
||||
;; Save clipboard contents into kill-ring before replacing them
|
||||
(setq save-interprogram-paste-before-kill t)
|
||||
|
||||
;; Fixes the clipboard in tty Emacs by piping clipboard I/O through xclip, xsel,
|
||||
;; pb{copy,paste}, wl-copy, termux-clipboard-get, or getclip (cygwin).
|
||||
(add-hook! 'tty-setup-hook
|
||||
(defun doom-init-clipboard-in-tty-emacs-h ()
|
||||
(and (not (getenv "SSH_CONNECTION"))
|
||||
(require 'xclip nil t)
|
||||
(xclip-mode +1))))
|
||||
;; pb{copy,paste}, wl-copy, termux-clipboard-get, or getclip (cygwin); depending
|
||||
;; on what is available.
|
||||
(unless IS-WINDOWS
|
||||
(add-hook! 'tty-setup-hook
|
||||
(defun doom-init-clipboard-in-tty-emacs-h ()
|
||||
(and (require 'clipetty nil t)
|
||||
(global-clipetty-mode +1)))))
|
||||
|
||||
|
||||
;;
|
||||
@@ -146,6 +174,8 @@ possible."
|
||||
|
||||
(push '("/LICENSE\\'" . text-mode) auto-mode-alist)
|
||||
(push '("\\.log\\'" . text-mode) auto-mode-alist)
|
||||
(push '("rc\\'" . conf-mode) auto-mode-alist)
|
||||
(push '("\\.\\(?:hex\\|nes\\)\\'" . hexl-mode) auto-mode-alist)
|
||||
|
||||
|
||||
;;
|
||||
@@ -164,13 +194,13 @@ possible."
|
||||
;; Only prompts for confirmation when buffer is unsaved.
|
||||
revert-without-query (list "."))
|
||||
|
||||
;; Instead of using `auto-revert-mode' or `global-auto-revert-mode', we employ
|
||||
;; lazy auto reverting on `focus-in-hook' and `doom-switch-buffer-hook'.
|
||||
;; Instead of `auto-revert-mode' or `global-auto-revert-mode', we lazily auto
|
||||
;; revert; when we save a file or switch buffers/windows (or focus on Emacs).
|
||||
;;
|
||||
;; This is because autorevert abuses the heck out of inotify handles which can
|
||||
;; grind Emacs to a halt if you do expensive IO (outside of Emacs) on the
|
||||
;; files you have open (like compression). We only really need to revert
|
||||
;; changes when we switch to a buffer or when we focus the Emacs frame.
|
||||
;; Autorevert normally abuses the heck out of inotify handles which can grind
|
||||
;; Emacs to a halt if you do expensive IO (outside of Emacs) on the files you
|
||||
;; have open (like compression). The only alternative is aggressive polling,
|
||||
;; which is unreliable and expensive with a lot of buffers open.
|
||||
(defun doom-auto-revert-buffer-h ()
|
||||
"Auto revert current buffer, if necessary."
|
||||
(unless (or auto-revert-mode (active-minibuffer-window))
|
||||
@@ -186,7 +216,7 @@ possible."
|
||||
(use-package! recentf
|
||||
;; Keep track of recently opened files
|
||||
:defer-incrementally easymenu tree-widget timer
|
||||
:after-call after-find-file
|
||||
:hook (doom-first-file . recentf-mode)
|
||||
:commands recentf-open-files
|
||||
:config
|
||||
(defun doom--recent-file-truename (file)
|
||||
@@ -194,9 +224,11 @@ possible."
|
||||
(not (file-remote-p file)))
|
||||
(file-truename file)
|
||||
file))
|
||||
(setq recentf-filename-handlers '(doom--recent-file-truename abbreviate-file-name))
|
||||
|
||||
(setq recentf-save-file (concat doom-cache-dir "recentf")
|
||||
(setq recentf-filename-handlers
|
||||
'(substring-no-properties ; strip out lingering text properties
|
||||
doom--recent-file-truename ; resolve symlinks of local files
|
||||
abbreviate-file-name) ; replace $HOME with ~
|
||||
recentf-save-file (concat doom-cache-dir "recentf")
|
||||
recentf-auto-cleanup 'never
|
||||
recentf-max-menu-items 0
|
||||
recentf-max-saved-items 200)
|
||||
@@ -214,22 +246,20 @@ possible."
|
||||
"Add dired directory to recentf file list."
|
||||
(recentf-add-file default-directory)))
|
||||
|
||||
(when doom-interactive-mode
|
||||
(add-hook 'kill-emacs-hook #'recentf-cleanup)
|
||||
(quiet! (recentf-mode +1))))
|
||||
(add-hook 'kill-emacs-hook #'recentf-cleanup)
|
||||
(advice-add #'recentf-load-list :around #'doom-shut-up-a))
|
||||
|
||||
|
||||
(use-package! savehist
|
||||
;; persist variables across sessions
|
||||
:defer-incrementally custom
|
||||
:after-call post-command-hook
|
||||
:hook (doom-first-input . savehist-mode)
|
||||
:init
|
||||
(setq savehist-file (concat doom-cache-dir "savehist"))
|
||||
:config
|
||||
(setq savehist-file (concat doom-cache-dir "savehist")
|
||||
savehist-save-minibuffer-history t
|
||||
(setq savehist-save-minibuffer-history t
|
||||
savehist-autosave-interval nil ; save on kill only
|
||||
savehist-additional-variables '(kill-ring search-ring regexp-search-ring))
|
||||
(savehist-mode +1)
|
||||
|
||||
(add-hook! 'kill-emacs-hook
|
||||
(defun doom-unpropertize-kill-ring-h ()
|
||||
"Remove text properties from `kill-ring' for a smaller savehist file."
|
||||
@@ -241,31 +271,33 @@ possible."
|
||||
|
||||
(use-package! saveplace
|
||||
;; persistent point location in buffers
|
||||
:after-call after-find-file dired-initial-position-hook
|
||||
:config
|
||||
:hook (doom-first-file . save-place-mode)
|
||||
:init
|
||||
(setq save-place-file (concat doom-cache-dir "saveplace")
|
||||
save-place-limit 100)
|
||||
|
||||
:config
|
||||
(defadvice! doom--recenter-on-load-saveplace-a (&rest _)
|
||||
"Recenter on cursor when loading a saved place."
|
||||
:after-while #'save-place-find-file-hook
|
||||
(if buffer-file-name (ignore-errors (recenter))))
|
||||
|
||||
(defadvice! doom--inhibit-saveplace-in-long-files-a (orig-fn &rest args)
|
||||
:around #'save-place-to-alist
|
||||
(unless doom-large-file-p
|
||||
(apply orig-fn args)))
|
||||
|
||||
(defadvice! doom--dont-prettify-saveplace-cache-a (orig-fn)
|
||||
"`save-place-alist-to-file' uses `pp' to prettify the contents of its cache.
|
||||
`pp' can be expensive for longer lists, and there's no reason to prettify cache
|
||||
files, so we replace calls to `pp' with the much faster `prin1'."
|
||||
:around #'save-place-alist-to-file
|
||||
(cl-letf (((symbol-function #'pp)
|
||||
(symbol-function #'prin1)))
|
||||
(funcall orig-fn)))
|
||||
|
||||
(save-place-mode +1))
|
||||
(letf! ((#'pp #'prin1)) (funcall orig-fn))))
|
||||
|
||||
|
||||
(use-package! server
|
||||
:when (display-graphic-p)
|
||||
:after-call pre-command-hook after-find-file focus-out-hook
|
||||
:defer 1
|
||||
:init
|
||||
(when-let (name (getenv "EMACS_SERVER_NAME"))
|
||||
(setq server-name name))
|
||||
@@ -278,7 +310,8 @@ files, so we replace calls to `pp' with the much faster `prin1'."
|
||||
;;; Packages
|
||||
|
||||
(use-package! better-jumper
|
||||
:after-call pre-command-hook
|
||||
:hook (doom-first-input . better-jumper-mode)
|
||||
:hook (better-jumper-post-jump . recenter)
|
||||
:preface
|
||||
;; REVIEW Suppress byte-compiler warning spawning a *Compile-Log* buffer at
|
||||
;; startup. This can be removed once gilbertw1/better-jumper#2 is merged.
|
||||
@@ -288,17 +321,14 @@ files, so we replace calls to `pp' with the much faster `prin1'."
|
||||
(global-set-key [remap evil-jump-backward] #'better-jumper-jump-backward)
|
||||
(global-set-key [remap xref-pop-marker-stack] #'better-jumper-jump-backward)
|
||||
:config
|
||||
(better-jumper-mode +1)
|
||||
(add-hook 'better-jumper-post-jump-hook #'recenter)
|
||||
|
||||
(defadvice! doom-set-jump-a (orig-fn &rest args)
|
||||
(defun doom-set-jump-a (orig-fn &rest args)
|
||||
"Set a jump point and ensure ORIG-FN doesn't set any new jump points."
|
||||
(better-jumper-set-jump (if (markerp (car args)) (car args)))
|
||||
(let ((evil--jumps-jumping t)
|
||||
(better-jumper--jumping t))
|
||||
(apply orig-fn args)))
|
||||
|
||||
(defadvice! doom-set-jump-maybe-a (orig-fn &rest args)
|
||||
(defun doom-set-jump-maybe-a (orig-fn &rest args)
|
||||
"Set a jump point if ORIG-FN returns non-nil."
|
||||
(let ((origin (point-marker))
|
||||
(result
|
||||
@@ -329,20 +359,19 @@ files, so we replace calls to `pp' with the much faster `prin1'."
|
||||
|
||||
(use-package! dtrt-indent
|
||||
;; Automatic detection of indent settings
|
||||
:when doom-interactive-mode
|
||||
:defer t
|
||||
:init
|
||||
(add-hook! '(change-major-mode-after-body-hook read-only-mode-hook)
|
||||
(defun doom-detect-indentation-h ()
|
||||
(unless (or (not after-init-time)
|
||||
doom-inhibit-indent-detection
|
||||
doom-large-file-p
|
||||
(memq major-mode doom-detect-indentation-excluded-modes)
|
||||
(member (substring (buffer-name) 0 1) '(" " "*")))
|
||||
;; Don't display messages in the echo area, but still log them
|
||||
(let ((inhibit-message (not doom-debug-mode)))
|
||||
(dtrt-indent-mode +1)))))
|
||||
:when doom-interactive-p
|
||||
:hook ((change-major-mode-after-body read-only-mode) . doom-detect-indentation-h)
|
||||
:config
|
||||
(defun doom-detect-indentation-h ()
|
||||
(unless (or (not after-init-time)
|
||||
doom-inhibit-indent-detection
|
||||
doom-large-file-p
|
||||
(memq major-mode doom-detect-indentation-excluded-modes)
|
||||
(member (substring (buffer-name) 0 1) '(" " "*")))
|
||||
;; Don't display messages in the echo area, but still log them
|
||||
(let ((inhibit-message (not doom-debug-p)))
|
||||
(dtrt-indent-mode +1))))
|
||||
|
||||
;; Enable dtrt-indent even in smie modes so that it can update `tab-width',
|
||||
;; `standard-indent' and `evil-shift-width' there as well.
|
||||
(setq dtrt-indent-run-after-smie t)
|
||||
@@ -358,18 +387,14 @@ files, so we replace calls to `pp' with the much faster `prin1'."
|
||||
`nim-mode'. This prevents them from leaving Emacs in a broken state."
|
||||
:around #'dtrt-indent-mode
|
||||
(let ((dtrt-indent-run-after-smie dtrt-indent-run-after-smie))
|
||||
(cl-letf* ((old-smie-config-guess (symbol-function 'smie-config-guess))
|
||||
(old-smie-config--guess (symbol-function 'symbol-config--guess))
|
||||
((symbol-function 'symbol-config--guess)
|
||||
(lambda (beg end)
|
||||
(funcall old-smie-config--guess beg (min end 10000))))
|
||||
((symbol-function 'smie-config-guess)
|
||||
(lambda ()
|
||||
(condition-case e (funcall old-smie-config-guess)
|
||||
(error (setq dtrt-indent-run-after-smie t)
|
||||
(message "[WARNING] Indent detection: %s"
|
||||
(error-message-string e))
|
||||
(message "")))))) ; warn silently
|
||||
(letf! ((defun symbol-config--guess (beg end)
|
||||
(funcall symbol-config--guess beg (min end 10000)))
|
||||
(defun smie-config-guess ()
|
||||
(condition-case e (funcall smie-config-guess)
|
||||
(error (setq dtrt-indent-run-after-smie t)
|
||||
(message "[WARNING] Indent detection: %s"
|
||||
(error-message-string e))
|
||||
(message ""))))) ; warn silently
|
||||
(funcall orig-fn arg)))))
|
||||
|
||||
|
||||
@@ -377,17 +402,16 @@ files, so we replace calls to `pp' with the much faster `prin1'."
|
||||
;; a better *help* buffer
|
||||
:commands helpful--read-symbol
|
||||
:init
|
||||
(define-key!
|
||||
[remap describe-function] #'helpful-callable
|
||||
[remap describe-command] #'helpful-command
|
||||
[remap describe-variable] #'helpful-variable
|
||||
[remap describe-key] #'helpful-key
|
||||
[remap describe-symbol] #'doom/describe-symbol)
|
||||
(global-set-key [remap describe-function] #'helpful-callable)
|
||||
(global-set-key [remap describe-command] #'helpful-command)
|
||||
(global-set-key [remap describe-variable] #'helpful-variable)
|
||||
(global-set-key [remap describe-key] #'helpful-key)
|
||||
(global-set-key [remap describe-symbol] #'helpful-symbol)
|
||||
|
||||
(defun doom-use-helpful-a (orig-fn &rest args)
|
||||
"Force ORIG-FN to use helpful instead of the old describe-* commands."
|
||||
(cl-letf (((symbol-function #'describe-function) #'helpful-function)
|
||||
((symbol-function #'describe-variable) #'helpful-variable))
|
||||
(letf! ((#'describe-function #'helpful-function)
|
||||
(#'describe-variable #'helpful-variable))
|
||||
(apply orig-fn args)))
|
||||
|
||||
(after! apropos
|
||||
@@ -411,30 +435,33 @@ files, so we replace calls to `pp' with the much faster `prin1'."
|
||||
(use-package! smartparens
|
||||
;; Auto-close delimiters and blocks as you type. It's more powerful than that,
|
||||
;; but that is all Doom uses it for.
|
||||
:after-call doom-switch-buffer-hook after-find-file
|
||||
:hook (doom-first-buffer . smartparens-global-mode)
|
||||
:commands sp-pair sp-local-pair sp-with-modes sp-point-in-comment sp-point-in-string
|
||||
:config
|
||||
;; smartparens recognizes `slime-mrepl-mode', but not `sly-mrepl-mode', so...
|
||||
(add-to-list 'sp-lisp-modes 'sly-mrepl-mode)
|
||||
;; Load default smartparens rules for various languages
|
||||
(require 'smartparens-config)
|
||||
|
||||
;; Overlays are too distracting and not terribly helpful. show-parens does
|
||||
;; this for us already, so...
|
||||
;; this for us already (and is faster), so...
|
||||
(setq sp-highlight-pair-overlay nil
|
||||
sp-highlight-wrap-overlay nil
|
||||
sp-highlight-wrap-tag-overlay nil)
|
||||
;; But if someone does want overlays enabled, evil users will be stricken with
|
||||
;; an off-by-one issue where smartparens assumes you're outside the pair when
|
||||
;; you're really at the last character in insert mode. We must correct this
|
||||
;; vile injustice.
|
||||
(setq sp-show-pair-from-inside t)
|
||||
;; ...and stay highlighted until we've truly escaped the pair!
|
||||
(setq sp-cancel-autoskip-on-backward-movement nil)
|
||||
(with-eval-after-load 'evil
|
||||
;; But if someone does want overlays enabled, evil users will be stricken
|
||||
;; with an off-by-one issue where smartparens assumes you're outside the
|
||||
;; pair when you're really at the last character in insert mode. We must
|
||||
;; correct this vile injustice.
|
||||
(setq sp-show-pair-from-inside t)
|
||||
;; ...and stay highlighted until we've truly escaped the pair!
|
||||
(setq sp-cancel-autoskip-on-backward-movement nil))
|
||||
|
||||
;; The default is 100, because smartparen's scans are relatively expensive
|
||||
;; (especially with large pair lists for somoe modes), we halve it, as a
|
||||
;; (especially with large pair lists for some modes), we reduce it, as a
|
||||
;; better compromise between performance and accuracy.
|
||||
(setq sp-max-prefix-length 50)
|
||||
;; This speeds up smartparens. No pair has any business being longer than 4
|
||||
;; characters; if they must, the modes that need it set it buffer-locally.
|
||||
(setq sp-max-prefix-length 25)
|
||||
;; No pair has any business being longer than 4 characters; if they must, set
|
||||
;; it buffer-locally. It's less work for smartparens.
|
||||
(setq sp-max-pair-length 4)
|
||||
;; This isn't always smart enough to determine when we're in a string or not.
|
||||
;; See https://github.com/Fuco1/smartparens/issues/783.
|
||||
@@ -442,14 +469,15 @@ files, so we replace calls to `pp' with the much faster `prin1'."
|
||||
|
||||
;; Silence some harmless but annoying echo-area spam
|
||||
(dolist (key '(:unmatched-expression :no-matching-tag))
|
||||
(setf (cdr (assq key sp-message-alist)) nil))
|
||||
(setf (alist-get key sp-message-alist) nil))
|
||||
|
||||
(add-hook! 'minibuffer-setup-hook
|
||||
(defun doom-init-smartparens-in-minibuffer-maybe-h ()
|
||||
"Enable `smartparens-mode' in the minibuffer, during `eval-expression' or
|
||||
`evil-ex'."
|
||||
(when (memq this-command '(eval-expression evil-ex))
|
||||
(smartparens-mode))))
|
||||
"Enable `smartparens-mode' in the minibuffer, during `eval-expression',
|
||||
`pp-eval-expression' or `evil-ex'."
|
||||
(and (memq this-command '(eval-expression pp-eval-expression evil-ex))
|
||||
smartparens-global-mode
|
||||
(smartparens-mode))))
|
||||
|
||||
;; You're likely writing lisp in the minibuffer, therefore, disable these
|
||||
;; quote pairs, which lisps doesn't use for strings:
|
||||
@@ -467,16 +495,13 @@ files, so we replace calls to `pp' with the much faster `prin1'."
|
||||
(defun doom-disable-smartparens-mode-maybe-h ()
|
||||
(when smartparens-mode
|
||||
(setq-local doom-buffer-smartparens-mode t)
|
||||
(turn-off-smartparens-mode))))
|
||||
|
||||
(smartparens-global-mode +1))
|
||||
(turn-off-smartparens-mode)))))
|
||||
|
||||
|
||||
(use-package! so-long
|
||||
:after-call after-find-file
|
||||
:hook (doom-first-file . global-so-long-mode)
|
||||
:config
|
||||
(when doom-interactive-mode
|
||||
(global-so-long-mode +1))
|
||||
(setq so-long-threshold 400) ; reduce false positives w/ larger threshold
|
||||
;; Don't disable syntax highlighting and line numbers, or make the buffer
|
||||
;; read-only, in `so-long-minor-mode', so we can have a basic editing
|
||||
;; experience in them, at least. It will remain off in `so-long-mode',
|
||||
@@ -486,6 +511,8 @@ files, so we replace calls to `pp' with the much faster `prin1'."
|
||||
(delq! 'buffer-read-only so-long-variable-overrides 'assq)
|
||||
;; ...but at least reduce the level of syntax highlighting
|
||||
(add-to-list 'so-long-variable-overrides '(font-lock-maximum-decoration . 1))
|
||||
;; ...and insist that save-place not operate in large/long files
|
||||
(add-to-list 'so-long-variable-overrides '(save-place-alist . nil))
|
||||
;; Text files could possibly be too long too
|
||||
(add-to-list 'so-long-target-modes 'text-mode)
|
||||
;; But disable everything else that may be unnecessary/expensive for large
|
||||
@@ -493,6 +520,7 @@ files, so we replace calls to `pp' with the much faster `prin1'."
|
||||
(appendq! so-long-minor-modes
|
||||
'(flycheck-mode
|
||||
flyspell-mode
|
||||
spell-fu-mode
|
||||
eldoc-mode
|
||||
smartparens-mode
|
||||
highlight-numbers-mode
|
||||
@@ -502,60 +530,28 @@ files, so we replace calls to `pp' with the much faster `prin1'."
|
||||
undo-tree-mode
|
||||
highlight-indent-guides-mode
|
||||
hl-fill-column-mode))
|
||||
;; HACK Fix #2183: `so-long-detected-long-line-p' tries to parse comment
|
||||
;; syntax, but in some buffers comment state isn't initialized, leading
|
||||
;; to a wrong-type-argument: stringp error.
|
||||
(defun doom-buffer-has-long-lines-p ()
|
||||
(when (bound-and-true-p comment-use-syntax)
|
||||
;; HACK Fix #2183: `so-long-detected-long-line-p' tries to parse comment
|
||||
;; syntax, but in some buffers comment state isn't initialized,
|
||||
;; leading to a wrong-type-argument: stringp error.
|
||||
(let ((so-long-skip-leading-comments (bound-and-true-p comment-use-syntax))
|
||||
;; HACK If visual-line-mode is on, then false positives are more
|
||||
;; likely, so up the threshold. More so in text-mode, since long
|
||||
;; paragraphs are the norm.
|
||||
(so-long-threshold
|
||||
(if visual-line-mode
|
||||
(* so-long-threshold
|
||||
(if (derived-mode-p 'text-mode)
|
||||
3
|
||||
2))
|
||||
so-long-threshold)))
|
||||
(so-long-detected-long-line-p)))
|
||||
(setq so-long-predicate #'doom-buffer-has-long-lines-p))
|
||||
|
||||
|
||||
(use-package! undo-tree
|
||||
;; Branching & persistent undo
|
||||
:after-call doom-switch-buffer-hook after-find-file
|
||||
:config
|
||||
(setq undo-tree-auto-save-history t
|
||||
;; Increase undo-limits by a factor of ten to avoid emacs prematurely
|
||||
;; truncating the undo history and corrupting the tree. See
|
||||
;; https://github.com/syl20bnr/spacemacs/issues/12110
|
||||
undo-limit 800000
|
||||
undo-strong-limit 12000000
|
||||
undo-outer-limit 120000000
|
||||
undo-tree-history-directory-alist
|
||||
`(("." . ,(concat doom-cache-dir "undo-tree-hist/"))))
|
||||
|
||||
;; Compress undo-tree history files with zstd, if available. File size isn't
|
||||
;; the (only) concern here: the file IO barrier is slow for Emacs to cross;
|
||||
;; reading a tiny file and piping it in-memory through zstd is *slightly*
|
||||
;; faster than Emacs reading the entire undo-tree file from the get go (on
|
||||
;; SSDs). Whether or not that's true in practice, we still enjoy zstd's ~80%
|
||||
;; file savings (these files add up over time and zstd is so incredibly fast).
|
||||
(when (executable-find "zstd")
|
||||
(defadvice! doom--undo-tree-make-history-save-file-name-a (file)
|
||||
:filter-return #'undo-tree-make-history-save-file-name
|
||||
(concat file ".zst")))
|
||||
|
||||
;; Strip text properties from undo-tree data to stave off bloat. File size
|
||||
;; isn't the concern here; undo cache files bloat easily, which can cause
|
||||
;; freezing, crashes, GC-induced stuttering or delays when opening files.
|
||||
(defadvice! doom--undo-tree-strip-text-properties-a (&rest _)
|
||||
:before #'undo-list-transfer-to-tree
|
||||
(dolist (item buffer-undo-list)
|
||||
(and (consp item)
|
||||
(stringp (car item))
|
||||
(setcar item (substring-no-properties (car item))))))
|
||||
|
||||
(global-undo-tree-mode +1))
|
||||
|
||||
|
||||
(use-package! ws-butler
|
||||
;; a less intrusive `delete-trailing-whitespaces' on save
|
||||
:after-call after-find-file
|
||||
:config
|
||||
(appendq! ws-butler-global-exempt-modes
|
||||
'(special-mode comint-mode term-mode eshell-mode))
|
||||
(ws-butler-global-mode))
|
||||
:hook (doom-first-buffer . ws-butler-global-mode))
|
||||
|
||||
(provide 'core-editor)
|
||||
;;; core-editor.el ends here
|
||||
|
||||
@@ -26,9 +26,12 @@ and Emacs states, and for non-evil users.")
|
||||
;;
|
||||
;;; Keybind settings
|
||||
|
||||
(when IS-MAC
|
||||
(setq mac-command-modifier 'super
|
||||
mac-option-modifier 'meta))
|
||||
(cond (IS-MAC
|
||||
(setq mac-command-modifier 'super
|
||||
mac-option-modifier 'meta))
|
||||
(IS-WINDOWS
|
||||
(setq w32-lwindow-modifier 'super
|
||||
w32-rwindow-modifier 'super)))
|
||||
|
||||
|
||||
;;
|
||||
@@ -77,7 +80,8 @@ all hooks after it are ignored.")
|
||||
:init
|
||||
;; Convenience aliases
|
||||
(defalias 'define-key! #'general-def)
|
||||
(defalias 'unmap! #'general-unbind))
|
||||
(defalias 'undefine-key! #'general-unbind))
|
||||
|
||||
|
||||
;; HACK `map!' uses this instead of `define-leader-key!' because it consumes
|
||||
;; 20-30% more startup time, so we reimplement it ourselves.
|
||||
@@ -108,8 +112,8 @@ all hooks after it are ignored.")
|
||||
(general--concat t doom-leader-key ,key)
|
||||
,desc))))))))
|
||||
(macroexp-progn
|
||||
(cons `(after! which-key ,@(nreverse wkforms))
|
||||
(nreverse forms)))))
|
||||
(append (and wkforms `((after! which-key ,@(nreverse wkforms))))
|
||||
(nreverse forms)))))
|
||||
|
||||
(defmacro define-leader-key! (&rest args)
|
||||
"Define <leader> keys.
|
||||
@@ -175,8 +179,7 @@ localleader prefix."
|
||||
;;; Packages
|
||||
|
||||
(use-package! which-key
|
||||
:defer 1
|
||||
:after-call pre-command-hook
|
||||
:hook (doom-first-input . which-key-mode)
|
||||
:init
|
||||
(setq which-key-sort-order #'which-key-prefix-then-key-order
|
||||
which-key-sort-uppercase-first nil
|
||||
@@ -191,9 +194,7 @@ localleader prefix."
|
||||
(setq-hook! 'which-key-init-buffer-hook line-spacing 3)
|
||||
|
||||
(which-key-add-key-based-replacements doom-leader-key "<leader>")
|
||||
(which-key-add-key-based-replacements doom-localleader-key "<localleader>")
|
||||
|
||||
(which-key-mode +1))
|
||||
(which-key-add-key-based-replacements doom-localleader-key "<localleader>"))
|
||||
|
||||
|
||||
;;
|
||||
@@ -215,21 +216,11 @@ localleader prefix."
|
||||
|
||||
For example, :nvi will map to (list 'normal 'visual 'insert). See
|
||||
`doom-evil-state-alist' to customize this."
|
||||
(cl-loop for l across (substring (symbol-name keyword) 1)
|
||||
if (cdr (assq l doom-evil-state-alist)) collect it
|
||||
(cl-loop for l across (doom-keyword-name keyword)
|
||||
if (assq l doom-evil-state-alist) collect (cdr it)
|
||||
else do (error "not a valid state: %s" l)))
|
||||
|
||||
|
||||
;; Register keywords for proper indentation (see `map!')
|
||||
(put :after 'lisp-indent-function 'defun)
|
||||
(put :desc 'lisp-indent-function 'defun)
|
||||
(put :leader 'lisp-indent-function 'defun)
|
||||
(put :localleader 'lisp-indent-function 'defun)
|
||||
(put :map 'lisp-indent-function 'defun)
|
||||
(put :mode 'lisp-indent-function 'defun)
|
||||
(put :prefix 'lisp-indent-function 'defun)
|
||||
(put :prefix-map 'lisp-indent-function 'defun)
|
||||
|
||||
;; specials
|
||||
(defvar doom--map-forms nil)
|
||||
(defvar doom--map-fn nil)
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
;;; core-lib.el -*- lexical-binding: t; -*-
|
||||
|
||||
(require 'cl-lib)
|
||||
(require 'subr-x)
|
||||
|
||||
;;
|
||||
;;; Helpers
|
||||
|
||||
@@ -69,10 +66,10 @@ list is returned as-is."
|
||||
(substring (symbol-name keyword) 1))
|
||||
|
||||
(defmacro doom-log (format-string &rest args)
|
||||
"Log to *Messages* if `doom-debug-mode' is on.
|
||||
"Log to *Messages* if `doom-debug-p' is on.
|
||||
Does not interrupt the minibuffer if it is in use, but still logs to *Messages*.
|
||||
Accepts the same arguments as `message'."
|
||||
`(when doom-debug-mode
|
||||
`(when doom-debug-p
|
||||
(let ((inhibit-message (active-minibuffer-window)))
|
||||
(message
|
||||
,(concat (propertize "DOOM " 'face 'font-lock-comment-face)
|
||||
@@ -85,6 +82,53 @@ Accepts the same arguments as `message'."
|
||||
format-string)
|
||||
,@args))))
|
||||
|
||||
(defun doom-try-run-hook (hook)
|
||||
"Run HOOK (a hook function) with better error handling.
|
||||
Meant to be used with `run-hook-wrapped'."
|
||||
(doom-log "Running doom hook: %s" hook)
|
||||
(condition-case e
|
||||
(funcall hook)
|
||||
((debug error)
|
||||
(signal 'doom-hook-error (list hook e))))
|
||||
;; return nil so `run-hook-wrapped' won't short circuit
|
||||
nil)
|
||||
|
||||
(defun doom-load-envvars-file (file &optional noerror)
|
||||
"Read and set envvars from FILE.
|
||||
If NOERROR is non-nil, don't throw an error if the file doesn't exist or is
|
||||
unreadable. Returns the names of envvars that were changed."
|
||||
(if (null (file-exists-p file))
|
||||
(unless noerror
|
||||
(signal 'file-error (list "No envvar file exists" file)))
|
||||
(when-let
|
||||
(env
|
||||
(with-temp-buffer
|
||||
(save-excursion
|
||||
(setq-local coding-system-for-read 'utf-8)
|
||||
(insert "\0\n") ; to prevent off-by-one
|
||||
(insert-file-contents file))
|
||||
(save-match-data
|
||||
(when (re-search-forward "\0\n *\\([^#= \n]*\\)=" nil t)
|
||||
(setq
|
||||
env (split-string (buffer-substring (match-beginning 1) (point-max))
|
||||
"\0\n"
|
||||
'omit-nulls))))))
|
||||
(setq-default
|
||||
process-environment
|
||||
(append (nreverse env)
|
||||
(default-value 'process-environment))
|
||||
exec-path
|
||||
(append (split-string (getenv "PATH") path-separator t)
|
||||
(list exec-directory))
|
||||
shell-file-name
|
||||
(or (getenv "SHELL")
|
||||
(default-value 'shell-file-name)))
|
||||
env)))
|
||||
|
||||
|
||||
;;
|
||||
;;; Functional library
|
||||
|
||||
(defalias 'doom-partial #'apply-partially)
|
||||
|
||||
(defun doom-rpartial (fn &rest args)
|
||||
@@ -93,6 +137,7 @@ Accepts the same arguments as `message'."
|
||||
ARGS is a list of the last N arguments to pass to FUN. The result is a new
|
||||
function which does the same as FUN, except that the last N arguments are fixed
|
||||
at the values with which this function was called."
|
||||
(declare (side-effect-free t))
|
||||
(lambda (&rest pre-args)
|
||||
(apply fn (append pre-args args))))
|
||||
|
||||
@@ -100,23 +145,10 @@ at the values with which this function was called."
|
||||
;;
|
||||
;;; Sugars
|
||||
|
||||
(defmacro λ! (&rest body)
|
||||
"Expands to (lambda () (interactive) ,@body).
|
||||
A factory for quickly producing interaction commands, particularly for keybinds
|
||||
or aliases."
|
||||
(declare (doc-string 1))
|
||||
`(lambda () (interactive) ,@body))
|
||||
(defalias 'lambda! 'λ!)
|
||||
|
||||
(defun λ!! (command &optional arg)
|
||||
"Expands to a command that interactively calls COMMAND with prefix ARG.
|
||||
A factory for quickly producing interactive, prefixed commands for keybinds or
|
||||
aliases."
|
||||
(declare (doc-string 1))
|
||||
(lambda () (interactive)
|
||||
(let ((current-prefix-arg arg))
|
||||
(call-interactively command))))
|
||||
(defalias 'lambda!! 'λ!!)
|
||||
(defun dir! ()
|
||||
"Returns the directory of the emacs lisp file this macro is called from."
|
||||
(when-let (path (file!))
|
||||
(directory-file-name (file-name-directory path))))
|
||||
|
||||
(defun file! ()
|
||||
"Return the emacs lisp file this macro is called from."
|
||||
@@ -127,18 +159,152 @@ aliases."
|
||||
(buffer-file-name)
|
||||
((error "Cannot get this file-path"))))
|
||||
|
||||
(defun dir! ()
|
||||
"Returns the directory of the emacs lisp file this macro is called from."
|
||||
(when-let (path (file!))
|
||||
(directory-file-name (file-name-directory path))))
|
||||
(defmacro letenv! (envvars &rest body)
|
||||
"Lexically bind ENVVARS in BODY, like `let' but for `process-environment'."
|
||||
(declare (indent 1))
|
||||
`(let ((process-environment (copy-sequence process-environment)))
|
||||
(dolist (var (list ,@(cl-loop for (var val) in envvars
|
||||
collect `(cons ,var ,val))))
|
||||
(setenv (car var) (cdr var)))
|
||||
,@body))
|
||||
|
||||
(defmacro letf! (bindings &rest body)
|
||||
"Temporarily rebind function and macros in BODY.
|
||||
|
||||
BINDINGS is either a) a list of, or a single, `defun' or `defmacro'-ish form, or
|
||||
b) a list of (PLACE VALUE) bindings as `cl-letf*' would accept.
|
||||
|
||||
TYPE is either `defun' or `defmacro'. NAME is the name of the function. If an
|
||||
original definition for NAME exists, it can be accessed as a lexical variable by
|
||||
the same name, for use with `funcall' or `apply'. ARGLIST and BODY are as in
|
||||
`defun'.
|
||||
|
||||
\(fn ((TYPE NAME ARGLIST &rest BODY) ...) BODY...)"
|
||||
(declare (indent defun))
|
||||
(setq body (macroexp-progn body))
|
||||
(when (memq (car bindings) '(defun defmacro))
|
||||
(setq bindings (list bindings)))
|
||||
(dolist (binding (reverse bindings) (macroexpand body))
|
||||
(let ((type (car binding))
|
||||
(rest (cdr binding)))
|
||||
(setq
|
||||
body (pcase type
|
||||
(`defmacro `(cl-macrolet ((,@rest)) ,body))
|
||||
(`defun `(cl-letf* ((,(car rest) (symbol-function #',(car rest)))
|
||||
((symbol-function #',(car rest))
|
||||
(lambda ,(cadr rest) ,@(cddr rest))))
|
||||
(ignore ,(car rest))
|
||||
,body))
|
||||
(_
|
||||
(when (eq (car-safe type) 'function)
|
||||
(setq type (list 'symbol-function type)))
|
||||
(list 'cl-letf (list (cons type rest)) body)))))))
|
||||
|
||||
(defmacro quiet! (&rest forms)
|
||||
"Run FORMS without generating any output.
|
||||
|
||||
This silences calls to `message', `load', `write-region' and anything that
|
||||
writes to `standard-output'."
|
||||
`(if doom-debug-p
|
||||
(progn ,@forms)
|
||||
,(if doom-interactive-p
|
||||
`(let ((inhibit-message t)
|
||||
(save-silently t))
|
||||
(prog1 ,@forms (message "")))
|
||||
`(letf! ((standard-output (lambda (&rest _)))
|
||||
(defun message (&rest _))
|
||||
(defun load (file &optional noerror nomessage nosuffix must-suffix)
|
||||
(funcall load file noerror t nosuffix must-suffix))
|
||||
(defun write-region (start end filename &optional append visit lockname mustbenew)
|
||||
(unless visit (setq visit 'no-message))
|
||||
(funcall write-region start end filename append visit lockname mustbenew)))
|
||||
,@forms))))
|
||||
|
||||
(defmacro if! (cond then &rest body)
|
||||
"Expands to THEN if COND is non-nil, to BODY otherwise.
|
||||
COND is checked at compile/expansion time, allowing BODY to be omitted
|
||||
entirely when the elisp is byte-compiled. Use this for forms that contain
|
||||
expensive macros that could safely be removed at compile time."
|
||||
(declare (indent 2))
|
||||
(if (eval cond)
|
||||
then
|
||||
(macroexp-progn body)))
|
||||
|
||||
(defmacro when! (cond &rest body)
|
||||
"Expands to BODY if CONDITION is non-nil at compile/expansion time.
|
||||
See `if!' for details on this macro's purpose."
|
||||
(declare (indent 1))
|
||||
(when (eval cond)
|
||||
(macroexp-progn body)))
|
||||
|
||||
|
||||
;;; Closure factories
|
||||
(defmacro fn! (arglist &rest body)
|
||||
"Expands to (cl-function (lambda ARGLIST BODY...))"
|
||||
(declare (indent defun) (doc-string 1) (pure t) (side-effect-free t))
|
||||
`(cl-function (lambda ,arglist ,@body)))
|
||||
|
||||
(defmacro cmd! (&rest body)
|
||||
"Expands to (lambda () (interactive) ,@body).
|
||||
A factory for quickly producing interaction commands, particularly for keybinds
|
||||
or aliases."
|
||||
(declare (doc-string 1) (pure t) (side-effect-free t))
|
||||
`(lambda (&rest _) (interactive) ,@body))
|
||||
|
||||
(defmacro cmd!! (command &rest args)
|
||||
"Expands to a closure that interactively calls COMMAND with ARGS.
|
||||
A factory for quickly producing interactive, prefixed commands for keybinds or
|
||||
aliases."
|
||||
(declare (doc-string 1) (pure t) (side-effect-free t))
|
||||
`(lambda (&rest _) (interactive)
|
||||
(funcall-interactively ,command ,@args)))
|
||||
|
||||
(defmacro cmds! (&rest branches)
|
||||
"Expands to a `menu-item' dispatcher for keybinds."
|
||||
(declare (doc-string 1))
|
||||
(let ((docstring (if (stringp (car branches)) (pop branches) ""))
|
||||
fallback)
|
||||
(when (cl-oddp (length branches))
|
||||
(setq fallback (car (last branches))
|
||||
branches (butlast branches)))
|
||||
`(general-predicate-dispatch ,fallback
|
||||
:docstring ,docstring
|
||||
,@branches)))
|
||||
|
||||
;; For backwards compatibility
|
||||
(defalias 'λ! 'cmd!)
|
||||
(defalias 'λ!! 'cmd!!)
|
||||
;; DEPRECATED These have been superseded by `cmd!' and `cmd!!'
|
||||
(define-obsolete-function-alias 'lambda! 'cmd! "3.0.0")
|
||||
(define-obsolete-function-alias 'lambda!! 'cmd!! "3.0.0")
|
||||
|
||||
|
||||
;;; Mutation
|
||||
(defmacro appendq! (sym &rest lists)
|
||||
"Append LISTS to SYM in place."
|
||||
`(setq ,sym (append ,sym ,@lists)))
|
||||
|
||||
(defmacro setq! (&rest settings)
|
||||
"A stripped-down `customize-set-variable' with the syntax of `setq'."
|
||||
"A stripped-down `customize-set-variable' with the syntax of `setq'.
|
||||
|
||||
This can be used as a drop-in replacement for `setq'. Particularly when you know
|
||||
a variable has a custom setter (a :set property in its `defcustom' declaration).
|
||||
This triggers setters. `setq' does not."
|
||||
(macroexp-progn
|
||||
(cl-loop for (var val) on settings by 'cddr
|
||||
collect `(funcall (or (get ',var 'custom-set) #'set)
|
||||
',var ,val))))
|
||||
|
||||
(defmacro delq! (elt list &optional fetcher)
|
||||
"`delq' ELT from LIST in-place.
|
||||
|
||||
If FETCHER is a function, ELT is used as the key in LIST (an alist)."
|
||||
`(setq ,list
|
||||
(delq ,(if fetcher
|
||||
`(funcall ,fetcher ,elt ,list)
|
||||
elt)
|
||||
,list)))
|
||||
|
||||
(defmacro pushnew! (place &rest values)
|
||||
"Push VALUES sequentially into PLACE, if they aren't already present.
|
||||
This is a variadic `cl-pushnew'."
|
||||
@@ -150,31 +316,8 @@ This is a variadic `cl-pushnew'."
|
||||
"Prepend LISTS to SYM in place."
|
||||
`(setq ,sym (append ,@lists ,sym)))
|
||||
|
||||
(defmacro appendq! (sym &rest lists)
|
||||
"Append LISTS to SYM in place."
|
||||
`(setq ,sym (append ,sym ,@lists)))
|
||||
|
||||
(defmacro nconcq! (sym &rest lists)
|
||||
"Append LISTS to SYM by altering them in place."
|
||||
`(setq ,sym (nconc ,sym ,@lists)))
|
||||
|
||||
(defmacro delq! (elt list &optional fetcher)
|
||||
"`delq' ELT from LIST in-place.
|
||||
|
||||
If FETCHER is a function, ELT is used as the key in LIST (an alist)."
|
||||
`(setq ,list
|
||||
(delq ,(if fetcher
|
||||
`(funcall ,fetcher ,elt ,list)
|
||||
elt)
|
||||
,list)))
|
||||
|
||||
(defmacro letenv! (envvars &rest body)
|
||||
"Lexically bind ENVVARS in BODY, like `let' but for `process-environment'."
|
||||
`(let ((process-environment (copy-sequence process-environment)))
|
||||
(dolist (var ',envvars)
|
||||
(setenv (car var) (cadr var)))
|
||||
,@body))
|
||||
|
||||
;;; Loading
|
||||
(defmacro add-load-path! (&rest dirs)
|
||||
"Add DIRS to `load-path', relative to the current file.
|
||||
The current file is the file from which `add-to-load-path!' is used."
|
||||
@@ -183,6 +326,136 @@ The current file is the file from which `add-to-load-path!' is used."
|
||||
(dolist (dir (list ,@dirs))
|
||||
(cl-pushnew (expand-file-name dir) load-path))))
|
||||
|
||||
(defmacro after! (package &rest body)
|
||||
"Evaluate BODY after PACKAGE have loaded.
|
||||
|
||||
PACKAGE is a symbol or list of them. These are package names, not modes,
|
||||
functions or variables. It can be:
|
||||
|
||||
- An unquoted package symbol (the name of a package)
|
||||
(after! helm BODY...)
|
||||
- An unquoted list of package symbols (i.e. BODY is evaluated once both magit
|
||||
and git-gutter have loaded)
|
||||
(after! (magit git-gutter) BODY...)
|
||||
- An unquoted, nested list of compound package lists, using any combination of
|
||||
:or/:any and :and/:all
|
||||
(after! (:or package-a package-b ...) BODY...)
|
||||
(after! (:and package-a package-b ...) BODY...)
|
||||
(after! (:and package-a (:or package-b package-c) ...) BODY...)
|
||||
Without :or/:any/:and/:all, :and/:all are implied.
|
||||
|
||||
This is a wrapper around `eval-after-load' that:
|
||||
|
||||
1. Suppresses warnings for disabled packages at compile-time
|
||||
2. No-ops for package that are disabled by the user (via `package!')
|
||||
3. Supports compound package statements (see below)
|
||||
4. Prevents eager expansion pulling in autoloaded macros all at once"
|
||||
(declare (indent defun) (debug t))
|
||||
(if (symbolp package)
|
||||
(unless (memq package (bound-and-true-p doom-disabled-packages))
|
||||
(list (if (or (not (bound-and-true-p byte-compile-current-file))
|
||||
(require package nil 'noerror))
|
||||
#'progn
|
||||
#'with-no-warnings)
|
||||
(let ((body (macroexp-progn body)))
|
||||
`(if (featurep ',package)
|
||||
,body
|
||||
;; We intentionally avoid `with-eval-after-load' to prevent
|
||||
;; eager macro expansion from pulling (or failing to pull) in
|
||||
;; autoloaded macros/packages.
|
||||
(eval-after-load ',package ',body)))))
|
||||
(let ((p (car package)))
|
||||
(cond ((not (keywordp p))
|
||||
`(after! (:and ,@package) ,@body))
|
||||
((memq p '(:or :any))
|
||||
(macroexp-progn
|
||||
(cl-loop for next in (cdr package)
|
||||
collect `(after! ,next ,@body))))
|
||||
((memq p '(:and :all))
|
||||
(dolist (next (cdr package))
|
||||
(setq body `((after! ,next ,@body))))
|
||||
(car body))))))
|
||||
|
||||
(defun doom--handle-load-error (e target path)
|
||||
(let* ((source (file-name-sans-extension target))
|
||||
(err (cond ((not (featurep 'core))
|
||||
(cons 'error (file-name-directory path)))
|
||||
((file-in-directory-p source doom-core-dir)
|
||||
(cons 'doom-error doom-core-dir))
|
||||
((file-in-directory-p source doom-private-dir)
|
||||
(cons 'doom-private-error doom-private-dir))
|
||||
((cons 'doom-module-error doom-emacs-dir)))))
|
||||
(signal (car err)
|
||||
(list (file-relative-name
|
||||
(concat source ".el")
|
||||
(cdr err))
|
||||
e))))
|
||||
|
||||
(defmacro load! (filename &optional path noerror)
|
||||
"Load a file relative to the current executing file (`load-file-name').
|
||||
|
||||
FILENAME is either a file path string or a form that should evaluate to such a
|
||||
string at run time. PATH is where to look for the file (a string representing a
|
||||
directory path). If omitted, the lookup is relative to either `load-file-name',
|
||||
`byte-compile-current-file' or `buffer-file-name' (checked in that order).
|
||||
|
||||
If NOERROR is non-nil, don't throw an error if the file doesn't exist."
|
||||
(let* ((path (or path
|
||||
(dir!)
|
||||
(error "Could not detect path to look for '%s' in"
|
||||
filename)))
|
||||
(file (if path
|
||||
`(expand-file-name ,filename ,path)
|
||||
filename)))
|
||||
`(condition-case-unless-debug e
|
||||
(let (file-name-handler-alist)
|
||||
(load ,file ,noerror 'nomessage))
|
||||
(doom-error (signal (car e) (cdr e)))
|
||||
(error (doom--handle-load-error e ,file ,path)))))
|
||||
|
||||
(defmacro defer-until! (condition &rest body)
|
||||
"Run BODY when CONDITION is true (checks on `after-load-functions'). Meant to
|
||||
serve as a predicated alternative to `after!'."
|
||||
(declare (indent defun) (debug t))
|
||||
`(if ,condition
|
||||
(progn ,@body)
|
||||
,(let ((fn (intern (format "doom--delay-form-%s-h" (sxhash (cons condition body))))))
|
||||
`(progn
|
||||
(fset ',fn (lambda (&rest args)
|
||||
(when ,(or condition t)
|
||||
(remove-hook 'after-load-functions #',fn)
|
||||
(unintern ',fn nil)
|
||||
(ignore args)
|
||||
,@body)))
|
||||
(put ',fn 'permanent-local-hook t)
|
||||
(add-hook 'after-load-functions #',fn)))))
|
||||
|
||||
(defmacro defer-feature! (feature &rest fns)
|
||||
"Pretend FEATURE hasn't been loaded yet, until FEATURE-hook or FN runs.
|
||||
|
||||
Some packages (like `elisp-mode' and `lisp-mode') are loaded immediately at
|
||||
startup, which will prematurely trigger `after!' (and `with-eval-after-load')
|
||||
blocks. To get around this we make Emacs believe FEATURE hasn't been loaded yet,
|
||||
then wait until FEATURE-hook (or MODE-hook, if FN is provided) is triggered to
|
||||
reverse this and trigger `after!' blocks at a more reasonable time."
|
||||
(let ((advice-fn (intern (format "doom--defer-feature-%s-a" feature))))
|
||||
`(progn
|
||||
(delq! ',feature features)
|
||||
(defadvice! ,advice-fn (&rest _)
|
||||
:before ',fns
|
||||
;; Some plugins (like yasnippet) will invoke a fn early to parse
|
||||
;; code, which would prematurely trigger this. In those cases, well
|
||||
;; behaved plugins will use `delay-mode-hooks', which we can check for:
|
||||
(unless delay-mode-hooks
|
||||
;; ...Otherwise, announce to the world this package has been loaded,
|
||||
;; so `after!' handlers can react.
|
||||
(provide ',feature)
|
||||
(dolist (fn ',fns)
|
||||
(advice-remove fn #',advice-fn)))))))
|
||||
|
||||
|
||||
;;; Hooks
|
||||
(defvar doom--transient-counter 0)
|
||||
(defmacro add-transient-hook! (hook-or-function &rest forms)
|
||||
"Attaches a self-removing function to HOOK-OR-FUNCTION.
|
||||
|
||||
@@ -193,9 +466,12 @@ HOOK-OR-FUNCTION can be a quoted hook or a sharp-quoted function (which will be
|
||||
advised)."
|
||||
(declare (indent 1))
|
||||
(let ((append (if (eq (car forms) :after) (pop forms)))
|
||||
(fn (intern (format "doom--transient-%s-h" (sxhash hook-or-function)))))
|
||||
;; Avoid `make-symbol' and `gensym' here because an interned symbol is
|
||||
;; easier to debug in backtraces (and is visible to `describe-function')
|
||||
(fn (intern (format "doom--transient-%d-h" (cl-incf doom--transient-counter)))))
|
||||
`(let ((sym ,hook-or-function))
|
||||
(defun ,fn (&rest _)
|
||||
,(format "Transient hook for %S" (doom-unquote hook-or-function))
|
||||
,@forms
|
||||
(let ((sym ,hook-or-function))
|
||||
(cond ((functionp sym) (advice-remove sym #',fn))
|
||||
@@ -207,20 +483,29 @@ advised)."
|
||||
(put ',fn 'permanent-local-hook t)
|
||||
(add-hook sym #',fn ,append))))))
|
||||
|
||||
(defmacro add-hook-trigger! (hook-var &rest targets)
|
||||
"TODO"
|
||||
`(let ((fn (intern (format "%s-h" ,hook-var))))
|
||||
(fset fn (lambda (&rest _) (run-hooks ,hook-var) (set ,hook-var nil)))
|
||||
(put ,hook-var 'permanent-local t)
|
||||
(dolist (on (list ,@targets))
|
||||
(if (functionp on)
|
||||
(advice-add on :before fn)
|
||||
(add-hook on fn)))))
|
||||
|
||||
(defmacro add-hook! (hooks &rest rest)
|
||||
"A convenience macro for adding N functions to M hooks.
|
||||
|
||||
If N and M = 1, there's no benefit to using this macro over `add-hook'.
|
||||
|
||||
This macro accepts, in order:
|
||||
|
||||
1. Optional properties :local and/or :append, which will make the hook
|
||||
1. The mode(s) or hook(s) to add to. This is either an unquoted mode, an
|
||||
unquoted list of modes, a quoted hook variable or a quoted list of hook
|
||||
variables.
|
||||
2. Optional properties :local and/or :append, which will make the hook
|
||||
buffer-local or append to the list of hooks (respectively),
|
||||
2. The hook(s) to be added to: either an unquoted mode, an unquoted list of
|
||||
modes, a quoted hook variable or a quoted list of hook variables. If
|
||||
unquoted, '-hook' will be appended to each symbol.
|
||||
3. The function(s) to be added: this can be one function, a list thereof, a
|
||||
list of `defun's, or body forms (implicitly wrapped in a closure).
|
||||
3. The function(s) to be added: this can be one function, a quoted list
|
||||
thereof, a list of `defun's, or body forms (implicitly wrapped in a
|
||||
lambda).
|
||||
|
||||
\(fn HOOKS [:append :local] FUNCTIONS)"
|
||||
(declare (indent (lambda (indent-point state)
|
||||
@@ -301,106 +586,8 @@ If N and M = 1, there's no benefit to using this macro over `remove-hook'.
|
||||
in (doom--setq-hook-fns hooks vars 'singles)
|
||||
collect `(remove-hook ',hook #',fn))))
|
||||
|
||||
(defmacro load! (filename &optional path noerror)
|
||||
"Load a file relative to the current executing file (`load-file-name').
|
||||
|
||||
FILENAME is either a file path string or a form that should evaluate to such a
|
||||
string at run time. PATH is where to look for the file (a string representing a
|
||||
directory path). If omitted, the lookup is relative to either `load-file-name',
|
||||
`byte-compile-current-file' or `buffer-file-name' (checked in that order).
|
||||
|
||||
If NOERROR is non-nil, don't throw an error if the file doesn't exist."
|
||||
(let* ((path (or path
|
||||
(dir!)
|
||||
(error "Could not detect path to look for '%s' in"
|
||||
filename)))
|
||||
(file (if path
|
||||
`(expand-file-name ,filename ,path)
|
||||
filename)))
|
||||
`(condition-case-unless-debug e
|
||||
(let (file-name-handler-alist)
|
||||
(load ,file ,noerror 'nomessage))
|
||||
(doom-error (signal (car e) (cdr e)))
|
||||
(error
|
||||
(let* ((source (file-name-sans-extension ,file))
|
||||
(err (cond ((not (featurep 'core))
|
||||
(cons 'error (file-name-directory path)))
|
||||
((file-in-directory-p source doom-core-dir)
|
||||
(cons 'doom-error doom-core-dir))
|
||||
((file-in-directory-p source doom-private-dir)
|
||||
(cons 'doom-private-error doom-private-dir))
|
||||
((cons 'doom-module-error doom-emacs-dir)))))
|
||||
(signal (car err)
|
||||
(list (file-relative-name
|
||||
(concat source ".el")
|
||||
(cdr err))
|
||||
e)))))))
|
||||
|
||||
(defmacro defer-until! (condition &rest body)
|
||||
"Run BODY when CONDITION is true (checks on `after-load-functions'). Meant to
|
||||
serve as a predicated alternative to `after!'."
|
||||
(declare (indent defun) (debug t))
|
||||
`(if ,condition
|
||||
(progn ,@body)
|
||||
,(let ((fn (intern (format "doom--delay-form-%s-h" (sxhash (cons condition body))))))
|
||||
`(progn
|
||||
(fset ',fn (lambda (&rest args)
|
||||
(when ,(or condition t)
|
||||
(remove-hook 'after-load-functions #',fn)
|
||||
(unintern ',fn nil)
|
||||
(ignore args)
|
||||
,@body)))
|
||||
(put ',fn 'permanent-local-hook t)
|
||||
(add-hook 'after-load-functions #',fn)))))
|
||||
|
||||
(defmacro defer-feature! (feature &optional fn)
|
||||
"Pretend FEATURE hasn't been loaded yet, until FEATURE-hook or FN runs.
|
||||
|
||||
Some packages (like `elisp-mode' and `lisp-mode') are loaded immediately at
|
||||
startup, which will prematurely trigger `after!' (and `with-eval-after-load')
|
||||
blocks. To get around this we make Emacs believe FEATURE hasn't been loaded yet,
|
||||
then wait until FEATURE-hook (or MODE-hook, if FN is provided) is triggered to
|
||||
reverse this and trigger `after!' blocks at a more reasonable time."
|
||||
(let ((advice-fn (intern (format "doom--defer-feature-%s-a" feature)))
|
||||
(fn (or fn feature)))
|
||||
`(progn
|
||||
(setq features (delq ',feature features))
|
||||
(advice-add #',fn :before #',advice-fn)
|
||||
(defun ,advice-fn (&rest _)
|
||||
;; Some plugins (like yasnippet) will invoke a fn early to parse
|
||||
;; code, which would prematurely trigger this. In those cases, well
|
||||
;; behaved plugins will use `delay-mode-hooks', which we can check for:
|
||||
(when (and ,(intern (format "%s-hook" fn))
|
||||
(not delay-mode-hooks))
|
||||
;; ...Otherwise, announce to the world this package has been loaded,
|
||||
;; so `after!' handlers can react.
|
||||
(provide ',feature)
|
||||
(advice-remove #',fn #',advice-fn))))))
|
||||
|
||||
(defmacro quiet! (&rest forms)
|
||||
"Run FORMS without generating any output.
|
||||
|
||||
This silences calls to `message', `load-file', `write-region' and anything that
|
||||
writes to `standard-output'."
|
||||
`(cond (doom-debug-mode ,@forms)
|
||||
((not doom-interactive-mode)
|
||||
(let ((old-fn (symbol-function 'write-region)))
|
||||
(cl-letf ((standard-output (lambda (&rest _)))
|
||||
((symbol-function 'load-file) (lambda (file) (load file nil t)))
|
||||
((symbol-function 'message) (lambda (&rest _)))
|
||||
((symbol-function 'write-region)
|
||||
(lambda (start end filename &optional append visit lockname mustbenew)
|
||||
(unless visit (setq visit 'no-message))
|
||||
(funcall old-fn start end filename append visit lockname mustbenew))))
|
||||
,@forms)))
|
||||
((let ((inhibit-message t)
|
||||
(save-silently t))
|
||||
(prog1 ,@forms (message ""))))))
|
||||
|
||||
|
||||
;;
|
||||
;;; Definers
|
||||
|
||||
(defmacro defadvice! (symbol arglist &optional docstring &rest body)
|
||||
"Define an advice called SYMBOL and add it to PLACES.
|
||||
|
||||
@@ -419,10 +606,63 @@ DOCSTRING and BODY are as in `defun'.
|
||||
where-alist))
|
||||
`(progn
|
||||
(defun ,symbol ,arglist ,docstring ,@body)
|
||||
,(when where-alist
|
||||
`(dolist (targets (list ,@(nreverse where-alist)))
|
||||
(dolist (target (cdr targets))
|
||||
(advice-add target (car targets) #',symbol)))))))
|
||||
(dolist (targets (list ,@(nreverse where-alist)))
|
||||
(dolist (target (cdr targets))
|
||||
(advice-add target (car targets) #',symbol))))))
|
||||
|
||||
(defmacro undefadvice! (symbol _arglist &optional docstring &rest body)
|
||||
"Undefine an advice called SYMBOL.
|
||||
|
||||
This has the same signature as `defadvice!' an exists as an easy undefiner when
|
||||
testing advice (when combined with `rotate-text').
|
||||
|
||||
\(fn SYMBOL ARGLIST &optional DOCSTRING &rest [WHERE PLACES...] BODY\)"
|
||||
(declare (doc-string 3) (indent defun))
|
||||
(let (where-alist)
|
||||
(unless (stringp docstring)
|
||||
(push docstring body))
|
||||
(while (keywordp (car body))
|
||||
(push `(cons ,(pop body) (doom-enlist ,(pop body)))
|
||||
where-alist))
|
||||
`(dolist (targets (list ,@(nreverse where-alist)))
|
||||
(dolist (target (cdr targets))
|
||||
(advice-remove target #',symbol)))))
|
||||
|
||||
|
||||
;;
|
||||
;;; Backports
|
||||
|
||||
(when! (not EMACS27+)
|
||||
;; DEPRECATED Backported from Emacs 27
|
||||
(defmacro setq-local (&rest pairs)
|
||||
"Make variables in PAIRS buffer-local and assign them the corresponding values.
|
||||
|
||||
PAIRS is a list of variable/value pairs. For each variable, make
|
||||
it buffer-local and assign it the corresponding value. The
|
||||
variables are literal symbols and should not be quoted.
|
||||
|
||||
The second VALUE is not computed until after the first VARIABLE
|
||||
is set, and so on; each VALUE can use the new value of variables
|
||||
set earlier in the ‘setq-local’. The return value of the
|
||||
‘setq-local’ form is the value of the last VALUE.
|
||||
|
||||
\(fn [VARIABLE VALUE]...)"
|
||||
(declare (debug setq))
|
||||
(unless (zerop (mod (length pairs) 2))
|
||||
(error "PAIRS must have an even number of variable/value members"))
|
||||
(let ((expr nil))
|
||||
(while pairs
|
||||
(unless (symbolp (car pairs))
|
||||
(error "Attempting to set a non-symbol: %s" (car pairs)))
|
||||
;; Can't use backquote here, it's too early in the bootstrap.
|
||||
(setq expr
|
||||
(cons
|
||||
(list 'set
|
||||
(list 'make-local-variable (list 'quote (car pairs)))
|
||||
(car (cdr pairs)))
|
||||
expr))
|
||||
(setq pairs (cdr (cdr pairs))))
|
||||
(macroexp-progn (nreverse expr)))))
|
||||
|
||||
(provide 'core-lib)
|
||||
;;; core-lib.el ends here
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
(defvar doom-init-modules-p nil
|
||||
"Non-nil if `doom-initialize-modules' has run.")
|
||||
|
||||
(defvar doom-modules ()
|
||||
(defvar doom-modules (make-hash-table :test 'equal)
|
||||
"A hash table of enabled modules. Set by `doom-initialize-modules'.")
|
||||
|
||||
(defvar doom-modules-dirs
|
||||
@@ -11,36 +11,52 @@
|
||||
doom-modules-dir)
|
||||
"A list of module root directories. Order determines priority.")
|
||||
|
||||
(defvar doom-module-init-file "init"
|
||||
"The basename of init files for modules.
|
||||
|
||||
Init files are loaded early, just after Doom core, and before modules' config
|
||||
files. They are always loaded, even in non-interactive sessions, and before
|
||||
`doom-before-init-modules-hook'. Related to `doom-module-config-file'.")
|
||||
|
||||
(defvar doom-module-config-file "config"
|
||||
"The basename of config files for modules.
|
||||
|
||||
Config files are loaded later, and almost always in interactive sessions. These
|
||||
run before `doom-init-modules-hook'. Relevant to `doom-module-init-file'.")
|
||||
|
||||
(defconst doom-obsolete-modules
|
||||
'((:feature (version-control (:emacs vc) (:ui vc-gutter))
|
||||
(spellcheck (:tools flyspell))
|
||||
(syntax-checker (:tools flycheck))
|
||||
(evil (:editor evil))
|
||||
(snippets (:editor snippets))
|
||||
(file-templates (:editor file-templates))
|
||||
(workspaces (:ui workspaces))
|
||||
(eval (:tools eval))
|
||||
(lookup (:tools lookup))
|
||||
(debugger (:tools debugger)))
|
||||
(:tools (rotate-text (:editor rotate-text))
|
||||
(vterm (:term vterm))
|
||||
(password-store (:tools pass)))
|
||||
(:emacs (electric-indent (:emacs electric))
|
||||
(hideshow (:editor fold))
|
||||
(eshell (:term eshell))
|
||||
(term (:term term)))
|
||||
(:ui (doom-modeline (:ui modeline))
|
||||
(fci (:ui fill-column))
|
||||
(evil-goggles (:ui ophints))
|
||||
(tabbar (:ui tabs)))
|
||||
(:app (email (:email mu4e))
|
||||
(notmuch (:email notmuch))))
|
||||
'((:feature (version-control (:emacs vc) (:ui vc-gutter))
|
||||
(spellcheck (:checkers spell))
|
||||
(syntax-checker (:checkers syntax))
|
||||
(evil (:editor evil))
|
||||
(snippets (:editor snippets))
|
||||
(file-templates (:editor file-templates))
|
||||
(workspaces (:ui workspaces))
|
||||
(eval (:tools eval))
|
||||
(lookup (:tools lookup))
|
||||
(debugger (:tools debugger)))
|
||||
(:tools (rotate-text (:editor rotate-text))
|
||||
(vterm (:term vterm))
|
||||
(password-store (:tools pass))
|
||||
(flycheck (:checkers syntax))
|
||||
(flyspell (:checkers spell)))
|
||||
(:emacs (electric-indent (:emacs electric))
|
||||
(hideshow (:editor fold))
|
||||
(eshell (:term eshell))
|
||||
(term (:term term)))
|
||||
(:ui (doom-modeline (:ui modeline))
|
||||
(fci (:ui fill-column))
|
||||
(evil-goggles (:ui ophints))
|
||||
(tabbar (:ui tabs)))
|
||||
(:app (email (:email mu4e))
|
||||
(notmuch (:email notmuch)))
|
||||
(:lang (perl (:lang raku))))
|
||||
"A tree alist that maps deprecated modules to their replacement(s).
|
||||
|
||||
Each entry is a three-level tree. For example:
|
||||
|
||||
(:feature (version-control (:emacs vc) (:ui vc-gutter))
|
||||
(spellcheck (:tools flyspell))
|
||||
(spellcheck (:checkers spell))
|
||||
(syntax-checker (:tools flycheck)))
|
||||
|
||||
This marks :feature version-control, :feature spellcheck and :feature
|
||||
@@ -48,7 +64,7 @@ syntax-checker modules obsolete. e.g. If :feature version-control is found in
|
||||
your `doom!' block, a warning is emitted before replacing it with :emacs vc and
|
||||
:ui vc-gutter.")
|
||||
|
||||
(defvar doom-inhibit-module-warnings doom-interactive-mode
|
||||
(defvar doom-inhibit-module-warnings doom-interactive-p
|
||||
"If non-nil, don't emit deprecated or missing module warnings at startup.")
|
||||
|
||||
;;; Custom hooks
|
||||
@@ -69,28 +85,39 @@ before the user's private module.")
|
||||
;;
|
||||
;;; Bootstrap API
|
||||
|
||||
(defun doom-initialize-modules (&optional force-p)
|
||||
(defun doom-initialize-core-modules ()
|
||||
"Load Doom's core files for an interactive session."
|
||||
(require 'core-keybinds)
|
||||
(require 'core-ui)
|
||||
(require 'core-projects)
|
||||
(require 'core-editor))
|
||||
|
||||
(defun doom-module-loader (file)
|
||||
"Return a closure that loads FILE from a module.
|
||||
|
||||
This closure takes two arguments: a cons cell containing (CATEGORY . MODULE)
|
||||
symbols, and that module's plist."
|
||||
(declare (pure t) (side-effect-free t))
|
||||
(lambda (module plist)
|
||||
(let ((doom--current-module module)
|
||||
(doom--current-flags (plist-get plist :flags)))
|
||||
(load! file (plist-get plist :path) t))))
|
||||
|
||||
(defun doom-initialize-modules (&optional force-p no-config-p)
|
||||
"Loads the init.el in `doom-private-dir' and sets up hooks for a healthy
|
||||
session of Dooming. Will noop if used more than once, unless FORCE-P is
|
||||
non-nil."
|
||||
(when (or force-p (not doom-init-modules-p))
|
||||
(setq doom-init-modules-p t
|
||||
doom-modules nil)
|
||||
(when (load! "init" doom-private-dir t)
|
||||
(when doom-modules
|
||||
(maphash (lambda (key plist)
|
||||
(let ((doom--current-module key)
|
||||
(doom--current-flags (plist-get plist :flags)))
|
||||
(load! "init" (plist-get plist :path) t)))
|
||||
doom-modules))
|
||||
(setq doom-init-modules-p t)
|
||||
(unless no-config-p
|
||||
(doom-log "Initializing core modules")
|
||||
(doom-initialize-core-modules))
|
||||
(when-let (init-p (load! doom-module-init-file doom-private-dir t))
|
||||
(doom-log "Initializing user config")
|
||||
(maphash (doom-module-loader doom-module-init-file) doom-modules)
|
||||
(run-hook-wrapped 'doom-before-init-modules-hook #'doom-try-run-hook)
|
||||
(when doom-interactive-mode
|
||||
(when doom-modules
|
||||
(maphash (lambda (key plist)
|
||||
(let ((doom--current-module key)
|
||||
(doom--current-flags (plist-get plist :flags)))
|
||||
(load! "config" (plist-get plist :path) t)))
|
||||
doom-modules))
|
||||
(unless no-config-p
|
||||
(maphash (doom-module-loader doom-module-config-file) doom-modules)
|
||||
(run-hook-wrapped 'doom-init-modules-hook #'doom-try-run-hook)
|
||||
(load! "config" doom-private-dir t)))))
|
||||
|
||||
@@ -101,11 +128,10 @@ non-nil."
|
||||
(defun doom-module-p (category module &optional flag)
|
||||
"Returns t if CATEGORY MODULE is enabled (ie. present in `doom-modules')."
|
||||
(declare (pure t) (side-effect-free t))
|
||||
(let ((plist (gethash (cons category module) doom-modules)))
|
||||
(and plist
|
||||
(or (null flag)
|
||||
(memq flag (plist-get plist :flags)))
|
||||
t)))
|
||||
(when-let (plist (gethash (cons category module) doom-modules))
|
||||
(or (null flag)
|
||||
(and (memq flag (plist-get plist :flags))
|
||||
t))))
|
||||
|
||||
(defun doom-module-get (category module &optional property)
|
||||
"Returns the plist for CATEGORY MODULE. Gets PROPERTY, specifically, if set."
|
||||
@@ -120,15 +146,17 @@ non-nil."
|
||||
of PROPERTY and VALUEs.
|
||||
|
||||
\(fn CATEGORY MODULE PROPERTY VALUE &rest [PROPERTY VALUE [...]])"
|
||||
(if-let (old-plist (doom-module-get category module))
|
||||
(progn
|
||||
(when plist
|
||||
(when (cl-oddp (length plist))
|
||||
(signal 'wrong-number-of-arguments (list (length plist))))
|
||||
(while plist
|
||||
(plist-put old-plist (pop plist) (pop plist))))
|
||||
(puthash (cons category module) old-plist doom-modules))
|
||||
(puthash (cons category module) plist doom-modules)))
|
||||
(puthash (cons category module)
|
||||
(if-let (old-plist (doom-module-get category module))
|
||||
(if (null plist)
|
||||
old-plist
|
||||
(when (cl-oddp (length plist))
|
||||
(signal 'wrong-number-of-arguments (list (length plist))))
|
||||
(while plist
|
||||
(plist-put old-plist (pop plist) (pop plist)))
|
||||
old-plist)
|
||||
plist)
|
||||
doom-modules))
|
||||
|
||||
(defun doom-module-set (category module &rest plist)
|
||||
"Enables a module by adding it to `doom-modules'.
|
||||
@@ -140,10 +168,8 @@ following properties:
|
||||
:path [STRING] path to category root directory
|
||||
|
||||
Example:
|
||||
(doom-module-set :lang 'haskell :flags '(+intero))"
|
||||
(puthash (cons category module)
|
||||
plist
|
||||
doom-modules))
|
||||
(doom-module-set :lang 'haskell :flags '(+dante))"
|
||||
(puthash (cons category module) plist doom-modules))
|
||||
|
||||
(defun doom-module-path (category module &optional file)
|
||||
"Like `expand-file-name', but expands FILE relative to CATEGORY (keywordp) and
|
||||
@@ -211,45 +237,108 @@ those directories. The first returned path is always `doom-private-dir'."
|
||||
(declare (pure t) (side-effect-free t))
|
||||
(append (list doom-private-dir)
|
||||
(if module-dirs
|
||||
(doom-files-in (if (listp module-dirs)
|
||||
module-dirs
|
||||
doom-modules-dirs)
|
||||
:type 'dirs
|
||||
:mindepth 1
|
||||
:depth 1)
|
||||
(cl-loop for plist being the hash-values of (doom-modules)
|
||||
(mapcar (lambda (m) (doom-module-locate-path (car m) (cdr m)))
|
||||
(delete-dups
|
||||
(doom-files-in (if (listp module-dirs)
|
||||
module-dirs
|
||||
doom-modules-dirs)
|
||||
:map #'doom-module-from-path
|
||||
:type 'dirs
|
||||
:mindepth 1
|
||||
:depth 1)))
|
||||
(cl-loop for plist being the hash-values of doom-modules
|
||||
collect (plist-get plist :path)))
|
||||
nil))
|
||||
|
||||
(defun doom-modules (&optional refresh-p)
|
||||
(defun doom-module-mplist-map (fn mplist)
|
||||
"Apply FN to each module in MPLIST."
|
||||
(let ((mplist (copy-sequence mplist))
|
||||
(inhibit-message doom-inhibit-module-warnings)
|
||||
obsolete
|
||||
results
|
||||
category m)
|
||||
(while mplist
|
||||
(setq m (pop mplist))
|
||||
(cond ((keywordp m)
|
||||
(setq category m
|
||||
obsolete (assq m doom-obsolete-modules)))
|
||||
((null category)
|
||||
(error "No module category specified for %s" m))
|
||||
((and (listp m) (keywordp (car m)))
|
||||
(pcase (car m)
|
||||
(:cond
|
||||
(cl-loop for (cond . mods) in (cdr m)
|
||||
if (eval cond t)
|
||||
return (prependq! mplist mods)))
|
||||
(:if (if (eval (cadr m) t)
|
||||
(push (caddr m) mplist)
|
||||
(prependq! mplist (cdddr m))))
|
||||
(test (if (or (eval (cadr m) t)
|
||||
(eq test :unless))
|
||||
(prependq! mplist (cddr m))))))
|
||||
((catch 'doom-modules
|
||||
(let* ((module (if (listp m) (car m) m))
|
||||
(flags (if (listp m) (cdr m))))
|
||||
(when-let (new (assq module obsolete))
|
||||
(let ((newkeys (cdr new)))
|
||||
(if (null newkeys)
|
||||
(message "WARNING %s module was removed" key)
|
||||
(if (cdr newkeys)
|
||||
(message "WARNING %s module was removed and split into the %s modules"
|
||||
(list category module) (mapconcat #'prin1-to-string newkeys ", "))
|
||||
(message "WARNING %s module was moved to %s"
|
||||
(list category module) (car newkeys)))
|
||||
(push category mplist)
|
||||
(dolist (key newkeys)
|
||||
(push (if flags
|
||||
(nconc (cdr key) flags)
|
||||
(cdr key))
|
||||
mplist)
|
||||
(push (car key) mplist))
|
||||
(throw 'doom-modules t))))
|
||||
(push (funcall fn category module
|
||||
:flags (if (listp m) (cdr m))
|
||||
:path (doom-module-locate-path category module))
|
||||
results))))))
|
||||
(unless doom-interactive-p
|
||||
(setq doom-inhibit-module-warnings t))
|
||||
(nreverse results)))
|
||||
|
||||
(defun doom-module-list (&optional all-p)
|
||||
"Minimally initialize `doom-modules' (a hash table) and return it.
|
||||
This value is cached. If REFRESH-P, then don't use the cached value."
|
||||
(or (unless refresh-p doom-modules)
|
||||
(let (doom-interactive-mode
|
||||
doom-modules
|
||||
doom-init-modules-p)
|
||||
(load! "init" doom-private-dir t)
|
||||
(or doom-modules
|
||||
(make-hash-table :test 'equal
|
||||
:size 20
|
||||
:rehash-threshold 1.0)))))
|
||||
(if all-p
|
||||
(cl-loop for path in (cdr (doom-module-load-path 'all))
|
||||
collect (doom-module-from-path path))
|
||||
doom-modules))
|
||||
|
||||
|
||||
;;
|
||||
;;; Use-package modifications
|
||||
|
||||
(eval-and-compile
|
||||
(autoload 'use-package "use-package-core" nil nil t)
|
||||
|
||||
(setq use-package-compute-statistics doom-debug-mode
|
||||
use-package-verbose doom-debug-mode
|
||||
use-package-minimum-reported-time (if doom-debug-mode 0 0.1)
|
||||
use-package-expand-minimally doom-interactive-mode))
|
||||
|
||||
(defvar doom--deferred-packages-alist '(t))
|
||||
|
||||
(autoload 'use-package "use-package-core" nil nil t)
|
||||
|
||||
(setq use-package-compute-statistics doom-debug-p
|
||||
use-package-verbose doom-debug-p
|
||||
use-package-minimum-reported-time (if doom-debug-p 0 0.1)
|
||||
use-package-expand-minimally doom-interactive-p)
|
||||
|
||||
;; A common mistake for new users is that they inadvertantly install their
|
||||
;; packages with package.el, by copying over old `use-package' declarations with
|
||||
;; an :ensure t property. Doom doesn't use package.el, so this will throw an
|
||||
;; error that will confuse beginners, so we disable `:ensure'.
|
||||
(setq use-package-ensure-function #'ignore)
|
||||
;; ...On the other hand, if the user has loaded `package', then we should assume
|
||||
;; they know what they're doing and restore the old behavior:
|
||||
(add-transient-hook! 'package-initialize
|
||||
(when (eq use-package-ensure-function #'ignore)
|
||||
(setq use-package-ensure-function #'use-package-ensure-elpa)))
|
||||
|
||||
(with-eval-after-load 'use-package-core
|
||||
;; Macros are already fontified, no need for this
|
||||
;; `use-package' adds syntax highlighting for the `use-package' macro, but
|
||||
;; Emacs 26+ already highlights macros, so it's redundant.
|
||||
(font-lock-remove-keywords 'emacs-lisp-mode use-package-font-lock-keywords)
|
||||
|
||||
;; We define :minor and :magic-minor from the `auto-minor-mode' package here
|
||||
@@ -266,6 +355,17 @@ This value is cached. If REFRESH-P, then don't use the cached value."
|
||||
(defun use-package-handler/:magic-minor (name _ arg rest state)
|
||||
(use-package-handle-mode name 'auto-minor-mode-magic-alist arg rest state))
|
||||
|
||||
;; HACK Fix `:load-path' so it resolves relative paths to the containing file,
|
||||
;; rather than `user-emacs-directory'. This is a done as a convenience
|
||||
;; for users, wanting to specify a local directory.
|
||||
(defadvice! doom--resolve-load-path-from-containg-file-a (orig-fn label arg &optional recursed)
|
||||
"Resolve :load-path from the current directory."
|
||||
:around #'use-package-normalize-paths
|
||||
;; `use-package-normalize-paths' resolves paths relative to
|
||||
;; `user-emacs-directory', so we change that.
|
||||
(let ((user-emacs-directory (if (stringp arg) (dir!))))
|
||||
(funcall orig-fn label arg recursed)))
|
||||
|
||||
;; Adds two keywords to `use-package' to expand its lazy-loading capabilities:
|
||||
;;
|
||||
;; :after-call SYMBOL|LIST
|
||||
@@ -360,62 +460,16 @@ The overall load order of Doom is as follows:
|
||||
Module load order is determined by your `doom!' block. See `doom-modules-dirs'
|
||||
for a list of all recognized module trees. Order defines precedence (from most
|
||||
to least)."
|
||||
`(let ((modules
|
||||
,@(if (keywordp (car modules))
|
||||
(list (list 'quote modules))
|
||||
modules)))
|
||||
(unless doom-modules
|
||||
(setq doom-modules
|
||||
(make-hash-table :test 'equal
|
||||
:size (if modules (length modules) 150)
|
||||
:rehash-threshold 1.0)))
|
||||
(let ((inhibit-message doom-inhibit-module-warnings)
|
||||
obsolete category m)
|
||||
(while modules
|
||||
(setq m (pop modules))
|
||||
(cond ((keywordp m)
|
||||
(setq category m
|
||||
obsolete (assq m doom-obsolete-modules)))
|
||||
((not category)
|
||||
(error "No module category specified for %s" m))
|
||||
((and (listp m) (keywordp (car m)))
|
||||
(pcase (car m)
|
||||
(:cond
|
||||
(cl-loop for (cond . mods) in (cdr m)
|
||||
if (eval cond t)
|
||||
return (prependq! modules mods)))
|
||||
(:if (if (eval (cadr m) t)
|
||||
(push (caddr m) modules)
|
||||
(prependq! modules (cdddr m))))
|
||||
(fn (if (or (eval (cadr m) t)
|
||||
(eq fn :unless))
|
||||
(prependq! modules (cddr m))))))
|
||||
((catch 'doom-modules
|
||||
(let* ((module (if (listp m) (car m) m))
|
||||
(flags (if (listp m) (cdr m))))
|
||||
(when-let (new (assq module obsolete))
|
||||
(let ((newkeys (cdr new)))
|
||||
(if (null newkeys)
|
||||
(message "WARNING %s module was removed" key)
|
||||
(if (cdr newkeys)
|
||||
(message "WARNING %s module was removed and split into the %s modules"
|
||||
(list category module) (mapconcat #'prin1-to-string newkeys ", "))
|
||||
(message "WARNING %s module was moved to %s"
|
||||
(list category module) (car newkeys)))
|
||||
(push category modules)
|
||||
(dolist (key newkeys)
|
||||
(push (if flags
|
||||
(nconc (cdr key) flags)
|
||||
(cdr key))
|
||||
modules)
|
||||
(push (car key) modules))
|
||||
(throw 'doom-modules t))))
|
||||
(if-let (path (doom-module-locate-path category module))
|
||||
(doom-module-set category module :flags flags :path path)
|
||||
(message "WARNING Couldn't find the %s %s module" category module)))))))
|
||||
(unless doom-interactive-mode
|
||||
(setq doom-inhibit-module-warnings t))
|
||||
doom-modules)))
|
||||
`(unless doom-interactive-p
|
||||
(doom-module-mplist-map
|
||||
(lambda (category module &rest plist)
|
||||
(if (plist-get plist :path)
|
||||
(apply #'doom-module-set category module plist)
|
||||
(message "WARNING Couldn't find the %s %s module" category module)))
|
||||
,@(if (keywordp (car modules))
|
||||
(list (list 'quote modules))
|
||||
modules))
|
||||
doom-modules))
|
||||
|
||||
(defvar doom-disabled-packages)
|
||||
(defmacro use-package! (name &rest plist)
|
||||
@@ -481,39 +535,6 @@ WARNINGS:
|
||||
(lambda () ,@body)
|
||||
'append)))
|
||||
|
||||
(defmacro require! (category module &rest flags)
|
||||
"Loads the CATEGORY MODULE module with FLAGS.
|
||||
|
||||
CATEGORY is a keyword, MODULE is a symbol and FLAGS are symbols.
|
||||
|
||||
(require! :lang php +lsp)
|
||||
|
||||
This is for testing and internal use. This is not the correct way to enable a
|
||||
module."
|
||||
`(let ((doom-modules (or ,doom-modules (doom-modules)))
|
||||
(module-path (doom-module-locate-path ,category ',module)))
|
||||
(doom-module-set
|
||||
,category ',module
|
||||
(let ((plist (doom-module-get ,category ',module)))
|
||||
,(when flags
|
||||
`(plist-put plist :flags `,flags))
|
||||
(unless (plist-member plist :path)
|
||||
(plist-put plist :path ,(doom-module-locate-path category module)))
|
||||
plist))
|
||||
(if (directory-name-p module-path)
|
||||
(condition-case-unless-debug ex
|
||||
(let ((doom--current-module ',(cons category module))
|
||||
(doom--current-flags ',flags))
|
||||
(load! "init" module-path :noerror)
|
||||
(load! "config" module-path :noerror))
|
||||
('error
|
||||
(lwarn 'doom-modules :error
|
||||
"%s in '%s %s' -> %s"
|
||||
(car ex) ,category ',module
|
||||
(error-message-string ex))))
|
||||
(warn 'doom-modules :warning "Couldn't find module '%s %s'"
|
||||
,category ',module))))
|
||||
|
||||
(defmacro featurep! (category &optional module flag)
|
||||
"Returns t if CATEGORY MODULE is enabled.
|
||||
|
||||
@@ -522,82 +543,20 @@ If FLAG is provided, returns t if CATEGORY MODULE has FLAG enabled.
|
||||
(featurep! :config default)
|
||||
|
||||
Module FLAGs are set in your config's `doom!' block, typically in
|
||||
~/.emacs.d/init.el. Like so:
|
||||
~/.doom.d/init.el. Like so:
|
||||
|
||||
:config (default +flag1 -flag2)
|
||||
|
||||
CATEGORY and MODULE can be omitted When this macro is used from inside a module
|
||||
(except your DOOMDIR, which is a special moduel). e.g. (featurep! +flag)"
|
||||
(except your DOOMDIR, which is a special module). e.g. (featurep! +flag)"
|
||||
(and (cond (flag (memq flag (doom-module-get category module :flags)))
|
||||
(module (doom-module-p category module))
|
||||
(doom--current-flags (memq category doom--current-flags))
|
||||
((let ((module (doom-module-from-path)))
|
||||
(unless module
|
||||
(error "(featurep! %s %s %s) couldn't figure out what module it was called from (in %s)"
|
||||
category module flag (file!)))
|
||||
(memq category (doom-module-get (car module) (cdr module) :flags)))))
|
||||
((if-let (module (doom-module-from-path))
|
||||
(memq category (doom-module-get (car module) (cdr module) :flags))
|
||||
(error "(featurep! %s %s %s) couldn't figure out what module it was called from (in %s)"
|
||||
category module flag (file!)))))
|
||||
t))
|
||||
|
||||
(defmacro after! (package &rest body)
|
||||
"Evaluate BODY after PACKAGE have loaded.
|
||||
|
||||
PACKAGE is a symbol or list of them. These are package names, not modes,
|
||||
functions or variables. It can be:
|
||||
|
||||
- An unquoted package symbol (the name of a package)
|
||||
(after! helm BODY...)
|
||||
- An unquoted list of package symbols (i.e. BODY is evaluated once both magit
|
||||
and git-gutter have loaded)
|
||||
(after! (magit git-gutter) BODY...)
|
||||
- An unquoted, nested list of compound package lists, using any combination of
|
||||
:or/:any and :and/:all
|
||||
(after! (:or package-a package-b ...) BODY...)
|
||||
(after! (:and package-a package-b ...) BODY...)
|
||||
(after! (:and package-a (:or package-b package-c) ...) BODY...)
|
||||
Without :or/:any/:and/:all, :and/:all are implied.
|
||||
|
||||
This is a wrapper around `eval-after-load' that:
|
||||
|
||||
1. Suppresses warnings for disabled packages at compile-time
|
||||
2. No-ops for package that are disabled by the user (via `package!')
|
||||
3. Supports compound package statements (see below)
|
||||
4. Prevents eager expansion pulling in autoloaded macros all at once"
|
||||
(declare (indent defun) (debug t))
|
||||
(if (symbolp package)
|
||||
(unless (memq package (bound-and-true-p doom-disabled-packages))
|
||||
(list (if (or (not (bound-and-true-p byte-compile-current-file))
|
||||
(require package nil 'noerror))
|
||||
#'progn
|
||||
#'with-no-warnings)
|
||||
(let ((body (macroexp-progn body)))
|
||||
`(if (featurep ',package)
|
||||
,body
|
||||
;; We intentionally avoid `with-eval-after-load' to prevent
|
||||
;; eager macro expansion from pulling (or failing to pull) in
|
||||
;; autoloaded macros/packages.
|
||||
(eval-after-load ',package ',body)))))
|
||||
(let ((p (car package)))
|
||||
(cond ((not (keywordp p))
|
||||
`(after! (:and ,@package) ,@body))
|
||||
((memq p '(:or :any))
|
||||
(macroexp-progn
|
||||
(cl-loop for next in (cdr package)
|
||||
collect `(after! ,next ,@body))))
|
||||
((memq p '(:and :all))
|
||||
(dolist (next (cdr package))
|
||||
(setq body `((after! ,next ,@body))))
|
||||
(car body))))))
|
||||
|
||||
;; DEPRECATED
|
||||
(defmacro def-package! (&rest args)
|
||||
(make-obsolete 'def-package! 'use-package! "2.0.9")
|
||||
(message "`def-package!' was renamed to `use-package!'; use that instead.")
|
||||
`(use-package! ,@args))
|
||||
|
||||
(defmacro def-package-hook! (&rest args)
|
||||
(make-obsolete 'def-package-hook! 'use-package-hook! "2.0.9")
|
||||
(message "`def-package-hook!' was renamed to `use-package-hook!'; use that instead.")
|
||||
`(use-package-hook! ,@args))
|
||||
|
||||
(provide 'core-modules)
|
||||
;;; core-modules.el ends here
|
||||
|
||||
@@ -1,27 +1,25 @@
|
||||
;;; core/core-packages.el -*- lexical-binding: t; -*-
|
||||
|
||||
;; Emacs package management is opinionated, and so is Doom. Doom uses `straight'
|
||||
;; to create a declarative, lazy-loaded and optionally rolling-release package
|
||||
;; to create a declarative, lazy-loaded and (nominally) reproducible package
|
||||
;; management system. We use `straight' over `package' because the latter is
|
||||
;; tempermental. ELPA sources suffer downtime occasionally, and often fail at
|
||||
;; building some packages when GNU Tar is unavailable (e.g. MacOS users start
|
||||
;; with BSD tar). There are also known gnutls errors in the current stable
|
||||
;; release of Emacs (26.x) which bork TLS handshakes with ELPA repos (mainly
|
||||
;; gnu.elpa.org). See https://debbugs.gnu.org/cgi/bugreport.cgi?bug=3434.
|
||||
;; tempermental. ELPA sources suffer downtime occasionally and often fail to
|
||||
;; build packages when GNU Tar is unavailable (e.g. MacOS users start with BSD
|
||||
;; tar). Known gnutls errors plague the current stable release of Emacs (26.x)
|
||||
;; which bork TLS handshakes with ELPA repos (mainly gnu.elpa.org). See
|
||||
;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=3434.
|
||||
;;
|
||||
;; What's worse, you can only get the latest version of packages through ELPA.
|
||||
;; In an ecosystem that is constantly changing, this is more frustrating than
|
||||
;; convenient. Straight (and Doom) can do rolling release, but it is optional
|
||||
;; (and will eventually be opt-in).
|
||||
;; convenient. Straight (and Doom) can do rolling release, but it is opt-in.
|
||||
;;
|
||||
;; ANyhow, interacting with this package management system is done through the
|
||||
;; bin/doom script included with Doom Emacs. You'll find more about it by
|
||||
;; running 'doom help' (I highly recommend you add it to your PATH), but here
|
||||
;; are the highlights:
|
||||
;; Interacting with this package management system is done through Doom's
|
||||
;; bin/doom script. Find out more about it by running 'doom help' (I highly
|
||||
;; recommend you add the script to your PATH). Here are some highlights:
|
||||
;;
|
||||
;; + `bin/doom install`: a wizard that guides you through setting up Doom and
|
||||
;; your private config for the first time.
|
||||
;; + `bin/doom refresh`: your go-to command for making sure Doom is in optimal
|
||||
;; + `bin/doom sync`: your go-to command for making sure Doom is in optimal
|
||||
;; condition. It ensures all unneeded packages are removed, all needed ones
|
||||
;; are installed, and all metadata associated with them is generated.
|
||||
;; + `bin/doom upgrade`: upgrades Doom Emacs and your packages to the latest
|
||||
@@ -32,48 +30,31 @@
|
||||
;; `doom-core-dir'. These contain `package!' declarations that tell DOOM what
|
||||
;; plugins to install and where from.
|
||||
;;
|
||||
;; All that said, you can still use package.el's commands, but 'bin/doom
|
||||
;; refresh' will purge ELPA packages.
|
||||
|
||||
(defvar doom-init-packages-p nil
|
||||
"If non-nil, Doom's package management system has been initialized.")
|
||||
;; All that said, you can still use package.el's commands, but 'bin/doom sync'
|
||||
;; will purge ELPA packages.
|
||||
|
||||
(defvar doom-packages ()
|
||||
"A list of enabled packages. Each element is a sublist, whose CAR is the
|
||||
package's name as a symbol, and whose CDR is the plist supplied to its
|
||||
`package!' declaration. Set by `doom-initialize-packages'.")
|
||||
|
||||
(defvar doom-core-packages '(straight use-package async gcmh)
|
||||
"A list of packages that must be installed (and will be auto-installed if
|
||||
missing) and shouldn't be deleted.")
|
||||
|
||||
(defvar doom-core-package-sources
|
||||
'((org-elpa :local-repo nil)
|
||||
(melpa
|
||||
:type git :host github
|
||||
:repo "melpa/melpa"
|
||||
:no-build t)
|
||||
(gnu-elpa-mirror
|
||||
:type git :host github
|
||||
:repo "emacs-straight/gnu-elpa-mirror"
|
||||
:no-build t)
|
||||
(emacsmirror-mirror
|
||||
:type git :host github
|
||||
:repo "emacs-straight/emacsmirror-mirror"
|
||||
:no-build t))
|
||||
"A list of recipes for straight's recipe repos.")
|
||||
|
||||
(defvar doom-disabled-packages ()
|
||||
"A list of packages that should be ignored by `use-package!' and `after!'.")
|
||||
|
||||
(defvar doom-packages-file "packages"
|
||||
"The basename of packages file for modules.
|
||||
|
||||
Package files are read whenever Doom's package manager wants a manifest of all
|
||||
desired packages. They are rarely read in interactive sessions (unless the user
|
||||
uses a straight or package.el command directly).")
|
||||
|
||||
|
||||
;;
|
||||
;;; Package managers
|
||||
;;; package.el
|
||||
|
||||
;; Ensure that, if we do need package.el, it is configured correctly. You really
|
||||
;; shouldn't be using it, but it may be convenient for quick package testing.
|
||||
(setq package--init-file-ensured t
|
||||
package-enable-at-startup nil
|
||||
(setq package-enable-at-startup nil
|
||||
package-user-dir (concat doom-local-dir "elpa/")
|
||||
package-gnupghome-dir (expand-file-name "gpg" package-user-dir)
|
||||
;; I omit Marmalade because its packages are manually submitted rather
|
||||
@@ -84,175 +65,363 @@ missing) and shouldn't be deleted.")
|
||||
("melpa" . ,(concat proto "://melpa.org/packages/"))
|
||||
("org" . ,(concat proto "://orgmode.org/elpa/")))))
|
||||
|
||||
;; Don't save `package-selected-packages' to `custom-file'
|
||||
(defadvice! doom--package-inhibit-custom-file-a (&optional value)
|
||||
:override #'package--save-selected-packages
|
||||
(if value (setq package-selected-packages value)))
|
||||
;; package.el has no business modifying the user's init.el
|
||||
(advice-add #'package--ensure-init-file :override #'ignore)
|
||||
|
||||
;; Refresh package.el the first time you call `package-install'
|
||||
;; Refresh package.el the first time you call `package-install', so it can still
|
||||
;; be used (e.g. to temporarily test packages). Remember to run 'doom sync' to
|
||||
;; purge them; they can conflict with packages installed via straight!
|
||||
(add-transient-hook! 'package-install (package-refresh-contents))
|
||||
|
||||
;;; straight
|
||||
|
||||
;;
|
||||
;;; Straight
|
||||
|
||||
(setq straight-base-dir doom-local-dir
|
||||
straight-repository-branch "develop"
|
||||
straight-cache-autoloads nil ; we already do this, and better.
|
||||
;; Doom doesn't encourage you to modify packages in place. Disabling this
|
||||
;; makes 'doom refresh' instant (once everything set up), which is much
|
||||
;; nicer UX than the several seconds modification checks.
|
||||
;; makes 'doom sync' instant (once everything set up), which is much nicer
|
||||
;; UX than the several seconds modification checks.
|
||||
straight-check-for-modifications nil
|
||||
;; We handle package.el ourselves (and a little more comprehensively)
|
||||
straight-enable-package-integration nil
|
||||
;; Before switching to straight, `doom-local-dir' would average out at
|
||||
;; around 100mb with half Doom's modules at ~230 packages. Afterwards, at
|
||||
;; around 1gb. With shallow cloning, that is reduced to ~400mb. This
|
||||
;; imposes an issue with packages that require their git history for
|
||||
;; certain things to work (like magit and org), but we can deal with that
|
||||
;; when we cross that bridge.
|
||||
;; around 1gb. With shallow cloning, that is reduced to ~400mb. This has
|
||||
;; no affect on packages that are pinned, however (run 'doom purge' to
|
||||
;; compact those after-the-fact). Some packages break when shallow cloned
|
||||
;; (like magit and org), but we'll deal with that elsewhere.
|
||||
straight-vc-git-default-clone-depth 1
|
||||
;; Straight's own emacsmirror mirror is a little smaller and faster.
|
||||
straight-recipes-emacsmirror-use-mirror t
|
||||
;; Prefix declarations are unneeded bulk added to our autoloads file. Best
|
||||
;; we just don't have to deal with them at all.
|
||||
autoload-compute-prefixes nil)
|
||||
;; we don't have to deal with them at all.
|
||||
autoload-compute-prefixes nil
|
||||
;; We handle it ourselves
|
||||
straight-fix-org nil)
|
||||
|
||||
(defun doom--finalize-straight ()
|
||||
(mapc #'funcall (delq nil (mapcar #'cdr straight--transaction-alist)))
|
||||
(setq straight--transaction-alist nil))
|
||||
|
||||
;;; Getting straight to behave in batch mode
|
||||
(when noninteractive
|
||||
;; HACK Remove dired & magit options from prompt, since they're inaccessible
|
||||
;; in noninteractive sessions.
|
||||
(advice-add #'straight-vc-git--popup-raw :override #'straight--popup-raw))
|
||||
|
||||
;; HACK Replace GUI popup prompts (which hang indefinitely in tty Emacs) with
|
||||
;; simple prompts.
|
||||
(defadvice! doom--straight-fallback-to-y-or-n-prompt-a (orig-fn &optional prompt)
|
||||
:around #'straight-are-you-sure
|
||||
(if noninteractive
|
||||
(y-or-n-p (format! "%s" (or prompt "")))
|
||||
(funcall orig-fn prompt)))
|
||||
|
||||
(defadvice! doom--straight-fallback-to-tty-prompt-a (orig-fn prompt actions)
|
||||
"Modifies straight to prompt on the terminal when in noninteractive sessions."
|
||||
:around #'straight--popup-raw
|
||||
(if (not noninteractive)
|
||||
(funcall orig-fn prompt actions)
|
||||
;; We can't intercept C-g, so no point displaying any options for this key
|
||||
;; Just use C-c
|
||||
(delq! "C-g" actions 'assoc)
|
||||
;; HACK These are associated with opening dired or magit, which isn't
|
||||
;; possible in tty Emacs, so...
|
||||
(delq! "e" actions 'assoc)
|
||||
(delq! "g" actions 'assoc)
|
||||
(let ((options (list (lambda ()
|
||||
(let ((doom-format-indent 0))
|
||||
(terpri)
|
||||
(print! (error "Aborted")))
|
||||
(kill-emacs)))))
|
||||
(print! (start "%s") (red prompt))
|
||||
(terpri)
|
||||
(print-group!
|
||||
(print-group!
|
||||
(print! " 1) Abort")
|
||||
(dolist (action actions)
|
||||
(cl-destructuring-bind (_key desc func) action
|
||||
(when desc
|
||||
(push func options)
|
||||
(print! "%2s) %s" (length options) desc)))))
|
||||
(terpri)
|
||||
(let ((options (nreverse options))
|
||||
answer fn)
|
||||
(while
|
||||
(not
|
||||
(setq
|
||||
fn (ignore-errors
|
||||
(nth (1- (setq answer
|
||||
(read-number
|
||||
(format! "How to proceed? (%s) "
|
||||
(mapconcat #'number-to-string
|
||||
(number-sequence 1 (length options))
|
||||
", ")))))
|
||||
options))))
|
||||
(print! (warn "%s is not a valid answer, try again.") answer))
|
||||
(funcall fn))))))
|
||||
(defadvice! doom--read-pinned-packages-a (orig-fn &rest args)
|
||||
"Read `:pin's in `doom-packages' on top of straight's lockfiles."
|
||||
:around #'straight--lockfile-read-all
|
||||
(append (apply orig-fn args) ; lockfiles still take priority
|
||||
(doom-package-pinned-list)))
|
||||
|
||||
|
||||
;;
|
||||
;;; Bootstrapper
|
||||
;;; Bootstrappers
|
||||
|
||||
(defun doom--ensure-straight (recipe pin)
|
||||
(let ((repo-dir (doom-path straight-base-dir "straight/repos/straight.el"))
|
||||
(repo-url (concat "http" (if gnutls-verify-error "s")
|
||||
"://github.com/"
|
||||
(or (plist-get recipe :repo) "raxod502/straight.el")))
|
||||
(branch (or (plist-get recipe :branch) straight-repository-branch))
|
||||
(call (if doom-debug-p #'doom-exec-process #'doom-call-process)))
|
||||
(unless (file-directory-p repo-dir)
|
||||
(message "Installing straight...")
|
||||
(cond
|
||||
((eq straight-vc-git-default-clone-depth 'full)
|
||||
(funcall call "git" "clone" "--origin" "origin" repo-url repo-dir))
|
||||
((null pin)
|
||||
(funcall call "git" "clone" "--origin" "origin" repo-url repo-dir
|
||||
"--depth" (number-to-string straight-vc-git-default-clone-depth)
|
||||
"--branch" straight-repository-branch))
|
||||
((integerp straight-vc-git-default-clone-depth)
|
||||
(make-directory repo-dir t)
|
||||
(let ((default-directory repo-dir))
|
||||
(funcall call "git" "init")
|
||||
(funcall call "git" "checkout" "-b" straight-repository-branch)
|
||||
(funcall call "git" "remote" "add" "origin" repo-url)
|
||||
(funcall call "git" "fetch" "origin" pin
|
||||
"--depth" (number-to-string straight-vc-git-default-clone-depth))
|
||||
(funcall call "git" "checkout" "--detach" pin)))))
|
||||
(require 'straight (concat repo-dir "/straight.el"))
|
||||
(doom-log "Initializing recipes")
|
||||
(with-temp-buffer
|
||||
(insert-file-contents (doom-path repo-dir "bootstrap.el"))
|
||||
;; Don't install straight for us -- we've already done that -- only set
|
||||
;; up its recipe repos for us.
|
||||
(eval-region (search-forward "(require 'straight)")
|
||||
(point-max)))))
|
||||
|
||||
(defun doom--ensure-core-packages (packages)
|
||||
(doom-log "Installing core packages")
|
||||
(dolist (package packages)
|
||||
(let ((name (car package)))
|
||||
(when-let (recipe (plist-get (cdr package) :recipe))
|
||||
(straight-override-recipe (cons name recipe)))
|
||||
(straight-use-package name))))
|
||||
|
||||
(defun doom-initialize-core-packages (&optional force-p)
|
||||
"Ensure `straight' is installed and was compiled with this version of Emacs."
|
||||
(when (or force-p (null (bound-and-true-p straight-recipe-repositories)))
|
||||
(doom-log "Initializing straight")
|
||||
(let ((packages (doom-package-list nil 'core)))
|
||||
(cl-destructuring-bind (&key recipe pin &allow-other-keys)
|
||||
(alist-get 'straight packages)
|
||||
(doom--ensure-straight recipe pin))
|
||||
(doom--ensure-core-packages packages))))
|
||||
|
||||
(defun doom-initialize-packages (&optional force-p)
|
||||
"Ensures that Doom's package system and straight.el are initialized.
|
||||
"Process all packages, essential and otherwise, if they haven't already been.
|
||||
|
||||
If FORCE-P is non-nil, do it anyway.
|
||||
|
||||
This ensure `doom-packages' is populated, if isn't aren't already. Use this
|
||||
before any of straight's or Doom's package management's API to ensure all the
|
||||
necessary package metadata is initialized and available for them."
|
||||
(unless doom-init-packages-p
|
||||
(setq force-p t))
|
||||
This ensures `doom-packages' is populated and `straight' recipes are properly
|
||||
processed."
|
||||
(doom-initialize-core-packages force-p)
|
||||
(when (or force-p (not (bound-and-true-p package--initialized)))
|
||||
(doom-log "Initializing package.el")
|
||||
(require 'package)
|
||||
(package-initialize))
|
||||
(when (or force-p (not doom-packages))
|
||||
(doom-log "Initializing straight")
|
||||
(setq doom-init-packages-p t)
|
||||
(unless (fboundp 'straight--reset-caches)
|
||||
(doom-ensure-straight)
|
||||
(require 'straight))
|
||||
(straight--reset-caches)
|
||||
(setq straight-recipe-repositories nil)
|
||||
(mapc #'straight-use-recipes doom-core-package-sources)
|
||||
(straight-register-package
|
||||
`(straight :type git :host github
|
||||
:repo ,(format "%s/straight.el" straight-repository-user)
|
||||
:files ("straight*.el")
|
||||
:branch ,straight-repository-branch
|
||||
:no-byte-compile t))
|
||||
(mapc #'straight-use-package doom-core-packages)
|
||||
(doom-log "Initializing doom-packages")
|
||||
(setq doom-disabled-packages nil
|
||||
doom-packages (doom-package-list))
|
||||
(cl-loop for (pkg . plist) in doom-packages
|
||||
if (plist-get plist :disable)
|
||||
do (cl-pushnew pkg doom-disabled-packages)
|
||||
else if (not (plist-get plist :ignore))
|
||||
do (with-demoted-errors "Package error: %s"
|
||||
(straight-register-package
|
||||
(if-let (recipe (plist-get plist :recipe))
|
||||
(cons pkg recipe)
|
||||
pkg))))
|
||||
(unless doom-interactive-mode
|
||||
(add-hook 'kill-emacs-hook #'doom--finalize-straight))))
|
||||
(package-initialize)
|
||||
(unless package--initialized
|
||||
(error "Failed to initialize package.el")))
|
||||
(when (or force-p (null doom-packages))
|
||||
(doom-log "Initializing straight.el")
|
||||
(or (setq doom-disabled-packages nil
|
||||
doom-packages (doom-package-list))
|
||||
(error "Failed to read any packages"))
|
||||
(dolist (package doom-packages)
|
||||
(cl-destructuring-bind
|
||||
(name &key recipe disable ignore &allow-other-keys) package
|
||||
(unless ignore
|
||||
(if disable
|
||||
(cl-pushnew name doom-disabled-packages)
|
||||
(when recipe
|
||||
(straight-override-recipe (cons name recipe)))
|
||||
(straight-register-package name)))))))
|
||||
|
||||
(defun doom-ensure-straight ()
|
||||
"Ensure `straight' is installed and was compiled with this version of Emacs."
|
||||
(defvar bootstrap-version)
|
||||
(let* (;; Force straight to install into ~/.emacs.d/.local/straight instead of
|
||||
;; ~/.emacs.d/straight by pretending `doom-local-dir' is our .emacs.d.
|
||||
(user-emacs-directory straight-base-dir)
|
||||
(bootstrap-file (doom-path straight-base-dir "straight/repos/straight.el/straight.el"))
|
||||
(bootstrap-version 5))
|
||||
(make-directory (doom-path straight-base-dir "straight/build") 'parents)
|
||||
(unless (featurep 'straight)
|
||||
(unless (or (require 'straight nil t)
|
||||
(file-readable-p bootstrap-file))
|
||||
(with-current-buffer
|
||||
(url-retrieve-synchronously
|
||||
(format "https://raw.githubusercontent.com/raxod502/straight.el/%s/install.el"
|
||||
straight-repository-branch)
|
||||
'silent 'inhibit-cookies)
|
||||
(goto-char (point-max))
|
||||
(eval-print-last-sexp)))
|
||||
(load bootstrap-file nil t))))
|
||||
|
||||
;;
|
||||
;;; Package management API
|
||||
|
||||
(defun doom-package-get (package &optional prop nil-value)
|
||||
"Returns PACKAGE's `package!' recipe from `doom-packages'."
|
||||
(let ((plist (cdr (assq package doom-packages))))
|
||||
(if prop
|
||||
(if (plist-member plist prop)
|
||||
(plist-get plist prop)
|
||||
nil-value)
|
||||
plist)))
|
||||
|
||||
(defun doom-package-set (package prop value)
|
||||
"Set PROPERTY in PACKAGE's recipe to VALUE."
|
||||
(setf (alist-get package doom-packages)
|
||||
(plist-put (alist-get package doom-packages)
|
||||
prop value)))
|
||||
|
||||
(defun doom-package-recipe (package &optional prop nil-value)
|
||||
"Returns the `straight' recipe PACKAGE was registered with."
|
||||
(let ((plist (gethash (symbol-name package) straight--recipe-cache)))
|
||||
(if prop
|
||||
(if (plist-member plist prop)
|
||||
(plist-get plist prop)
|
||||
nil-value)
|
||||
plist)))
|
||||
|
||||
(defun doom-package-recipe-repo (package)
|
||||
"Resolve and return PACKAGE's (symbol) local-repo property."
|
||||
(if-let* ((recipe (cdr (straight-recipes-retrieve package)))
|
||||
(repo (straight-vc-local-repo-name recipe)))
|
||||
repo
|
||||
(symbol-name package)))
|
||||
|
||||
(defun doom-package-build-recipe (package &optional prop nil-value)
|
||||
"Returns the `straight' recipe PACKAGE was installed with."
|
||||
(let ((plist (nth 2 (gethash (symbol-name package) straight--build-cache))))
|
||||
(if prop
|
||||
(if (plist-member plist prop)
|
||||
(plist-get plist prop)
|
||||
nil-value)
|
||||
plist)))
|
||||
|
||||
(defun doom-package-build-time (package)
|
||||
"TODO"
|
||||
(car (gethash (symbol-name package) straight--build-cache)))
|
||||
|
||||
(defun doom-package-dependencies (package &optional recursive _noerror)
|
||||
"Return a list of dependencies for a package."
|
||||
(let ((deps (nth 1 (gethash (symbol-name package) straight--build-cache))))
|
||||
(if recursive
|
||||
(append deps (mapcan (lambda (dep) (doom-package-dependencies dep t t))
|
||||
(copy-sequence deps)))
|
||||
(copy-sequence deps))))
|
||||
|
||||
(defun doom-package-depending-on (package &optional noerror)
|
||||
"Return a list of packages that depend on the package named NAME."
|
||||
(cl-check-type name symbol)
|
||||
;; can't get dependencies for built-in packages
|
||||
(unless (or (doom-package-build-recipe name)
|
||||
noerror)
|
||||
(error "Couldn't find %s, is it installed?" name))
|
||||
(cl-loop for pkg in (hash-table-keys straight--build-cache)
|
||||
for deps = (doom-package-dependencies pkg)
|
||||
if (memq package deps)
|
||||
collect pkg
|
||||
and append (doom-package-depending-on pkg t)))
|
||||
|
||||
|
||||
;;; Predicate functions
|
||||
(defun doom-package-built-in-p (package)
|
||||
"Return non-nil if PACKAGE (a symbol) is built-in."
|
||||
(eq (doom-package-build-recipe package :type)
|
||||
'built-in))
|
||||
|
||||
(defun doom-package-installed-p (package)
|
||||
"Return non-nil if PACKAGE (a symbol) is installed."
|
||||
(file-directory-p (straight--build-dir (symbol-name package))))
|
||||
|
||||
(defun doom-package-is-type-p (package type)
|
||||
"TODO"
|
||||
(memq type (doom-enlist (doom-package-get package :type))))
|
||||
|
||||
(defun doom-package-in-module-p (package category &optional module)
|
||||
"Return non-nil if PACKAGE was installed by the user's private config."
|
||||
(when-let (modules (doom-package-get package :modules))
|
||||
(or (and (not module) (assq :private modules))
|
||||
(member (cons category module) modules))))
|
||||
|
||||
(defun doom-package-backend (package)
|
||||
"Return 'straight, 'builtin, 'elpa or 'other, depending on how PACKAGE is
|
||||
installed."
|
||||
(cond ((gethash (symbol-name package) straight--build-cache)
|
||||
'straight)
|
||||
((or (doom-package-built-in-p package)
|
||||
(assq package package--builtins))
|
||||
'builtin)
|
||||
((assq package package-alist)
|
||||
'elpa)
|
||||
((locate-library (symbol-name package))
|
||||
'other)))
|
||||
|
||||
(defun doom-package-changed-recipe-p (name)
|
||||
"Return t if a package named NAME (a symbol) has a different recipe than it
|
||||
was installed with."
|
||||
(cl-check-type name symbol)
|
||||
;; TODO
|
||||
;; (when (doom-package-installed-p name)
|
||||
;; (when-let* ((doom-recipe (assq name doom-packages))
|
||||
;; (install-recipe (doom-package-recipe)))
|
||||
;; (not (equal (cdr quelpa-recipe)
|
||||
;; (cdr (plist-get (cdr doom-recipe) :recipe))))))
|
||||
)
|
||||
|
||||
|
||||
;;; Package getters
|
||||
(defun doom--read-packages (file &optional noeval noerror)
|
||||
(condition-case-unless-debug e
|
||||
(with-temp-buffer ; prevent buffer-local state from propagating
|
||||
(if (not noeval)
|
||||
(load file noerror 'nomessage 'nosuffix)
|
||||
(when (file-exists-p file)
|
||||
(insert-file-contents file)
|
||||
(let (emacs-lisp-mode) (emacs-lisp-mode))
|
||||
;; Scrape `package!' blocks from FILE for a comprehensive listing of
|
||||
;; packages used by this module.
|
||||
(while (search-forward "(package!" nil t)
|
||||
(let ((ppss (save-excursion (syntax-ppss))))
|
||||
;; Don't collect packages in comments or strings
|
||||
(unless (or (nth 3 ppss)
|
||||
(nth 4 ppss))
|
||||
(goto-char (match-beginning 0))
|
||||
(cl-destructuring-bind (_ name . plist)
|
||||
(read (current-buffer))
|
||||
(push (cons
|
||||
name (plist-put
|
||||
plist :modules
|
||||
(list (doom-module-from-path file))))
|
||||
doom-packages))))))))
|
||||
(error
|
||||
(signal 'doom-package-error
|
||||
(list (doom-module-from-path file)
|
||||
file e)))))
|
||||
|
||||
(defun doom-package-list (&optional all-p core-only-p)
|
||||
"Retrieve a list of explicitly declared packages from enabled modules.
|
||||
|
||||
If ALL-P, gather packages unconditionally across all modules, including disabled
|
||||
ones."
|
||||
(let ((packages-file (concat doom-packages-file ".el"))
|
||||
doom-packages)
|
||||
(doom--read-packages
|
||||
(doom-path doom-core-dir packages-file) all-p 'noerror)
|
||||
(unless core-only-p
|
||||
(let ((private-packages (doom-path doom-private-dir packages-file))
|
||||
(doom-modules (doom-module-list)))
|
||||
(if all-p
|
||||
(mapc #'doom--read-packages
|
||||
(doom-files-in doom-modules-dir
|
||||
:depth 2
|
||||
:match "/packages\\.el$"))
|
||||
;; We load the private packages file twice to ensure disabled packages
|
||||
;; are seen ASAP, and a second time to ensure privately overridden
|
||||
;; packages are properly overwritten.
|
||||
(doom--read-packages private-packages nil 'noerror)
|
||||
(cl-loop for key being the hash-keys of doom-modules
|
||||
for path = (doom-module-path (car key) (cdr key) packages-file)
|
||||
for doom--current-module = key
|
||||
do (doom--read-packages path nil 'noerror)))
|
||||
(doom--read-packages private-packages all-p 'noerror)))
|
||||
(cl-remove-if-not
|
||||
(if core-only-p
|
||||
(lambda (pkg) (eq (plist-get (cdr pkg) :type) 'core))
|
||||
#'identity)
|
||||
(nreverse doom-packages))))
|
||||
|
||||
(defun doom-package-pinned-list ()
|
||||
"Return an alist mapping package names (strings) to pinned commits (strings)."
|
||||
(let (alist)
|
||||
(dolist (package doom-packages alist)
|
||||
(cl-destructuring-bind (name &key disable ignore pin unpin &allow-other-keys)
|
||||
package
|
||||
(when (and (not ignore)
|
||||
(not disable)
|
||||
(or pin unpin))
|
||||
(setf (alist-get (doom-package-recipe-repo name) alist
|
||||
nil 'remove #'equal)
|
||||
(unless unpin pin)))))))
|
||||
|
||||
(defun doom-package-unpinned-list ()
|
||||
"Return an alist mapping package names (strings) to pinned commits (strings)."
|
||||
(let (alist)
|
||||
(dolist (package doom-packages alist)
|
||||
(cl-destructuring-bind
|
||||
(_ &key recipe disable ignore pin unpin &allow-other-keys)
|
||||
package
|
||||
(when (and (not ignore)
|
||||
(not disable)
|
||||
(or unpin
|
||||
(and (plist-member recipe :pin)
|
||||
(null pin))))
|
||||
(cl-pushnew (doom-package-recipe-repo (car package)) alist
|
||||
:test #'equal))))))
|
||||
|
||||
(defun doom-package-recipe-list ()
|
||||
"Return straight recipes for non-builtin packages with a local-repo."
|
||||
(let (recipes)
|
||||
(dolist (recipe (hash-table-values straight--recipe-cache))
|
||||
(cl-destructuring-bind (&key local-repo type &allow-other-keys)
|
||||
recipe
|
||||
(unless (or (null local-repo)
|
||||
(eq type 'built-in))
|
||||
(push recipe recipes))))
|
||||
(nreverse recipes)))
|
||||
|
||||
(defun doom-package-state-list ()
|
||||
"TODO"
|
||||
(let (alist)
|
||||
(dolist (recipe (hash-table-values straight--repo-cache) alist)
|
||||
(cl-destructuring-bind (&key local-repo type &allow-other-keys)
|
||||
recipe
|
||||
(when (and local-repo (not (eq type 'built-in)))
|
||||
(setf (alist-get local-repo alist nil nil #'equal)
|
||||
(straight-vc-get-commit type local-repo)))))))
|
||||
|
||||
|
||||
;;
|
||||
;;; Module package macros
|
||||
|
||||
(cl-defmacro package!
|
||||
(name &rest plist &key built-in recipe ignore _disable _freeze)
|
||||
(name &rest plist &key built-in recipe ignore _type _pin _disable)
|
||||
"Declares a package and how to install it (if applicable).
|
||||
|
||||
This macro is declarative and does not load nor install packages. It is used to
|
||||
@@ -263,67 +432,134 @@ Only use this macro in a module's packages.el file.
|
||||
|
||||
Accepts the following properties:
|
||||
|
||||
:type core|local|built-in|virtual
|
||||
Specifies what kind of package this is. Can be a symbol or a list thereof.
|
||||
`core' = this is a protected package and cannot be disabled!
|
||||
`local' = this package is being modified in-place. This package's repo is
|
||||
unshallowed and will be skipped when you update packages.
|
||||
`built-in' = this package is already built-in (otherwise, will be
|
||||
installed)
|
||||
`virtual' = this package is not tracked by Doom's package manager. It won't
|
||||
be installed or uninstalled. Use this to pin 2nd order dependencies.
|
||||
:recipe RECIPE
|
||||
Takes a MELPA-style recipe (see `quelpa-recipe' in `quelpa' for an example);
|
||||
for packages to be installed from external sources.
|
||||
Specifies a straight.el recipe to allow you to acquire packages from external
|
||||
sources. See https://github.com/raxod502/straight.el#the-recipe-format for
|
||||
details on this recipe.
|
||||
:disable BOOL
|
||||
Do not install or update this package AND disable all of its `use-package!'
|
||||
blocks.
|
||||
and `after!' blocks.
|
||||
:ignore FORM
|
||||
Do not install this package.
|
||||
:freeze FORM
|
||||
Do not update this package if FORM is non-nil.
|
||||
:built-in BOOL
|
||||
Same as :ignore if the package is a built-in Emacs package. If set to
|
||||
'prefer, will use built-in package if it is present.
|
||||
:pin STR|nil
|
||||
Pin this package to commit hash STR. Setting this to nil will unpin this
|
||||
package if previously pinned.
|
||||
:built-in BOOL|'prefer
|
||||
Same as :ignore if the package is a built-in Emacs package. This is more to
|
||||
inform help commands like `doom/help-packages' that this is a built-in
|
||||
package. If set to 'prefer, the package will not be installed if it is
|
||||
already provided by Emacs.
|
||||
|
||||
Returns t if package is successfully registered, and nil if it was disabled
|
||||
elsewhere."
|
||||
(declare (indent defun))
|
||||
(when (and recipe (keywordp (car-safe recipe)))
|
||||
(plist-put! plist :recipe `(quote ,recipe)))
|
||||
;; :built-in t is basically an alias for :ignore (locate-library NAME)
|
||||
(when built-in
|
||||
(when (and (not ignore) (equal built-in '(quote prefer)))
|
||||
(when (and (not ignore)
|
||||
(equal built-in '(quote prefer)))
|
||||
(setq built-in `(locate-library ,(symbol-name name) nil doom--initial-load-path)))
|
||||
(plist-delete! plist :built-in)
|
||||
(plist-put! plist :ignore built-in))
|
||||
`(let* ((name ',name)
|
||||
(plist (cdr (assq name doom-packages))))
|
||||
;; Record what module this declaration was found in
|
||||
(let ((module-list (plist-get plist :modules))
|
||||
(module ',(doom-module-from-path)))
|
||||
(unless (member module module-list)
|
||||
(plist-put! plist :modules
|
||||
(append module-list
|
||||
(list module)
|
||||
(when (file-in-directory-p ,(dir!) doom-private-dir)
|
||||
'((:private . modules)))
|
||||
nil))))
|
||||
|
||||
;; Merge given plist with pre-existing one
|
||||
(doplist! ((prop val) (list ,@plist) plist)
|
||||
(unless (null val)
|
||||
(plist-put! plist prop val)))
|
||||
|
||||
;; Some basic key validation; error if you're not using a valid key
|
||||
;; Some basic key validation; throws an error on invalid properties
|
||||
(condition-case e
|
||||
(cl-destructuring-bind
|
||||
(&key _local-repo _files _flavor _no-build
|
||||
_type _repo _host _branch _remote _nonrecursive _fork _depth)
|
||||
(plist-get plist :recipe))
|
||||
(when-let (recipe (plist-get plist :recipe))
|
||||
(cl-destructuring-bind
|
||||
(&key local-repo _files _flavor
|
||||
_no-build _no-byte-compile _no-autoloads
|
||||
_type _repo _host _branch _remote _nonrecursive _fork _depth)
|
||||
recipe
|
||||
;; Expand :local-repo from current directory
|
||||
(when local-repo
|
||||
(plist-put!
|
||||
plist :recipe
|
||||
(plist-put recipe :local-repo
|
||||
(let ((local-path (expand-file-name local-repo ,(dir!))))
|
||||
(if (file-directory-p local-path)
|
||||
local-path
|
||||
local-repo)))))))
|
||||
(error
|
||||
(signal 'doom-package-error
|
||||
(cons ,(symbol-name name)
|
||||
(error-message-string e)))))
|
||||
|
||||
;; This is the only side-effect of this macro!
|
||||
(setf (alist-get name doom-packages) plist)
|
||||
(if (not (plist-get plist :disable)) t
|
||||
(doom-log "Disabling package %S" name)
|
||||
(cl-pushnew name doom-disabled-packages)
|
||||
nil)))
|
||||
(unless (plist-get plist :disable)
|
||||
(with-no-warnings
|
||||
(cons name plist)))))
|
||||
|
||||
(defmacro disable-packages! (&rest packages)
|
||||
"A convenience macro for disabling packages in bulk.
|
||||
Only use this macro in a module's (or your private) packages.el file."
|
||||
(macroexp-progn
|
||||
(cl-loop for p in packages
|
||||
collect `(package! ,p :disable t))))
|
||||
(mapcar (lambda (p) `(package! ,p :disable t))
|
||||
packages)))
|
||||
|
||||
(defmacro unpin! (&rest targets)
|
||||
"Unpin packages in TARGETS.
|
||||
|
||||
This unpins packages, so that 'doom upgrade' downloads their latest version. It
|
||||
can be used one of five ways:
|
||||
|
||||
+ To disable pinning wholesale: (unpin! t)
|
||||
+ To unpin individual packages: (unpin! packageA packageB ...)
|
||||
+ To unpin all packages in a group of modules: (unpin! :lang :tools ...)
|
||||
+ To unpin packages in individual modules:
|
||||
(unpin! (:lang python javascript) (:tools docker))
|
||||
|
||||
Or any combination of the above.
|
||||
|
||||
This macro should only be used from the user's private packages.el. No module
|
||||
should use it!"
|
||||
(if (memq t targets)
|
||||
`(mapc (doom-rpartial #'doom-package-set :unpin t)
|
||||
(mapcar #'car doom-packages))
|
||||
(macroexp-progn
|
||||
(mapcar
|
||||
(lambda (target)
|
||||
(when target
|
||||
`(doom-package-set ',target :unpin t)))
|
||||
(cl-loop for target in targets
|
||||
if (or (keywordp target) (listp target))
|
||||
append
|
||||
(cl-loop with (category . modules) = (doom-enlist target)
|
||||
for (name . plist) in doom-packages
|
||||
for pkg-modules = (plist-get plist :modules)
|
||||
if (and (assq category pkg-modules)
|
||||
(or (null modules)
|
||||
(cl-loop for module in modules
|
||||
if (member (cons category module) pkg-modules)
|
||||
return t))
|
||||
name)
|
||||
collect it)
|
||||
else if (symbolp target)
|
||||
collect target)))))
|
||||
|
||||
(provide 'core-packages)
|
||||
;;; core-packages.el ends here
|
||||
|
||||
@@ -15,23 +15,18 @@ Emacs.")
|
||||
"fd")
|
||||
"name of `fd-find' executable binary")
|
||||
|
||||
(defvar doom-projectile-cache-timer-file (concat doom-cache-dir "projectile.timers")
|
||||
"Where to save project file cache timers.")
|
||||
|
||||
|
||||
;;
|
||||
;;; Packages
|
||||
|
||||
(use-package! projectile
|
||||
:after-call after-find-file dired-before-readin-hook minibuffer-setup-hook
|
||||
:commands (projectile-project-root
|
||||
projectile-project-name
|
||||
projectile-project-p
|
||||
projectile-locate-dominating-file)
|
||||
:init
|
||||
(setq projectile-cache-file (concat doom-cache-dir "projectile.cache")
|
||||
projectile-enable-caching doom-interactive-mode
|
||||
projectile-files-cache-expire 86400 ; expire after a day
|
||||
projectile-enable-caching doom-interactive-p
|
||||
projectile-globally-ignored-files '(".DS_Store" "Icon
|
||||
" "TAGS")
|
||||
projectile-globally-ignored-file-suffixes '(".elc" ".pyc" ".o")
|
||||
@@ -44,28 +39,47 @@ Emacs.")
|
||||
|
||||
:config
|
||||
(projectile-mode +1)
|
||||
|
||||
;; Projectile runs four functions to determine the root (in this order):
|
||||
;;
|
||||
;; + `projectile-root-local' -> checks the `projectile-project-root' variable
|
||||
;; for an explicit path.
|
||||
;; + `projectile-root-bottom-up' -> searches from / to your current directory
|
||||
;; for the paths listed in `projectile-project-root-files-bottom-up'. This
|
||||
;; includes .git and .project
|
||||
;; + `projectile-root-top-down' -> searches from the current directory down to
|
||||
;; / the paths listed in `projectile-root-files', like package.json,
|
||||
;; setup.py, or Cargo.toml
|
||||
;; + `projectile-root-top-down-recurring' -> searches from the current
|
||||
;; directory down to / for a directory that has one of
|
||||
;; `projectile-project-root-files-top-down-recurring' but doesn't have a
|
||||
;; parent directory with the same file.
|
||||
;;
|
||||
;; In the interest of performance, we reduce the number of project root marker
|
||||
;; files/directories projectile searches for when resolving the project root.
|
||||
(setq projectile-project-root-files-bottom-up
|
||||
(setq projectile-project-root-files-bottom-up
|
||||
(append '(".projectile" ; projectile's root marker
|
||||
".project" ; doom project marker
|
||||
".git") ; Git VCS root dir
|
||||
(when (executable-find "hg")
|
||||
'(".hg")) ; Mercurial VCS root dir
|
||||
(when (executable-find "fossil")
|
||||
'(".fslckout" ; Fossil VCS root dir
|
||||
'(".hg")) ; Mercurial VCS root dir
|
||||
(when (executable-find "bzr")
|
||||
'(".bzr")) ; Bazaar VCS root dir
|
||||
(when (executable-find "darcs")
|
||||
(when (executable-find "bzr")
|
||||
'(".bzr"))) ; Bazaar VCS root dir
|
||||
;; This will be filled by other modules. We build this list manually so
|
||||
;; projectile doesn't perform so many file checks every time it resolves
|
||||
;; a project's root -- particularly when a file has no project.
|
||||
projectile-project-root-files '("TAGS")
|
||||
;; a project's root -- particularly when a file has no project.
|
||||
projectile-project-root-files '()
|
||||
projectile-project-root-files-top-down-recurring '("Makefile"))
|
||||
|
||||
(push (abbreviate-file-name doom-local-dir) projectile-globally-ignored-directories)
|
||||
|
||||
;; Override projectile's dirconfig file '.projectile' with doom's project marker '.project'.
|
||||
(defadvice! doom--projectile-dirconfig-file-a ()
|
||||
:override #'projectile-dirconfig-file
|
||||
(cond
|
||||
;; Prefers '.projectile' to maintain compatibility with existing projects.
|
||||
((file-exists-p! (or ".projectile" ".project") (projectile-project-root)))
|
||||
((expand-file-name ".project" (projectile-project-root)))))
|
||||
|
||||
;; Disable commands that won't work, as is, and that Doom already provides a
|
||||
;; better alternative for.
|
||||
@@ -88,7 +102,7 @@ b) represent blacklisted directories that are too big, change too often or are
|
||||
b) represent blacklisted directories that are too big, change too often or are
|
||||
private. (see `doom-projectile-cache-blacklist'),
|
||||
c) are not valid projectile projects."
|
||||
(when (and (bound-and-true-p projectile-projects-cache)
|
||||
(when (and (bound-and-true-p projectile-projects-cache)
|
||||
doom-interactive-p)
|
||||
(cl-loop with blacklist = (mapcar #'file-truename doom-projectile-cache-blacklist)
|
||||
for proot in (hash-table-keys projectile-projects-cache)
|
||||
@@ -116,15 +130,34 @@ c) are not valid projectile projects."
|
||||
(append projectile-project-root-files-bottom-up
|
||||
projectile-project-root-files)
|
||||
projectile-project-root-files-bottom-up nil)))
|
||||
|
||||
;; HACK Don't rely on VCS-specific commands to generate our file lists. That's
|
||||
;; 7 commands to maintain, versus the more generic, reliable and
|
||||
;; performant `fd' or `ripgrep'.
|
||||
(defadvice! doom--only-use-generic-command-a (orig-fn vcs)
|
||||
"Only use `projectile-generic-command' for indexing project files.
|
||||
And if it's a function, evaluate it."
|
||||
:around #'projectile-get-ext-command
|
||||
(if (functionp projectile-generic-command)
|
||||
(funcall projectile-generic-command vcs)
|
||||
projectile-generic-command))
|
||||
|
||||
(cond
|
||||
;; If fd exists, use it for git and generic projects. fd is a rust program
|
||||
;; that is significantly faster than git ls-files or find, and it respects
|
||||
;; .gitignore. This is recommended in the projectile docs.
|
||||
((executable-find doom-projectile-fd-binary)
|
||||
(setq projectile-generic-command
|
||||
(format "%s . --color=never --type f -0 -H -E .git"
|
||||
doom-projectile-fd-binary)
|
||||
(setq projectile-generic-command
|
||||
;; `projectile-generic-command' doesn't typically support a function.
|
||||
;; My `doom--only-use-generic-command-a' advice allows this. I do it
|
||||
;; this way so that future changes to
|
||||
;; `projectile-globally-ignored-directories' are respected.
|
||||
(lambda (_)
|
||||
(concat (format "%s . -0 -H -E .git --color=never --type file --type symlink --follow"
|
||||
doom-projectile-fd-binary)
|
||||
(cl-loop for dir in projectile-globally-ignored-directories
|
||||
concat " -E "
|
||||
concat (shell-quote-argument dir))
|
||||
(if IS-WINDOWS " --path-separator=//")))
|
||||
projectile-git-submodule-command nil
|
||||
;; ensure Windows users get fd's benefits
|
||||
@@ -132,29 +165,21 @@ c) are not valid projectile projects."
|
||||
|
||||
;; Otherwise, resort to ripgrep, which is also faster than find
|
||||
((executable-find "rg")
|
||||
(setq projectile-generic-command
|
||||
(concat "rg -0 --files --color=never --hidden"
|
||||
(cl-loop for dir in projectile-globally-ignored-directories
|
||||
concat (format " --glob '!%s'" dir)))
|
||||
(setq projectile-generic-command
|
||||
(lambda (_)
|
||||
(concat "rg -0 --files --follow --color=never --hidden"
|
||||
(cl-loop for dir in projectile-globally-ignored-directories
|
||||
concat " --glob "
|
||||
concat (shell-quote-argument (concat "!" dir)))
|
||||
(if IS-WINDOWS " --path-separator //")))
|
||||
projectile-git-submodule-command nil
|
||||
;; ensure Windows users get rg's benefits
|
||||
projectile-indexing-method 'alien))
|
||||
|
||||
;; Fix breakage on windows in git projects with submodules, since Windows
|
||||
;; doesn't have tr
|
||||
;; doesn't have tr
|
||||
(IS-WINDOWS
|
||||
(setq projectile-git-submodule-command nil)))
|
||||
|
||||
(defadvice! doom--projectile-cache-timers-a ()
|
||||
"Persist `projectile-projects-cache-time' across sessions, so that
|
||||
`projectile-files-cache-expire' checks won't reset when restarting Emacs."
|
||||
:before #'projectile-serialize-cache
|
||||
(projectile-serialize projectile-projects-cache-time doom-projectile-cache-timer-file))
|
||||
;; Restore it
|
||||
(when (file-readable-p doom-projectile-cache-timer-file)
|
||||
(setq projectile-projects-cache-time
|
||||
(projectile-unserialize doom-projectile-cache-timer-file)))
|
||||
|
||||
(defadvice! doom--projectile-default-generic-command-a (orig-fn &rest args)
|
||||
"If projectile can't tell what kind of project you're in, it issues an error
|
||||
@@ -169,12 +194,11 @@ the command instead."
|
||||
|
||||
;; Projectile root-searching functions can cause an infinite loop on TRAMP
|
||||
;; connections, so disable them.
|
||||
;; TODO Is this still necessary?
|
||||
;; TODO Is this still necessary?
|
||||
(defadvice! doom--projectile-locate-dominating-file-a (file _name)
|
||||
"Don't traverse the file system if on a remote connection."
|
||||
:around #'projectile-locate-dominating-file
|
||||
(when (and (stringp file)
|
||||
(not (file-remote-p file nil t)))
|
||||
"Don't traverse the file system if on a remote connection."
|
||||
:before-while #'projectile-locate-dominating-file
|
||||
(and (stringp file)
|
||||
(not (file-remote-p file nil t)))))
|
||||
|
||||
|
||||
@@ -193,16 +217,15 @@ state are passed in.")
|
||||
add-hooks
|
||||
on-load
|
||||
on-enter
|
||||
on-exit)
|
||||
"Define a project minor-mode named NAME (a symbol) and declare where and how
|
||||
it is activated. Project modes allow you to configure 'sub-modes' for
|
||||
major-modes that are specific to a folder, project structure, framework or
|
||||
whatever arbitrary context you define. These project modes can have their own
|
||||
on-exit)
|
||||
"Define a project minor mode named NAME and where/how it is activated.
|
||||
|
||||
Project modes allow you to configure 'sub-modes' for major-modes that are
|
||||
specific to a folder, project structure, framework or whatever arbitrary context
|
||||
you define. These project modes can have their own settings, keymaps, hooks,
|
||||
snippets, etc.
|
||||
|
||||
This creates NAME-hook and NAME-map as well.
|
||||
|
||||
A project can be enabled through .dir-locals.el too, by setting `doom-project'.
|
||||
|
||||
PLIST may contain any of these properties, which are all checked to see if NAME
|
||||
should be activated. If they are *all* true, NAME is activated.
|
||||
|
||||
@@ -54,6 +54,9 @@ examples.
|
||||
It is recommended you don't set specify a font-size, as to inherit `doom-font's
|
||||
size.")
|
||||
|
||||
(defvar doom-unicode-extra-fonts nil
|
||||
"Fonts to inject into the unicode charset before `doom-unicode-font'.")
|
||||
|
||||
|
||||
;;
|
||||
;;; Custom hooks
|
||||
@@ -85,45 +88,51 @@ size.")
|
||||
(defvar doom--last-frame nil)
|
||||
|
||||
(defun doom-run-switch-window-hooks-h ()
|
||||
(let ((gc-cons-threshold most-positive-fixnum))
|
||||
(unless (or doom-inhibit-switch-window-hooks
|
||||
(eq doom--last-window (selected-window))
|
||||
(minibufferp))
|
||||
(let ((doom-inhibit-switch-window-hooks t))
|
||||
(run-hooks 'doom-switch-window-hook)
|
||||
(setq doom--last-window (selected-window))))))
|
||||
(unless (or doom-inhibit-switch-window-hooks
|
||||
(eq doom--last-window (selected-window))
|
||||
(minibufferp))
|
||||
(let ((gc-cons-threshold most-positive-fixnum)
|
||||
(doom-inhibit-switch-window-hooks t)
|
||||
(inhibit-redisplay t))
|
||||
(run-hooks 'doom-switch-window-hook)
|
||||
(setq doom--last-window (selected-window)))))
|
||||
|
||||
(defun doom-run-switch-frame-hooks-h (&rest _)
|
||||
(unless (or doom-inhibit-switch-frame-hooks
|
||||
(eq doom--last-frame (selected-frame))
|
||||
(frame-parameter nil 'parent-frame))
|
||||
(let ((doom-inhibit-switch-frame-hooks t))
|
||||
(let ((gc-cons-threshold most-positive-fixnum)
|
||||
(doom-inhibit-switch-frame-hooks t))
|
||||
(run-hooks 'doom-switch-frame-hook)
|
||||
(setq doom--last-frame (selected-frame)))))
|
||||
|
||||
(defun doom-run-switch-buffer-hooks-a (orig-fn buffer-or-name &rest args)
|
||||
(let ((gc-cons-threshold most-positive-fixnum))
|
||||
(if (or doom-inhibit-switch-buffer-hooks
|
||||
(eq (current-buffer) (get-buffer buffer-or-name))
|
||||
(and (eq orig-fn #'switch-to-buffer) (car args)))
|
||||
(apply orig-fn buffer-or-name args)
|
||||
(let ((doom-inhibit-switch-buffer-hooks t))
|
||||
(when-let (buffer (apply orig-fn buffer-or-name args))
|
||||
(with-current-buffer (if (windowp buffer)
|
||||
(window-buffer buffer)
|
||||
buffer)
|
||||
(run-hooks 'doom-switch-buffer-hook))
|
||||
buffer)))))
|
||||
(if (or doom-inhibit-switch-buffer-hooks
|
||||
(and buffer-or-name
|
||||
(eq (current-buffer)
|
||||
(get-buffer buffer-or-name)))
|
||||
(and (eq orig-fn #'switch-to-buffer) (car args)))
|
||||
(apply orig-fn buffer-or-name args)
|
||||
(let ((gc-cons-threshold most-positive-fixnum)
|
||||
(doom-inhibit-switch-buffer-hooks t)
|
||||
(inhibit-redisplay t))
|
||||
(when-let (buffer (apply orig-fn buffer-or-name args))
|
||||
(with-current-buffer (if (windowp buffer)
|
||||
(window-buffer buffer)
|
||||
buffer)
|
||||
(run-hooks 'doom-switch-buffer-hook))
|
||||
buffer))))
|
||||
|
||||
(defun doom-run-switch-to-next-prev-buffer-hooks-a (orig-fn &rest args)
|
||||
(let ((gc-cons-threshold most-positive-fixnum))
|
||||
(if doom-inhibit-switch-buffer-hooks
|
||||
(apply orig-fn args)
|
||||
(let ((doom-inhibit-switch-buffer-hooks t))
|
||||
(when-let (buffer (apply orig-fn args))
|
||||
(with-current-buffer buffer
|
||||
(run-hooks 'doom-switch-buffer-hook))
|
||||
buffer)))))
|
||||
(if doom-inhibit-switch-buffer-hooks
|
||||
(apply orig-fn args)
|
||||
(let ((gc-cons-threshold most-positive-fixnum)
|
||||
(doom-inhibit-switch-buffer-hooks t)
|
||||
(inhibit-redisplay t))
|
||||
(when-let (buffer (apply orig-fn args))
|
||||
(with-current-buffer buffer
|
||||
(run-hooks 'doom-switch-buffer-hook))
|
||||
buffer))))
|
||||
|
||||
(defun doom-protect-fallback-buffer-h ()
|
||||
"Don't kill the scratch buffer. Meant for `kill-buffer-query-functions'."
|
||||
@@ -135,10 +144,11 @@ size.")
|
||||
e.g. If you indent with spaces by default, tabs will be highlighted. If you
|
||||
indent with tabs, spaces at BOL are highlighted.
|
||||
|
||||
Does nothing if `whitespace-mode' is already active or the current buffer is
|
||||
read-only or not file-visiting."
|
||||
Does nothing if `whitespace-mode' or 'global-whitespace-mode' is already
|
||||
active or if the current buffer is read-only or not file-visiting."
|
||||
(unless (or (eq major-mode 'fundamental-mode)
|
||||
buffer-read-only
|
||||
(bound-and-true-p global-whitespace-mode)
|
||||
(null buffer-file-name))
|
||||
(require 'whitespace)
|
||||
(set (make-local-variable 'whitespace-style)
|
||||
@@ -156,6 +166,10 @@ read-only or not file-visiting."
|
||||
;; Simpler confirmation prompt when killing Emacs
|
||||
(setq confirm-kill-emacs #'doom-quit-p)
|
||||
|
||||
;; Don't prompt for confirmation when we create a new file or buffer (assume the
|
||||
;; user knows what they're doing).
|
||||
(setq confirm-nonexistent-file-or-buffer nil)
|
||||
|
||||
(setq uniquify-buffer-name-style 'forward
|
||||
;; no beeping or blinking please
|
||||
ring-bell-function #'ignore
|
||||
@@ -173,7 +187,12 @@ read-only or not file-visiting."
|
||||
|
||||
(setq hscroll-margin 2
|
||||
hscroll-step 1
|
||||
scroll-conservatively 10
|
||||
;; Emacs spends too much effort recentering the screen if you scroll the
|
||||
;; cursor more than N lines past window edges (where N is the settings of
|
||||
;; `scroll-conservatively'). This is especially slow in larger files
|
||||
;; during large-scale scrolling commands. If kept over 100, the window is
|
||||
;; never automatically recentered.
|
||||
scroll-conservatively 101
|
||||
scroll-margin 0
|
||||
scroll-preserve-screen-position t
|
||||
;; Reduce cursor lag by a tiny bit by not auto-adjusting `window-vscroll'
|
||||
@@ -195,12 +214,18 @@ read-only or not file-visiting."
|
||||
;;
|
||||
;;; Cursor
|
||||
|
||||
;; Don't blink the cursor, it's too distracting.
|
||||
;; The blinking cursor is distracting, but also interferes with cursor settings
|
||||
;; in some minor modes that try to change it buffer-locally (like treemacs) and
|
||||
;; can cause freezing for folks (esp on macOS) with customized & color cursors.
|
||||
(blink-cursor-mode -1)
|
||||
|
||||
;; Don't blink the paren matching the one at point, it's too distracting.
|
||||
(setq blink-matching-paren nil)
|
||||
|
||||
;; Some terminals offer two different cursors: a “visible” static cursor and a
|
||||
;; “very visible” blinking one. By default, Emacs uses the very visible cursor
|
||||
;; and switches to it when you start or resume Emacs. If `visible-cursor' is nil
|
||||
;; when Emacs starts or resumes, it uses the normal cursor.
|
||||
(setq visible-cursor nil)
|
||||
|
||||
;; Don't stretch the cursor to fit wide characters, it is disorienting,
|
||||
@@ -214,8 +239,6 @@ read-only or not file-visiting."
|
||||
;; Make `next-buffer', `other-buffer', etc. ignore unreal buffers.
|
||||
(push '(buffer-predicate . doom-buffer-frame-predicate) default-frame-alist)
|
||||
|
||||
(setq confirm-nonexistent-file-or-buffer t)
|
||||
|
||||
(defadvice! doom--switch-to-fallback-buffer-maybe-a (&rest _)
|
||||
"Switch to `doom-fallback-buffer' if on last real buffer.
|
||||
|
||||
@@ -261,9 +284,6 @@ windows, switch to `doom-fallback-buffer'. Otherwise, delegate to original
|
||||
(setq indicate-buffer-boundaries nil
|
||||
indicate-empty-lines nil)
|
||||
|
||||
;; remove continuation arrow on right fringe
|
||||
(delq! 'continuation fringe-indicator-alist 'assq)
|
||||
|
||||
|
||||
;;
|
||||
;;; Windows/frames
|
||||
@@ -272,40 +292,53 @@ windows, switch to `doom-fallback-buffer'. Otherwise, delegate to original
|
||||
(setq frame-title-format '("%b – Doom Emacs")
|
||||
icon-title-format frame-title-format)
|
||||
|
||||
;; Don't resize emacs in steps, it looks weird.
|
||||
;; Don't resize windows & frames in steps; it's prohibitive to prevent the user
|
||||
;; from resizing it to exact dimensions, and looks weird.
|
||||
(setq window-resize-pixelwise t
|
||||
frame-resize-pixelwise t)
|
||||
|
||||
(unless EMACS27+ ; We already do this in early-init.el
|
||||
;; Disable tool and scrollbars; Doom encourages keyboard-centric workflows, so
|
||||
;; these are just clutter (the scrollbar also impacts Emacs' performance).
|
||||
(push '(menu-bar-lines . 0) default-frame-alist)
|
||||
(push '(tool-bar-lines . 0) default-frame-alist)
|
||||
(push '(vertical-scroll-bars) default-frame-alist))
|
||||
(unless (assq 'menu-bar-lines default-frame-alist)
|
||||
;; We do this in early-init.el too, but in case the user is on Emacs 26 we do
|
||||
;; it here too: disable tool and scrollbars, as Doom encourages
|
||||
;; keyboard-centric workflows, so these are just clutter (the scrollbar also
|
||||
;; impacts performance).
|
||||
(add-to-list 'default-frame-alist '(menu-bar-lines . 0))
|
||||
(add-to-list 'default-frame-alist '(tool-bar-lines . 0))
|
||||
(add-to-list 'default-frame-alist '(vertical-scroll-bars)))
|
||||
|
||||
;; Sets `ns-appearance' and `ns-transparent-titlebar' on GUI frames (and fixes
|
||||
;; mismatching text color in the frame title)
|
||||
(when IS-MAC
|
||||
;; These are disabled directly through their frame parameters, to avoid the
|
||||
;; extra work their minor modes do, but we have to unset these variables
|
||||
;; ourselves, otherwise users will have to cycle them twice to re-enable them.
|
||||
(setq menu-bar-mode nil
|
||||
tool-bar-mode nil
|
||||
scroll-bar-mode nil)
|
||||
|
||||
(when! IS-MAC
|
||||
;; Curse Lion and its sudden but inevitable fullscreen mode!
|
||||
;; NOTE Meaningless to railwaycat's emacs-mac build
|
||||
(setq ns-use-native-fullscreen nil
|
||||
;; Visit files opened outside of Emacs in existing frame, rather than a
|
||||
;; new one
|
||||
ns-pop-up-frames nil)
|
||||
(setq ns-use-native-fullscreen nil)
|
||||
|
||||
;; Sets ns-transparent-titlebar and ns-appearance frame parameters as is
|
||||
;; appropriate for the loaded theme.
|
||||
;; Visit files opened outside of Emacs in existing frame, not a new one
|
||||
(setq ns-pop-up-frames nil)
|
||||
|
||||
;; Sets `ns-transparent-titlebar' and `ns-appearance' frame parameters so
|
||||
;; window borders will match the enabled theme.
|
||||
(and (or (daemonp)
|
||||
(display-graphic-p))
|
||||
(require 'ns-auto-titlebar nil t)
|
||||
(ns-auto-titlebar-mode +1))
|
||||
|
||||
(add-hook! 'after-make-frame-functions
|
||||
(defun doom-init-menu-bar-in-gui-frames-h (frame)
|
||||
"On MacOS, the menu bar isn't part of the frame. Disabling it makes MacOS
|
||||
treat Emacs as a non-application window."
|
||||
(when (display-graphic-p frame)
|
||||
(set-frame-parameter frame 'menu-bar-lines 1)))))
|
||||
;; HACK On MacOS, disabling the menu bar makes MacOS treat Emacs as a
|
||||
;; non-application window -- which means it doesn't automatically capture
|
||||
;; focus when it is started, among other things. We enable menu-bar-lines
|
||||
;; there, but we still want it disabled in terminal frames because there
|
||||
;; it activates an ugly menu bar.
|
||||
(add-hook! '(window-setup-hook after-make-frame-functions)
|
||||
(defun doom-init-menu-bar-in-gui-frames-h (&optional frame)
|
||||
"Re-enable menu-bar-lines in GUI frames."
|
||||
(when-let (frame (or frame (selected-frame)))
|
||||
(when (display-graphic-p frame)
|
||||
(set-frame-parameter frame 'menu-bar-lines 1))))))
|
||||
|
||||
;; The native border "consumes" a pixel of the fringe on righter-most splits,
|
||||
;; `window-divider' does not. Available since Emacs 25.1.
|
||||
@@ -314,18 +347,21 @@ treat Emacs as a non-application window."
|
||||
window-divider-default-right-width 1)
|
||||
(add-hook 'doom-init-ui-hook #'window-divider-mode)
|
||||
|
||||
;; Prompt the user for confirmation when deleting a non-empty frame
|
||||
(global-set-key [remap delete-frame] #'doom/delete-frame)
|
||||
;; Prompt for confirmation when deleting a non-empty frame; a last line of
|
||||
;; defense against accidental loss of work.
|
||||
(global-set-key [remap delete-frame] #'doom/delete-frame-with-prompt)
|
||||
|
||||
;; always avoid GUI
|
||||
(setq use-dialog-box nil)
|
||||
;; Don't display floating tooltips; display their contents in the echo-area.
|
||||
(if (bound-and-true-p tooltip-mode) (tooltip-mode -1))
|
||||
;; native linux tooltips are ugly
|
||||
;; Don't display floating tooltips; display their contents in the echo-area,
|
||||
;; because native tooltips are ugly.
|
||||
(when (bound-and-true-p tooltip-mode)
|
||||
(tooltip-mode -1))
|
||||
;; ...especially on linux
|
||||
(when IS-LINUX
|
||||
(setq x-gtk-use-system-tooltips nil))
|
||||
|
||||
;; Favor vertical splits over horizontal ones
|
||||
;; Favor vertical splits over horizontal ones. Screens are usually wide.
|
||||
(setq split-width-threshold 160
|
||||
split-height-threshold nil)
|
||||
|
||||
@@ -334,11 +370,11 @@ treat Emacs as a non-application window."
|
||||
;;; Minibuffer
|
||||
|
||||
;; Allow for minibuffer-ception. Sometimes we need another minibuffer command
|
||||
;; _while_ we're in the minibuffer.
|
||||
;; while we're in the minibuffer.
|
||||
(setq enable-recursive-minibuffers t)
|
||||
|
||||
;; Show current key-sequence in minibuffer, like vim does. Any feedback after
|
||||
;; typing is better UX than no feedback at all.
|
||||
;; Show current key-sequence in minibuffer ala 'set showcmd' in vim. Any
|
||||
;; feedback after typing is better UX than no feedback at all.
|
||||
(setq echo-keystrokes 0.02)
|
||||
|
||||
;; Expand the minibuffer to fit multi-line text displayed in the echo-area. This
|
||||
@@ -348,7 +384,7 @@ treat Emacs as a non-application window."
|
||||
max-mini-window-height 0.15)
|
||||
|
||||
;; Typing yes/no is obnoxious when y/n will do
|
||||
(fset #'yes-or-no-p #'y-or-n-p)
|
||||
(advice-add #'yes-or-no-p :override #'y-or-n-p)
|
||||
|
||||
;; Try really hard to keep the cursor from getting stuck in the read-only prompt
|
||||
;; portion of the minibuffer.
|
||||
@@ -387,42 +423,36 @@ treat Emacs as a non-application window."
|
||||
(set-window-configuration doom--ediff-saved-wconf)))))
|
||||
|
||||
|
||||
(use-package! goto-addr
|
||||
:hook (text-mode . goto-address-mode)
|
||||
:hook (prog-mode . goto-address-prog-mode)
|
||||
:config
|
||||
(define-key goto-address-highlight-keymap (kbd "RET") #'goto-address-at-point))
|
||||
|
||||
|
||||
(use-package! hl-line
|
||||
;; Highlights the current line
|
||||
:hook ((prog-mode text-mode conf-mode) . hl-line-mode)
|
||||
:hook ((prog-mode text-mode conf-mode special-mode) . hl-line-mode)
|
||||
:config
|
||||
;; Not having to render the hl-line overlay in multiple buffers offers a tiny
|
||||
;; performance boost. I also don't need to see it in other buffers.
|
||||
(setq hl-line-sticky-flag nil
|
||||
global-hl-line-sticky-flag nil)
|
||||
|
||||
;; Disable `hl-line' in evil-visual mode (temporarily). `hl-line' can make the
|
||||
;; selection region harder to see while in evil visual mode.
|
||||
(after! evil
|
||||
(defvar doom-buffer-hl-line-mode nil)
|
||||
(add-hook! 'evil-visual-state-entry-hook
|
||||
(defun doom-disable-hl-line-h ()
|
||||
(when hl-line-mode
|
||||
(setq-local doom-buffer-hl-line-mode t)
|
||||
(hl-line-mode -1))))
|
||||
(add-hook! 'evil-visual-state-exit-hook
|
||||
(defun doom-enable-hl-line-maybe-h ()
|
||||
(when doom-buffer-hl-line-mode
|
||||
(hl-line-mode +1))))))
|
||||
;; Temporarily disable `hl-line' when selection is active, since it doesn't
|
||||
;; serve much purpose when the selection is so much more visible.
|
||||
(defvar doom--hl-line-mode nil)
|
||||
|
||||
(add-hook! '(evil-visual-state-entry-hook activate-mark-hook)
|
||||
(defun doom-disable-hl-line-h ()
|
||||
(when hl-line-mode
|
||||
(setq-local doom--hl-line-mode t)
|
||||
(hl-line-mode -1))))
|
||||
|
||||
(add-hook! '(evil-visual-state-exit-hook deactivate-mark-hook)
|
||||
(defun doom-enable-hl-line-maybe-h ()
|
||||
(when doom--hl-line-mode
|
||||
(hl-line-mode +1)))))
|
||||
|
||||
|
||||
(use-package! winner
|
||||
;; undo/redo changes to Emacs' window layout
|
||||
:after-call after-find-file doom-switch-window-hook
|
||||
:preface (defvar winner-dont-bind-my-keys t) ; I'll bind keys myself
|
||||
:config (winner-mode +1)
|
||||
:hook (doom-first-buffer . winner-mode)
|
||||
:config
|
||||
(appendq! winner-boring-buffers
|
||||
'("*Compile-Log*" "*inferior-lisp*" "*Fuzzy Completions*"
|
||||
"*Apropos*" "*Help*" "*cvs*" "*Buffer List*" "*Ibuffer*"
|
||||
@@ -431,13 +461,12 @@ treat Emacs as a non-application window."
|
||||
|
||||
(use-package! paren
|
||||
;; highlight matching delimiters
|
||||
:after-call after-find-file doom-switch-buffer-hook
|
||||
:hook (doom-first-buffer . show-paren-mode)
|
||||
:config
|
||||
(setq show-paren-delay 0.1
|
||||
show-paren-highlight-openparen t
|
||||
show-paren-when-point-inside-paren t
|
||||
show-paren-when-point-in-periphery t)
|
||||
(show-paren-mode +1))
|
||||
show-paren-when-point-in-periphery t))
|
||||
|
||||
|
||||
;;;###package whitespace
|
||||
@@ -461,13 +490,31 @@ treat Emacs as a non-application window."
|
||||
all-the-icons-wicon
|
||||
all-the-icons-material
|
||||
all-the-icons-alltheicon)
|
||||
:init
|
||||
(defadvice! doom--disable-all-the-icons-in-tty-a (orig-fn &rest args)
|
||||
"Return a blank string in tty Emacs, which doesn't support multiple fonts."
|
||||
:around #'all-the-icons-insert
|
||||
(if (display-multi-font-p)
|
||||
(apply orig-fn args)
|
||||
"")))
|
||||
:preface
|
||||
(setq doom-unicode-extra-fonts
|
||||
(list "Weather Icons"
|
||||
"github-octicons"
|
||||
"FontAwesome"
|
||||
"all-the-icons"
|
||||
"file-icons"
|
||||
"Material Icons"))
|
||||
:config
|
||||
(cond ((daemonp)
|
||||
(defadvice! doom--disable-all-the-icons-in-tty-a (orig-fn &rest args)
|
||||
"Return a blank string in tty Emacs, which doesn't support multiple fonts."
|
||||
:around '(all-the-icons-octicon all-the-icons-material
|
||||
all-the-icons-faicon all-the-icons-fileicon
|
||||
all-the-icons-wicon all-the-icons-alltheicon)
|
||||
(if (or (not after-init-time) (display-multi-font-p))
|
||||
(apply orig-fn args)
|
||||
"")))
|
||||
((not (display-graphic-p))
|
||||
(defadvice! doom--disable-all-the-icons-in-tty-a (&rest _)
|
||||
"Return a blank string for tty users."
|
||||
:override '(all-the-icons-octicon all-the-icons-material
|
||||
all-the-icons-faicon all-the-icons-fileicon
|
||||
all-the-icons-wicon all-the-icons-alltheicon)
|
||||
""))))
|
||||
|
||||
;;;###package hide-mode-line-mode
|
||||
(add-hook! '(completion-list-mode-hook Man-mode-hook)
|
||||
@@ -486,10 +533,6 @@ treat Emacs as a non-application window."
|
||||
;; languages like Lisp.
|
||||
(setq rainbow-delimiters-max-face-count 3)
|
||||
|
||||
;;;###package pos-tip
|
||||
(setq pos-tip-internal-border-width 6
|
||||
pos-tip-border-width 1)
|
||||
|
||||
|
||||
;;
|
||||
;;; Line numbers
|
||||
@@ -497,16 +540,16 @@ treat Emacs as a non-application window."
|
||||
;; Explicitly define a width to reduce computation
|
||||
(setq-default display-line-numbers-width 3)
|
||||
|
||||
;; Show absolute line numbers for narrowed regions
|
||||
;; Show absolute line numbers for narrowed regions makes it easier to tell the
|
||||
;; buffer is narrowed, and where you are, exactly.
|
||||
(setq-default display-line-numbers-widen t)
|
||||
|
||||
;; Enable line numbers in most text-editing modes
|
||||
;; Enable line numbers in most text-editing modes. We avoid
|
||||
;; `global-display-line-numbers-mode' because there are many special and
|
||||
;; temporary modes where we don't need/want them.
|
||||
(add-hook! '(prog-mode-hook text-mode-hook conf-mode-hook)
|
||||
#'display-line-numbers-mode)
|
||||
|
||||
(defun doom-enable-line-numbers-h () (display-line-numbers-mode +1))
|
||||
(defun doom-disable-line-numbers-h () (display-line-numbers-mode -1))
|
||||
|
||||
|
||||
;;
|
||||
;;; Theme & font
|
||||
@@ -514,35 +557,44 @@ treat Emacs as a non-application window."
|
||||
;; Underline looks a bit better when drawn lower
|
||||
(setq x-underline-at-descent-line t)
|
||||
|
||||
;; DEPRECATED In Emacs 27
|
||||
(defvar doom--prefer-theme-elc nil
|
||||
"If non-nil, `load-theme' will prefer the compiled theme (unlike its default
|
||||
behavior). Do not set this directly, this is let-bound in `doom-init-theme-h'.")
|
||||
|
||||
(defun doom-init-fonts-h ()
|
||||
"Loads `doom-font'."
|
||||
(cond (doom-font
|
||||
(cl-pushnew
|
||||
(cons 'font
|
||||
(cond ((stringp doom-font) doom-font)
|
||||
((fontp doom-font) (font-xlfd-name doom-font))
|
||||
((signal 'wrong-type-argument (list '(fontp stringp)
|
||||
doom-font)))))
|
||||
default-frame-alist
|
||||
:key #'car :test #'eq))
|
||||
((display-graphic-p)
|
||||
(setq font-use-system-font t
|
||||
doom-font (face-attribute 'default :font)))))
|
||||
(cond
|
||||
(doom-font
|
||||
(cl-pushnew
|
||||
;; Avoiding `set-frame-font' because it does a lot of extra, expensive
|
||||
;; work we can avoid by setting the font frame parameter instead.
|
||||
(cons 'font
|
||||
(cond ((stringp doom-font) doom-font)
|
||||
((fontp doom-font) (font-xlfd-name doom-font))
|
||||
((signal 'wrong-type-argument (list '(fontp stringp)
|
||||
doom-font)))))
|
||||
default-frame-alist
|
||||
:key #'car :test #'eq))
|
||||
((display-graphic-p)
|
||||
;; We try our best to record your system font, so `doom-big-font-mode'
|
||||
;; can still use it to compute a larger font size with.
|
||||
(setq font-use-system-font t
|
||||
doom-font (face-attribute 'default :font)))))
|
||||
|
||||
(defun doom-init-extra-fonts-h (&optional frame)
|
||||
"Loads `doom-variable-pitch-font',`doom-serif-font' and `doom-unicode-font'."
|
||||
(condition-case e
|
||||
(with-selected-frame (or frame (selected-frame))
|
||||
(when doom-font
|
||||
(set-face-attribute 'fixed-pitch nil :font doom-font))
|
||||
(when doom-serif-font
|
||||
(set-face-attribute 'fixed-pitch-serif nil :font doom-serif-font))
|
||||
(when doom-variable-pitch-font
|
||||
(set-face-attribute 'variable-pitch nil :font doom-variable-pitch-font))
|
||||
(when (and doom-unicode-font (fboundp 'set-fontset-font))
|
||||
(set-fontset-font t 'unicode doom-unicode-font nil 'prepend)))
|
||||
(when (fboundp 'set-fontset-font)
|
||||
(dolist (font (append doom-unicode-extra-fonts (doom-enlist doom-unicode-font)))
|
||||
(set-fontset-font t 'unicode font nil 'prepend))))
|
||||
((debug error)
|
||||
(if (string-prefix-p "Font not available: " (error-message-string e))
|
||||
(lwarn 'doom-ui :warning
|
||||
@@ -554,29 +606,54 @@ behavior). Do not set this directly, this is let-bound in `doom-init-theme-h'.")
|
||||
"Load the theme specified by `doom-theme' in FRAME."
|
||||
(when (and doom-theme (not (memq doom-theme custom-enabled-themes)))
|
||||
(with-selected-frame (or frame (selected-frame))
|
||||
(let ((doom--prefer-theme-elc t))
|
||||
(let ((doom--prefer-theme-elc t)) ; DEPRECATED in Emacs 27
|
||||
(load-theme doom-theme t)))))
|
||||
|
||||
(defadvice! doom--run-load-theme-hooks-a (theme &optional _no-confirm no-enable)
|
||||
"Set up `doom-load-theme-hook' to run after `load-theme' is called."
|
||||
:after-while #'load-theme
|
||||
(unless no-enable
|
||||
(setq doom-theme theme
|
||||
doom-init-theme-p t)
|
||||
(run-hooks 'doom-load-theme-hook)))
|
||||
(defadvice! doom--load-theme-a (orig-fn theme &optional no-confirm no-enable)
|
||||
"Run `doom-load-theme-hook' on `load-theme' and fix its issues.
|
||||
|
||||
(defadvice! doom--prefer-compiled-theme-a (orig-fn &rest args)
|
||||
"Make `load-theme' prioritize the byte-compiled theme for a moderate boost in
|
||||
startup (or theme switch) time, so long as `doom--prefer-theme-elc' is non-nil."
|
||||
1. Disable previously enabled themes.
|
||||
2. Don't let face-remapping screw up loading the new theme
|
||||
(*cough*`mixed-pitch-mode').
|
||||
3. Record the current theme in `doom-theme'."
|
||||
:around #'load-theme
|
||||
(if (or (null after-init-time)
|
||||
doom--prefer-theme-elc)
|
||||
(cl-letf* ((old-locate-file (symbol-function 'locate-file))
|
||||
((symbol-function 'locate-file)
|
||||
(lambda (filename path &optional _suffixes predicate)
|
||||
(funcall old-locate-file filename path '("c" "") predicate))))
|
||||
(apply orig-fn args))
|
||||
(apply orig-fn args)))
|
||||
;; HACK Run `load-theme' from an estranged buffer, where we can be assured
|
||||
;; that buffer-local face remaps (by `mixed-pitch-mode', for instance)
|
||||
;; won't interfere with changing themes.
|
||||
(with-temp-buffer
|
||||
(when-let (result (funcall orig-fn theme no-confirm no-enable))
|
||||
(unless no-enable
|
||||
(setq doom-theme theme
|
||||
doom-init-theme-p t)
|
||||
;; `load-theme' doesn't disable previously enabled themes, which seems
|
||||
;; like what you'd want. You could always use `enable-theme' to activate
|
||||
;; multiple themes instead.
|
||||
(mapc #'disable-theme (remq theme custom-enabled-themes))
|
||||
(run-hooks 'doom-load-theme-hook))
|
||||
result)))
|
||||
|
||||
(when! (not EMACS27+)
|
||||
;; DEPRECATED `doom--load-theme-a' handles this for us after the theme is
|
||||
;; loaded, but this only works on Emacs 27+. Disabling old themes
|
||||
;; must be done *before* the theme is loaded in Emacs 26.
|
||||
(defadvice! doom--disable-previous-themes-a (theme &optional _no-confirm no-enable)
|
||||
"Disable other themes when loading a new one."
|
||||
:before #'load-theme
|
||||
(unless no-enable
|
||||
(mapc #'disable-theme custom-enabled-themes)))
|
||||
|
||||
;; DEPRECATED Not needed in Emacs 27
|
||||
(defadvice! doom--prefer-compiled-theme-a (orig-fn &rest args)
|
||||
"Have `load-theme' prioritize the byte-compiled theme.
|
||||
This offers a moderate boost in startup (or theme switch) time, so long as
|
||||
`doom--prefer-theme-elc' is non-nil."
|
||||
:around #'load-theme
|
||||
(if (or (null after-init-time)
|
||||
doom--prefer-theme-elc)
|
||||
(letf! (defun locate-file (filename path &optional _suffixes predicate)
|
||||
(funcall locate-file filename path '("c" "") predicate))
|
||||
(apply orig-fn args))
|
||||
(apply orig-fn args))))
|
||||
|
||||
|
||||
;;
|
||||
@@ -590,9 +667,13 @@ startup (or theme switch) time, so long as `doom--prefer-theme-elc' is non-nil."
|
||||
(add-hook 'after-change-major-mode-hook #'doom-highlight-non-default-indentation-h 'append)
|
||||
|
||||
;; Initialize custom switch-{buffer,window,frame} hooks:
|
||||
;;
|
||||
;; + `doom-switch-buffer-hook'
|
||||
;; + `doom-switch-window-hook'
|
||||
;; + `doom-switch-frame-hook'
|
||||
;;
|
||||
;; These should be done as late as possible, as not to prematurely trigger
|
||||
;; hooks during startup.
|
||||
(add-hook 'buffer-list-update-hook #'doom-run-switch-window-hooks-h)
|
||||
(add-hook 'focus-in-hook #'doom-run-switch-frame-hooks-h)
|
||||
(dolist (fn '(switch-to-next-buffer switch-to-prev-buffer))
|
||||
@@ -617,19 +698,27 @@ startup (or theme switch) time, so long as `doom--prefer-theme-elc' is non-nil."
|
||||
;;; Fixes/hacks
|
||||
|
||||
;; Doom doesn't support `customize' and it never will. It's a clumsy interface
|
||||
;; for something that should be configured from only one place ($DOOMDIR), so we
|
||||
;; disable them.
|
||||
(put 'customize 'disabled "Doom doesn't support `customize', configure Emacs from $DOOMDIR/config.el instead")
|
||||
;; that sets variables at a time where it can be easily and unpredictably
|
||||
;; overwritten. Configure things from your $DOOMDIR instead.
|
||||
(dolist (sym '(customize-option customize-browse customize-group customize-face
|
||||
customize-rogue customize-saved customize-apropos
|
||||
customize-changed customize-unsaved customize-variable
|
||||
customize-set-value customize-customized customize-set-variable
|
||||
customize-apropos-faces customize-save-variable
|
||||
customize-apropos-groups customize-apropos-options
|
||||
customize-changed-options customize-save-customized))
|
||||
(put sym 'disabled "Doom doesn't support `customize', configure Emacs from $DOOMDIR/config.el instead"))
|
||||
(put 'customize-themes 'disabled "Set `doom-theme' or use `load-theme' in $DOOMDIR/config.el instead")
|
||||
|
||||
;; doesn't exist in terminal Emacs; we define it to prevent errors
|
||||
;; Doesn't exist in terminal Emacs, so we define it to prevent void-function
|
||||
;; errors emitted from packages that blindly try to use it.
|
||||
(unless (fboundp 'define-fringe-bitmap)
|
||||
(fset 'define-fringe-bitmap #'ignore))
|
||||
|
||||
(after! whitespace
|
||||
(defun doom-disable-whitespace-mode-in-childframes-a (orig-fn)
|
||||
"`whitespace-mode' inundates child frames with whitspace markers, so disable
|
||||
it to fix all that visual noise."
|
||||
"`whitespace-mode' inundates child frames with whitespace markers, so
|
||||
disable it to fix all that visual noise."
|
||||
(unless (frame-parameter nil 'parent-frame)
|
||||
(funcall orig-fn)))
|
||||
(add-function :around whitespace-enable-predicate #'doom-disable-whitespace-mode-in-childframes-a))
|
||||
|
||||
@@ -1,41 +1,58 @@
|
||||
;;; core.el --- the heart of the beast -*- lexical-binding: t; -*-
|
||||
|
||||
(when (version< emacs-version "26.1")
|
||||
(error "Detected Emacs %s. Doom only supports Emacs 26.1 and higher"
|
||||
emacs-version))
|
||||
(eval-when-compile
|
||||
(when (< emacs-major-version 26)
|
||||
(error "Detected Emacs v%s. Doom only supports Emacs 26 and newer"
|
||||
emacs-version)))
|
||||
|
||||
|
||||
;;
|
||||
;;; Variables
|
||||
|
||||
(defconst doom-version "2.0.9"
|
||||
"Current version of Doom Emacs.")
|
||||
|
||||
(defconst EMACS27+ (> emacs-major-version 26))
|
||||
(defconst EMACS28+ (> emacs-major-version 27))
|
||||
(defconst IS-MAC (eq system-type 'darwin))
|
||||
(defconst IS-LINUX (eq system-type 'gnu/linux))
|
||||
(defconst IS-WINDOWS (memq system-type '(cygwin windows-nt ms-dos)))
|
||||
(defconst IS-BSD (or IS-MAC (eq system-type 'berkeley-unix)))
|
||||
|
||||
;; Unix tools look for HOME, but this is normally not defined on Windows.
|
||||
(when (and IS-WINDOWS (null (getenv "HOME")))
|
||||
(setenv "HOME" (getenv "USERPROFILE")))
|
||||
|
||||
;; Ensure `doom-core-dir' is in `load-path'
|
||||
(add-to-list 'load-path (file-name-directory load-file-name))
|
||||
|
||||
(defvar doom--initial-load-path load-path)
|
||||
(defvar doom--initial-process-environment process-environment)
|
||||
(defvar doom--initial-exec-path exec-path)
|
||||
(defvar doom--initial-file-name-handler-alist file-name-handler-alist)
|
||||
|
||||
;; This is consulted on every `require', `load' and various path/io functions.
|
||||
;; You get a minor speed up by nooping this.
|
||||
(setq file-name-handler-alist nil)
|
||||
;; `file-name-handler-alist' is consulted on every `require', `load' and various
|
||||
;; path/io functions. You get a minor speed up by nooping this. However, this
|
||||
;; may cause problems on builds of Emacs where its site lisp files aren't
|
||||
;; byte-compiled and we're forced to load the *.el.gz files (e.g. on Alpine)
|
||||
(unless noninteractive
|
||||
(defvar doom--initial-file-name-handler-alist file-name-handler-alist)
|
||||
|
||||
;; Restore `file-name-handler-alist', because it is needed for handling
|
||||
;; encrypted or compressed files, among other things.
|
||||
(defun doom-reset-file-handler-alist-h ()
|
||||
(setq file-name-handler-alist doom--initial-file-name-handler-alist))
|
||||
(add-hook 'emacs-startup-hook #'doom-reset-file-handler-alist-h)
|
||||
(setq file-name-handler-alist nil)
|
||||
;; Restore `file-name-handler-alist', because it is needed for handling
|
||||
;; encrypted or compressed files, among other things.
|
||||
(defun doom-reset-file-handler-alist-h ()
|
||||
;; Re-add rather than `setq', because file-name-handler-alist may have
|
||||
;; changed since startup, and we want to preserve those.
|
||||
(dolist (handler file-name-handler-alist)
|
||||
(add-to-list 'doom--initial-file-name-handler-alist handler))
|
||||
(setq file-name-handler-alist doom--initial-file-name-handler-alist))
|
||||
(add-hook 'emacs-startup-hook #'doom-reset-file-handler-alist-h))
|
||||
|
||||
;; Load the bare necessities
|
||||
;; Just the bare necessities
|
||||
(require 'subr-x)
|
||||
(require 'cl-lib)
|
||||
(require 'core-lib)
|
||||
|
||||
(autoload 'doom-initialize-packages "core-packages")
|
||||
|
||||
|
||||
;;
|
||||
;;; Global variables
|
||||
@@ -46,13 +63,13 @@
|
||||
(defvar doom-init-time nil
|
||||
"The time it took, in seconds, for Doom Emacs to initialize.")
|
||||
|
||||
(defvar doom-debug-mode (or (getenv "DEBUG") init-file-debug)
|
||||
(defvar doom-debug-p (or (getenv "DEBUG") init-file-debug)
|
||||
"If non-nil, Doom will log more.
|
||||
|
||||
Use `doom/toggle-debug-mode' to toggle it. The --debug-init flag and setting the
|
||||
DEBUG envvar will enable this at startup.")
|
||||
Use `doom-debug-mode' to toggle it. The --debug-init flag and setting the DEBUG
|
||||
envvar will enable this at startup.")
|
||||
|
||||
(defvar doom-interactive-mode (not noninteractive)
|
||||
(defvar doom-interactive-p (not noninteractive)
|
||||
"If non-nil, Emacs is in interactive mode.")
|
||||
|
||||
;;; Directories/files
|
||||
@@ -110,14 +127,8 @@ whichever is found first. Must end in a slash.")
|
||||
This file is responsible for informing Emacs where to find all of Doom's
|
||||
autoloaded core functions (in core/autoload/*.el).")
|
||||
|
||||
(defconst doom-package-autoload-file (concat doom-local-dir "autoloads.pkg.el")
|
||||
"Where `doom-reload-package-autoloads' stores its package autoloads.
|
||||
|
||||
This file is compiled from the autoloads files of all installed packages
|
||||
combined.")
|
||||
|
||||
(defconst doom-env-file (concat doom-local-dir "env")
|
||||
"The location of your envvar file, generated by `doom env refresh`.
|
||||
"The location of your envvar file, generated by `doom env`.
|
||||
|
||||
This file contains environment variables scraped from your shell environment,
|
||||
which is loaded at startup (if it exists). This is helpful if Emacs can't
|
||||
@@ -127,7 +138,7 @@ users).")
|
||||
;;; Custom error types
|
||||
(define-error 'doom-error "Error in Doom Emacs core")
|
||||
(define-error 'doom-hook-error "Error in a Doom startup hook" 'doom-error)
|
||||
(define-error 'doom-autoload-error "Error in an autoloads file" 'doom-error)
|
||||
(define-error 'doom-autoload-error "Error in Doom's autoloads file" 'doom-error)
|
||||
(define-error 'doom-module-error "Error in a Doom module" 'doom-error)
|
||||
(define-error 'doom-private-error "Error in private config" 'doom-error)
|
||||
(define-error 'doom-package-error "Error with packages" 'doom-error)
|
||||
@@ -136,84 +147,99 @@ users).")
|
||||
;;
|
||||
;;; Emacs core configuration
|
||||
|
||||
;; Reduce debug output, well, unless we've asked for it.
|
||||
(setq debug-on-error doom-debug-mode
|
||||
jka-compr-verbose doom-debug-mode)
|
||||
;; lo', longer logs ahoy, so to reliably locate lapses in doom's logic later
|
||||
(setq message-log-max 8192)
|
||||
|
||||
;; UTF-8 as the default coding system
|
||||
;; Reduce debug output, well, unless we've asked for it.
|
||||
(setq debug-on-error doom-debug-p
|
||||
jka-compr-verbose doom-debug-p)
|
||||
|
||||
;; Contrary to what many Emacs users have in their configs, you really don't
|
||||
;; need more than this to make UTF-8 the default coding system:
|
||||
(when (fboundp 'set-charset-priority)
|
||||
(set-charset-priority 'unicode)) ; pretty
|
||||
(prefer-coding-system 'utf-8) ; pretty
|
||||
(setq locale-coding-system 'utf-8) ; please
|
||||
;; Except for the clipboard on Windows, where its contents could be in an
|
||||
;; encoding that's wider than utf-8, so we let Emacs/the OS decide what encoding
|
||||
;; to use.
|
||||
;; The clipboard's on Windows could be in an encoding that's wider (or thinner)
|
||||
;; than utf-8, so let Emacs/the OS decide what encoding to use there.
|
||||
(unless IS-WINDOWS
|
||||
(setq selection-coding-system 'utf-8)) ; with sugar on top
|
||||
|
||||
;; Disable warnings from legacy advice system. They aren't useful, and we can't
|
||||
;; often do anything about them besides changing packages upstream
|
||||
;; Disable warnings from legacy advice system. They aren't useful, and what can
|
||||
;; we do about them, besides changing packages upstream?
|
||||
(setq ad-redefinition-action 'accept)
|
||||
|
||||
;; Make apropos omnipotent. It's more useful this way.
|
||||
(setq apropos-do-all t)
|
||||
|
||||
;; Don't make a second case-insensitive pass over `auto-mode-alist'. If it has
|
||||
;; to, it's our (the user's) failure. One case for all!
|
||||
;; A second, case-insensitive pass over `auto-mode-alist' is time wasted, and
|
||||
;; indicates misconfiguration (or that the user needs to stop relying on case
|
||||
;; insensitivity).
|
||||
(setq auto-mode-case-fold nil)
|
||||
|
||||
;; Make all regexps case-sensitive by default. This favors correctness for
|
||||
;; programmatical regexp searches and provides a slight performance benefit to
|
||||
;; font-locking where the keywords don't let-bind `case-fold-search' themselves
|
||||
;; and are already case-correct. This could break poorly written packages!
|
||||
(setq-default case-fold-search nil)
|
||||
|
||||
;; Display the bare minimum at startup. We don't need all that noise. The
|
||||
;; dashboard/empty scratch buffer is good enough.
|
||||
;; Less noise at startup. The dashboard/empty scratch buffer is good enough.
|
||||
(setq inhibit-startup-message t
|
||||
inhibit-startup-echo-area-message user-login-name
|
||||
inhibit-default-init t
|
||||
;; Avoid pulling in many packages by starting the scratch buffer in
|
||||
;; `fundamental-mode', rather than, say, `org-mode' or `text-mode'.
|
||||
initial-major-mode 'fundamental-mode
|
||||
initial-scratch-message nil)
|
||||
(fset #'display-startup-echo-area-message #'ignore)
|
||||
|
||||
;; Get rid of "For information about GNU Emacs..." message at startup, unless
|
||||
;; we're in a daemon session, where it'll say "Starting Emacs daemon." instead,
|
||||
;; which isn't so bad.
|
||||
(unless (daemonp)
|
||||
(advice-add #'display-startup-echo-area-message :override #'ignore))
|
||||
|
||||
;; Emacs "updates" its ui more often than it needs to, so we slow it down
|
||||
;; slightly, from 0.5s:
|
||||
(setq idle-update-delay 1)
|
||||
;; slightly from 0.5s:
|
||||
(setq idle-update-delay 1.0)
|
||||
|
||||
;; Emacs is a huge security vulnerability, what with all the dependencies it
|
||||
;; pulls in from all corners of the globe. Let's at least try to be more
|
||||
;; discerning.
|
||||
(setq gnutls-verify-error (getenv "INSECURE")
|
||||
;; Emacs is essentially one huge security vulnerability, what with all the
|
||||
;; dependencies it pulls in from all corners of the globe. Let's try to be at
|
||||
;; least a little more discerning.
|
||||
(setq gnutls-verify-error (not (getenv "INSECURE"))
|
||||
gnutls-algorithm-priority
|
||||
(when (boundp 'libgnutls-version)
|
||||
(concat "SECURE128:+SECURE192:-VERS-ALL"
|
||||
(if (and (not IS-WINDOWS)
|
||||
(not (version< emacs-version "26.3"))
|
||||
(>= libgnutls-version 30605))
|
||||
":+VERS-TLS1.3")
|
||||
":+VERS-TLS1.2"))
|
||||
;; `gnutls-min-prime-bits' is set based on recommendations from
|
||||
;; https://www.keylength.com/en/4/
|
||||
gnutls-min-prime-bits 3072
|
||||
tls-checktrust gnutls-verify-error
|
||||
tls-program '("gnutls-cli --x509cafile %t -p %p %h"
|
||||
;; Emacs is built with `gnutls' by default, so `tls-program' would not be
|
||||
;; used in that case. Otherwise, people have reasons to not go with
|
||||
;; `gnutls', we use `openssl' instead. For more details, see
|
||||
;; https://redd.it/8sykl1
|
||||
tls-program '("openssl s_client -connect %h:%p -CAfile %t -nbio -no_ssl3 -no_tls1 -no_tls1_1 -ign_eof"
|
||||
"gnutls-cli -p %p --dh-bits=3072 --ocsp --x509cafile=%t \
|
||||
--strict-tofu --priority='SECURE192:+SECURE128:-VERS-ALL:+VERS-TLS1.2:+VERS-TLS1.3' %h"
|
||||
;; compatibility fallbacks
|
||||
"gnutls-cli -p %p %h"
|
||||
"openssl s_client -connect %h:%p -no_ssl2 -no_ssl3 -ign_eof"))
|
||||
"gnutls-cli -p %p %h"))
|
||||
|
||||
;; Emacs stores authinfo in HOME and in plaintext. Let's not do that, mkay? This
|
||||
;; file usually stores usernames, passwords, and other such treasures for the
|
||||
;; Emacs stores `authinfo' in $HOME and in plain-text. Let's not do that, mkay?
|
||||
;; This file stores usernames, passwords, and other such treasures for the
|
||||
;; aspiring malicious third party.
|
||||
(setq auth-sources (list (expand-file-name "authinfo.gpg" doom-etc-dir)
|
||||
(setq auth-sources (list (concat doom-etc-dir "authinfo.gpg")
|
||||
"~/.authinfo.gpg"))
|
||||
|
||||
;; Emacs on Windows frequently confuses HOME (C:\Users\<NAME>) and APPDATA,
|
||||
;; causing `abbreviate-home-dir' to produce incorrect paths.
|
||||
(when IS-WINDOWS
|
||||
(setq abbreviated-home-dir "\\`'"))
|
||||
|
||||
;; Don't litter `doom-emacs-dir'
|
||||
;; Don't litter `doom-emacs-dir'. We don't use `no-littering' because it's a
|
||||
;; mote too opinionated for our needs.
|
||||
(setq abbrev-file-name (concat doom-local-dir "abbrev.el")
|
||||
async-byte-compile-log-file (concat doom-etc-dir "async-bytecomp.log")
|
||||
bookmark-default-file (concat doom-etc-dir "bookmarks")
|
||||
custom-file (concat doom-private-dir "init.el")
|
||||
custom-file (concat doom-private-dir "config.el")
|
||||
custom-theme-directory (concat doom-private-dir "themes/")
|
||||
desktop-dirname (concat doom-etc-dir "desktop")
|
||||
desktop-base-file-name "autosave"
|
||||
desktop-base-lock-name "autosave-lock"
|
||||
pcache-directory (concat doom-cache-dir "pcache/")
|
||||
request-storage-directory (concat doom-cache-dir "request")
|
||||
server-auth-dir (concat doom-cache-dir "server/")
|
||||
shared-game-score-directory (concat doom-etc-dir "shared-game-score/")
|
||||
tramp-auto-save-directory (concat doom-cache-dir "tramp-auto-save/")
|
||||
tramp-backup-directory-alist backup-directory-alist
|
||||
@@ -227,13 +253,21 @@ users).")
|
||||
:override #'emacs-session-filename
|
||||
(concat doom-cache-dir "emacs-session." session-id))
|
||||
|
||||
(defadvice! doom--save-enabled-commands-to-doomdir-a (orig-fn &rest args)
|
||||
"When enabling a disabled command, the `put' call is written to
|
||||
~/.emacs.d/init.el, which causes issues for Doom, so write it to the user's
|
||||
config.el instead."
|
||||
:around #'en/disable-command
|
||||
(let ((user-init-file custom-file))
|
||||
(apply orig-fn args)))
|
||||
|
||||
|
||||
;;
|
||||
;;; Optimizations
|
||||
|
||||
;; Disable bidirectional text rendering for a modest performance boost. Of
|
||||
;; course, this renders Emacs unable to detect/display right-to-left languages
|
||||
;; (sorry!), but for us left-to-right language speakers/writers, it's a boon.
|
||||
;; Disable bidirectional text rendering for a modest performance boost. I've set
|
||||
;; this to `nil' in the past, but the `bidi-display-reordering's docs say that
|
||||
;; is an undefined state and suggest this to be just as good:
|
||||
(setq-default bidi-display-reordering 'left-to-right
|
||||
bidi-paragraph-direction 'left-to-right)
|
||||
|
||||
@@ -243,7 +277,8 @@ users).")
|
||||
(setq highlight-nonselected-windows nil)
|
||||
|
||||
;; More performant rapid scrolling over unfontified regions. May cause brief
|
||||
;; spells of inaccurate fontification immediately after scrolling.
|
||||
;; spells of inaccurate syntax highlighting right after scrolling, which should
|
||||
;; quickly self-correct.
|
||||
(setq fast-but-imprecise-scrolling t)
|
||||
|
||||
;; Resizing the Emacs frame can be a terribly expensive part of changing the
|
||||
@@ -254,30 +289,42 @@ users).")
|
||||
;; Don't ping things that look like domain names.
|
||||
(setq ffap-machine-p-known 'reject)
|
||||
|
||||
;; Font compacting can be terribly expensive, especially for rendering icon
|
||||
;; fonts on Windows. Whether it has a notable affect on Linux and Mac hasn't
|
||||
;; been determined, but we inhibit it there anyway.
|
||||
(setq inhibit-compacting-font-caches t)
|
||||
|
||||
;; Performance on Windows is considerably worse than elsewhere, especially if
|
||||
;; WSL is involved. We'll need everything we can get.
|
||||
(when IS-WINDOWS
|
||||
;; Reduce the workload when doing file IO
|
||||
(setq w32-get-true-file-attributes nil)
|
||||
|
||||
;; Font compacting can be terribly expensive, especially for rendering icon
|
||||
;; fonts on Windows. Whether it has a noteable affect on Linux and Mac hasn't
|
||||
;; been determined.
|
||||
(setq inhibit-compacting-font-caches t))
|
||||
(setq w32-get-true-file-attributes nil ; slightly faster IO
|
||||
w32-pipe-read-delay 0 ; faster ipc
|
||||
w32-pipe-buffer-size (* 64 1024))) ; read more at a time (was 4K)
|
||||
|
||||
;; Remove command line options that aren't relevant to our current OS; means
|
||||
;; slightly less to process at startup.
|
||||
(unless IS-MAC (setq command-line-ns-option-alist nil))
|
||||
(unless IS-LINUX (setq command-line-x-option-alist nil))
|
||||
|
||||
;; Delete files to trash on macOS, as an extra layer of precaution against
|
||||
;; accidentally deleting wanted files.
|
||||
(setq delete-by-moving-to-trash IS-MAC)
|
||||
|
||||
;; Adopt a sneaky garbage collection strategy of waiting until idle time to
|
||||
;; collect; staving off the collector while the user is working.
|
||||
(when doom-interactive-mode
|
||||
(add-transient-hook! 'pre-command-hook (gcmh-mode +1))
|
||||
(with-eval-after-load 'gcmh
|
||||
(setq gcmh-idle-delay 10
|
||||
gcmh-verbose doom-debug-mode)
|
||||
(add-hook 'focus-out-hook #'gcmh-idle-garbage-collect)))
|
||||
(setq gcmh-idle-delay 5
|
||||
gcmh-high-cons-threshold (* 16 1024 1024) ; 16mb
|
||||
gcmh-verbose doom-debug-p)
|
||||
|
||||
;; HACK `tty-run-terminal-initialization' is *tremendously* slow for some
|
||||
;; reason. Disabling it completely could have many side-effects, so we
|
||||
;; defer it until later, at which time it (somehow) runs very quickly.
|
||||
(unless (daemonp)
|
||||
(advice-add #'tty-run-terminal-initialization :override #'ignore)
|
||||
(add-hook! 'window-setup-hook
|
||||
(defun doom-init-tty-h ()
|
||||
(advice-remove #'tty-run-terminal-initialization #'ignore)
|
||||
(tty-run-terminal-initialization (selected-frame) nil t))))
|
||||
|
||||
|
||||
;;
|
||||
@@ -290,18 +337,14 @@ users).")
|
||||
"Run MODE-local-vars-hook after local variables are initialized."
|
||||
(run-hook-wrapped (intern-soft (format "%s-local-vars-hook" major-mode))
|
||||
#'doom-try-run-hook))
|
||||
(add-hook 'hack-local-variables-hook #'doom-run-local-var-hooks-h)
|
||||
|
||||
;; If the user has disabled `enable-local-variables', then
|
||||
;; `hack-local-variables-hook' is never triggered, so we trigger it at the end
|
||||
;; of `after-change-major-mode-hook':
|
||||
(defun doom-run-local-var-hooks-if-necessary-h ()
|
||||
(defun doom-run-local-var-hooks-maybe-h ()
|
||||
"Run `doom-run-local-var-hooks-h' if `enable-local-variables' is disabled."
|
||||
(unless enable-local-variables
|
||||
(doom-run-local-var-hooks-h)))
|
||||
(add-hook 'after-change-major-mode-hook
|
||||
#'doom-run-local-var-hooks-if-necessary-h
|
||||
'append)
|
||||
|
||||
|
||||
;;
|
||||
@@ -326,21 +369,24 @@ If you want to disable incremental loading altogether, either remove
|
||||
`doom-incremental-first-idle-timer' to nil. Incremental loading does not occur
|
||||
in daemon sessions (they are loaded immediately at startup).")
|
||||
|
||||
(defvar doom-incremental-first-idle-timer 2
|
||||
(defvar doom-incremental-first-idle-timer 2.0
|
||||
"How long (in idle seconds) until incremental loading starts.
|
||||
|
||||
Set this to nil to disable incremental loading.")
|
||||
|
||||
(defvar doom-incremental-idle-timer 1.5
|
||||
(defvar doom-incremental-idle-timer 0.75
|
||||
"How long (in idle seconds) in between incrementally loading packages.")
|
||||
|
||||
(defvar doom-incremental-load-immediately (daemonp)
|
||||
"If non-nil, load all incrementally deferred packages immediately at startup.")
|
||||
|
||||
(defun doom-load-packages-incrementally (packages &optional now)
|
||||
"Registers PACKAGES to be loaded incrementally.
|
||||
|
||||
If NOW is non-nil, load PACKAGES incrementally, in `doom-incremental-idle-timer'
|
||||
intervals."
|
||||
(if (not now)
|
||||
(nconc doom-incremental-packages packages)
|
||||
(appendq! doom-incremental-packages packages)
|
||||
(while packages
|
||||
(let ((req (pop packages)))
|
||||
(unless (featurep req)
|
||||
@@ -357,7 +403,7 @@ intervals."
|
||||
t)
|
||||
(push req packages))
|
||||
((error debug)
|
||||
(message "Failed to load '%s' package incrementally, because: %s"
|
||||
(message "Failed to load %S package incrementally, because: %s"
|
||||
req e)))
|
||||
(if (not packages)
|
||||
(doom-log "Finished incremental loading")
|
||||
@@ -370,33 +416,32 @@ intervals."
|
||||
"Begin incrementally loading packages in `doom-incremental-packages'.
|
||||
|
||||
If this is a daemon session, load them all immediately instead."
|
||||
(if (daemonp)
|
||||
(if doom-incremental-load-immediately
|
||||
(mapc #'require (cdr doom-incremental-packages))
|
||||
(when (integerp doom-incremental-first-idle-timer)
|
||||
(when (numberp doom-incremental-first-idle-timer)
|
||||
(run-with-idle-timer doom-incremental-first-idle-timer
|
||||
nil #'doom-load-packages-incrementally
|
||||
(cdr doom-incremental-packages) t))))
|
||||
|
||||
(add-hook 'emacs-startup-hook #'doom-load-packages-incrementally-h)
|
||||
|
||||
;;
|
||||
;;; Custom hooks
|
||||
|
||||
(defvar doom-first-input-hook nil
|
||||
"Transient hooks run before the first user input.")
|
||||
|
||||
(defvar doom-first-file-hook nil
|
||||
"Transient hooks run before the first interactively opened file.")
|
||||
|
||||
(defvar doom-first-buffer-hook nil
|
||||
"Transient hooks run before the first interactively opened buffer.")
|
||||
|
||||
|
||||
;;
|
||||
;;; Bootstrap helpers
|
||||
|
||||
(defun doom-try-run-hook (hook)
|
||||
"Run HOOK (a hook function) with better error handling.
|
||||
Meant to be used with `run-hook-wrapped'."
|
||||
(doom-log "Running doom hook: %s" hook)
|
||||
(condition-case e
|
||||
(funcall hook)
|
||||
((debug error)
|
||||
(signal 'doom-hook-error (list hook e))))
|
||||
;; return nil so `run-hook-wrapped' won't short circuit
|
||||
nil)
|
||||
|
||||
(defun doom-display-benchmark-h (&optional return-p)
|
||||
"Display a benchmark, showing number of packages and modules, and how quickly
|
||||
they were loaded at startup.
|
||||
"Display a benchmark including number of packages and modules loaded.
|
||||
|
||||
If RETURN-P, return the message as a string instead of displaying it."
|
||||
(funcall (if return-p #'format #'message)
|
||||
@@ -407,58 +452,13 @@ If RETURN-P, return the message as a string instead of displaying it."
|
||||
(setq doom-init-time
|
||||
(float-time (time-subtract (current-time) before-init-time))))))
|
||||
|
||||
(defun doom-load-autoloads-file (file &optional noerror)
|
||||
"Tries to load FILE (an autoloads file).
|
||||
Return t on success, nil otherwise (but logs a warning)."
|
||||
(condition-case e
|
||||
(load (substring file 0 -3) noerror 'nomessage)
|
||||
((debug error)
|
||||
(message "Autoload file error: %s -> %s" (file-name-nondirectory file) e)
|
||||
nil)))
|
||||
|
||||
(defun doom-load-envvars-file (file &optional noerror)
|
||||
"Read and set envvars from FILE.
|
||||
If NOERROR is non-nil, don't throw an error if the file doesn't exist or is
|
||||
unreadable. Returns the names of envvars that were changed."
|
||||
(if (not (file-readable-p file))
|
||||
(unless noerror
|
||||
(signal 'file-error (list "Couldn't read envvar file" file)))
|
||||
(let (envvars environment)
|
||||
(with-temp-buffer
|
||||
(save-excursion
|
||||
(insert "\n")
|
||||
(insert-file-contents file))
|
||||
(while (re-search-forward "\n *\\([^#= \n]*\\)=" nil t)
|
||||
(push (match-string 1) envvars)
|
||||
(push (buffer-substring
|
||||
(match-beginning 1)
|
||||
(1- (or (save-excursion
|
||||
(when (re-search-forward "^\\([^= ]+\\)=" nil t)
|
||||
(line-beginning-position)))
|
||||
(point-max))))
|
||||
environment)))
|
||||
(when environment
|
||||
(setq process-environment
|
||||
(append (nreverse environment) process-environment)
|
||||
exec-path
|
||||
(if (member "PATH" envvars)
|
||||
(append (parse-colon-path (getenv "PATH"))
|
||||
(list exec-directory))
|
||||
exec-path)
|
||||
shell-file-name
|
||||
(if (member "SHELL" envvars)
|
||||
(setq shell-file-name
|
||||
(or (getenv "SHELL") shell-file-name))
|
||||
shell-file-name))
|
||||
envvars))))
|
||||
|
||||
(defun doom-initialize (&optional force-p noerror)
|
||||
(defun doom-initialize (&optional force-p)
|
||||
"Bootstrap Doom, if it hasn't already (or if FORCE-P is non-nil).
|
||||
|
||||
The bootstrap process ensures that the essential directories exist, all core
|
||||
packages are installed, `doom-autoload-file' and `doom-package-autoload-file'
|
||||
exist and are loaded, and that `core-packages' is auto-loaded when `package' or
|
||||
`straight' are.
|
||||
The bootstrap process ensures that everything Doom needs to run is set up;
|
||||
essential directories exist, core packages are installed, `doom-autoload-file'
|
||||
is loaded (failing if it isn't), that all the needed hooks are in place, and
|
||||
that `core-packages' will load when `package' or `straight' is used.
|
||||
|
||||
The overall load order of Doom is as follows:
|
||||
|
||||
@@ -470,7 +470,7 @@ The overall load order of Doom is as follows:
|
||||
Module config.el files
|
||||
~/.doom.d/config.el
|
||||
`doom-init-modules-hook'
|
||||
`after-init-hook'
|
||||
`doom-after-init-modules-hook' (`after-init-hook')
|
||||
`emacs-startup-hook'
|
||||
`doom-init-ui-hook'
|
||||
`window-setup-hook'
|
||||
@@ -480,74 +480,67 @@ for a list of all recognized module trees. Order defines precedence (from most
|
||||
to least)."
|
||||
(when (or force-p (not doom-init-p))
|
||||
(setq doom-init-p t)
|
||||
(doom-log "Initializing Doom")
|
||||
|
||||
;; Reset as much state as possible, so `doom-initialize' can be treated like
|
||||
;; a reset function. Particularly useful for reloading the config.
|
||||
;; a reset function. e.g. when reloading the config.
|
||||
(setq-default exec-path doom--initial-exec-path
|
||||
load-path doom--initial-load-path
|
||||
process-environment doom--initial-process-environment)
|
||||
|
||||
;; Load shell environment, optionally generated from 'doom env'. No need to
|
||||
;; do so if we're in terminal Emacs, because Emacs will correctly inherit
|
||||
;; Doom caches a lot of information in `doom-autoload-file'. Module and
|
||||
;; package autoloads, autodefs like `set-company-backend!', and variables
|
||||
;; like `doom-modules', `doom-disabled-packages', `load-path',
|
||||
;; `auto-mode-alist', and `Info-directory-list'. etc. Compiling them into
|
||||
;; one place is a big reduction in startup time.
|
||||
(condition-case e
|
||||
;; Avoid `file-name-sans-extension' for premature optimization reasons.
|
||||
;; `string-remove-suffix' is cheaper because it performs no file sanity
|
||||
;; checks; just plain ol' string manipulation.
|
||||
(load (string-remove-suffix ".el" doom-autoload-file)
|
||||
nil 'nomessage)
|
||||
(file-missing
|
||||
;; If the autoloads file fails to load then the user forgot to sync, or
|
||||
;; aborted a doom command midway!
|
||||
(signal 'doom-error
|
||||
(list "Doom is in an incomplete state"
|
||||
"run 'bin/doom sync' on the command line to repair it"))))
|
||||
|
||||
;; Load shell environment, optionally generated from 'doom env'. No need
|
||||
;; to do so if we're in terminal Emacs, where Emacs correctly inherits
|
||||
;; your shell environment there.
|
||||
(when (and (or (display-graphic-p)
|
||||
(daemonp))
|
||||
(file-exists-p doom-env-file))
|
||||
(doom-load-envvars-file doom-env-file))
|
||||
(if (or (display-graphic-p)
|
||||
(daemonp))
|
||||
(doom-load-envvars-file doom-env-file 'noerror))
|
||||
|
||||
;; Loads `use-package' and all the helper macros modules (and users) can use
|
||||
;; to configure their packages.
|
||||
(require 'core-modules)
|
||||
(let (;; `doom-autoload-file' tells Emacs where to load all its functions
|
||||
;; from. This includes everything in core/autoload/*.el and autoload
|
||||
;; files in enabled modules.
|
||||
(core-autoloads-p (doom-load-autoloads-file doom-autoload-file noerror))
|
||||
;; Loads `doom-package-autoload-file', which loads a concatenated
|
||||
;; package autoloads file which caches `load-path', `auto-mode-alist',
|
||||
;; `Info-directory-list', and `doom-disabled-packages'. A big
|
||||
;; reduction in startup time.
|
||||
(pkg-autoloads-p (doom-load-autoloads-file doom-package-autoload-file noerror)))
|
||||
|
||||
(if (and core-autoloads-p pkg-autoloads-p (not force-p))
|
||||
;; In case we want to use package.el or straight via M-x
|
||||
(progn
|
||||
(with-eval-after-load 'package
|
||||
(require 'core-packages))
|
||||
(with-eval-after-load 'straight
|
||||
(require 'core-packages)
|
||||
(doom-initialize-packages)))
|
||||
;; There's a chance the user will want to use package.el or straight later
|
||||
;; on in this interactive session. If that's the case, make sure they're
|
||||
;; properly initialized when they do.
|
||||
(autoload 'doom-initialize-packages "core-packages")
|
||||
(autoload 'doom-initialize-core-packages "core-packages")
|
||||
(with-eval-after-load 'package (require 'core-packages))
|
||||
(with-eval-after-load 'straight (doom-initialize-packages))
|
||||
|
||||
;; Eagerly load these libraries because we may be in a session that hasn't been
|
||||
;; fully initialized (e.g. where autoloads files haven't been generated or
|
||||
;; `load-path' populated).
|
||||
(mapc (doom-rpartial #'load nil (not doom-debug-mode) 'nosuffix)
|
||||
(file-expand-wildcards (concat doom-core-dir "autoload/*.el")))
|
||||
;; Bootstrap the interactive session
|
||||
(add-hook! 'window-setup-hook
|
||||
(add-hook 'hack-local-variables-hook #'doom-run-local-var-hooks-h)
|
||||
(add-hook 'after-change-major-mode-hook #'doom-run-local-var-hooks-maybe-h 'append)
|
||||
(add-hook 'doom-first-input-hook #'gcmh-mode)
|
||||
(add-hook-trigger! 'doom-first-input-hook 'pre-command-hook)
|
||||
(add-hook-trigger! 'doom-first-file-hook 'after-find-file 'dired-initial-position-hook)
|
||||
(add-hook-trigger! 'doom-first-buffer-hook 'after-find-file 'doom-switch-buffer-hook))
|
||||
(add-hook 'emacs-startup-hook #'doom-load-packages-incrementally-h)
|
||||
(add-hook 'window-setup-hook #'doom-display-benchmark-h 'append)
|
||||
(if doom-debug-p (doom-debug-mode +1))
|
||||
|
||||
;; Create all our core directories to quell file errors
|
||||
(dolist (dir (list doom-local-dir
|
||||
doom-etc-dir
|
||||
doom-cache-dir))
|
||||
(unless (file-directory-p dir)
|
||||
(make-directory dir 'parents)))
|
||||
;; Load core/core-*.el, the user's private init.el and their config.el
|
||||
(doom-initialize-modules force-p))
|
||||
|
||||
;; Ensure the package management system (and straight) are ready for
|
||||
;; action (and all core packages/repos are installed)
|
||||
(require 'core-packages)
|
||||
(doom-initialize-packages force-p))
|
||||
|
||||
(unless (or (and core-autoloads-p pkg-autoloads-p)
|
||||
noerror)
|
||||
(unless core-autoloads-p
|
||||
(warn "Your Doom core autoloads file is missing"))
|
||||
(unless pkg-autoloads-p
|
||||
(warn "Your package autoloads file is missing"))
|
||||
(signal 'doom-autoload-error (list "Run `bin/doom refresh' to generate them"))))
|
||||
t))
|
||||
|
||||
(defun doom-initialize-core ()
|
||||
"Load Doom's core files for an interactive session."
|
||||
(require 'core-keybinds)
|
||||
(require 'core-ui)
|
||||
(require 'core-projects)
|
||||
(require 'core-editor))
|
||||
doom-init-p)
|
||||
|
||||
(provide 'core)
|
||||
;;; core.el ends here
|
||||
|
||||
@@ -2,39 +2,60 @@
|
||||
;;; core/packages.el
|
||||
|
||||
;; core.el
|
||||
(package! dotenv-mode)
|
||||
(package! auto-minor-mode)
|
||||
(package! auto-minor-mode :pin "17cfa1b54800fdef2975c0c0531dad34846a5065")
|
||||
(package! gcmh :pin "b1bde5089169a74f62033d027e06e98cbeedd43f")
|
||||
|
||||
;; core-packages.el
|
||||
(package! straight
|
||||
:type 'core
|
||||
:recipe `(:host github
|
||||
:repo "raxod502/straight.el"
|
||||
:branch ,straight-repository-branch
|
||||
:local-repo "straight.el"
|
||||
:files ("straight*.el")
|
||||
:no-build t)
|
||||
:pin "09cfa1b344cbeeea7da2e075df7c19262fb2b9e6")
|
||||
|
||||
;; core-modules.el
|
||||
(package! use-package
|
||||
:type 'core
|
||||
:pin "d2640fec376a8458a669e7526e63e5870d875118")
|
||||
|
||||
;; core-ui.el
|
||||
(package! all-the-icons)
|
||||
(package! hide-mode-line)
|
||||
(package! highlight-numbers)
|
||||
(package! rainbow-delimiters)
|
||||
(package! restart-emacs)
|
||||
(package! all-the-icons :pin "ed8e44de4fa601309d2bba902c3b37cb73e4daa0")
|
||||
(package! hide-mode-line :pin "88888825b5b27b300683e662fa3be88d954b1cea")
|
||||
(package! highlight-numbers :pin "8b4744c7f46c72b1d3d599d4fb75ef8183dee307")
|
||||
(package! rainbow-delimiters :pin "5125f4e47604ad36c3eb4706310fcafac729ca8c")
|
||||
(package! restart-emacs :pin "9aa90d3df9e08bc420e1c9845ee3ff568e911bd9")
|
||||
|
||||
;; core-editor.el
|
||||
(package! better-jumper)
|
||||
(package! dtrt-indent)
|
||||
(package! helpful)
|
||||
(package! ns-auto-titlebar :ignore (not IS-MAC))
|
||||
(package! pcre2el)
|
||||
(package! smartparens)
|
||||
(package! better-jumper :pin "6d240032ca213ccb3347e25f26c29b6822bf03a7")
|
||||
(package! dtrt-indent :pin "50c440c80e0d15303d8ab543bce4c56e9c2bf407")
|
||||
(package! helpful :pin "c0662aa07266fe204f4e6d72ccaa6af089400556")
|
||||
(when IS-MAC
|
||||
(package! ns-auto-titlebar :pin "1efc30d38509647b417f05587fd7003457719256"))
|
||||
(package! pcre2el :pin "0b5b2a2c173aab3fd14aac6cf5e90ad3bf58fa7d")
|
||||
(package! smartparens :pin "555626a43f9bb1985aa9a0eb675f2b88b29702c8")
|
||||
(package! so-long
|
||||
:built-in 'prefer
|
||||
:built-in 'prefer ; included in Emacs 27+
|
||||
;; REVIEW so-long is slated to be published to ELPA eventually, but until then
|
||||
;; I've created my own mirror for it because git.savannah.gnu.org runs on a
|
||||
;; potato.
|
||||
:recipe (:host github :repo "hlissner/emacs-so-long"))
|
||||
(package! undo-tree
|
||||
;; Version 0.6.5 is on ELPA which lacks a fix we need, so we install 0.6.6
|
||||
;; from emacsmirror/undo-tree instead.
|
||||
:recipe (:host github :repo "emacsmirror/undo-tree"))
|
||||
(package! ws-butler)
|
||||
(package! xclip)
|
||||
;; I've created my own mirror for it because git.savannah.gnu.org runs
|
||||
;; on a potato.
|
||||
:recipe (:host github :repo "hlissner/emacs-so-long")
|
||||
:pin "ed666b0716f60e8988c455804de24b55919e71ca")
|
||||
(package! ws-butler
|
||||
;; Use my fork of ws-butler, which has a few choice improvements and
|
||||
;; optimizations (the original has been abandoned).
|
||||
:recipe (:host github :repo "hlissner/ws-butler")
|
||||
:pin "2bb49d3ee7d2cba133bc7e9cdac416cd1c5e4fe0")
|
||||
(unless IS-WINDOWS
|
||||
(package! clipetty
|
||||
:recipe (:host github :repo "spudlyo/clipetty")
|
||||
:pin "01b39044b9b65fa4ea7d3166f8b1ffab6f740362"))
|
||||
|
||||
;; core-projects.el
|
||||
(package! projectile)
|
||||
(package! projectile :pin "7e552b6d876014ca5b4609318ca8a202b2a89014")
|
||||
|
||||
;; core-keybinds.el
|
||||
(package! general)
|
||||
(package! which-key)
|
||||
(package! general :pin "a0b17d207badf462311b2eef7c065b884462cb7c")
|
||||
(package! which-key :pin "8b49ae978cceca65967f3544c236f32964ddbed0")
|
||||
|
||||
@@ -1,25 +1,19 @@
|
||||
Before you doom yourself, there are a few things you should know:
|
||||
But before you doom yourself, here are some things you should know:
|
||||
|
||||
1. Whenever you edit your doom! block in ~/.doom.d/init.el or modify your
|
||||
modules, run:
|
||||
1. Don't forget to run 'doom sync', then restart Emacs, after modifying
|
||||
~/.doom.d/init.el or ~/.doom.d/packages.el.
|
||||
|
||||
bin/doom refresh
|
||||
This command ensures needed packages are installed, orphaned packages are
|
||||
removed, and your autoloads/cache files are up to date. When in doubt, run
|
||||
'doom sync'!
|
||||
|
||||
This will ensure all needed packages are installed, all orphaned packages are
|
||||
removed, and your autoloads files are up to date. This is important! If you
|
||||
forget to do this you will get errors!
|
||||
2. If something goes wrong, run `doom doctor`. It diagnoses common issues with
|
||||
your environment and setup, and may offer clues about what is wrong.
|
||||
|
||||
2. If something inexplicably goes wrong, try `bin/doom doctor`
|
||||
3. Use 'doom upgrade' to update Doom. Doing it any other way will require
|
||||
additional steps. Run 'doom help upgrade' to understand those extra steps.
|
||||
|
||||
This will diagnose common issues with your environment and setup, and may
|
||||
give you clues about what is wrong.
|
||||
|
||||
3. Use `bin/doom upgrade` to update Doom. Doing it any other way may require
|
||||
additional work. When in doubt, run `bin/doom refresh`.
|
||||
|
||||
4. Check out `bin/doom help` to see what else `bin/doom` can do (and it is
|
||||
recommended you add ~/.emacs.d/bin to your PATH).
|
||||
|
||||
5. You can find Doom's documentation via `M-x doom/help` or `SPC h D`.
|
||||
4. Access Doom's documentation from within Emacs via 'SPC h D' or 'C-h D' (or
|
||||
'M-x doom/help')
|
||||
|
||||
Have fun!
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
;; -*- lexical-binding: t; no-byte-compile: t; -*-
|
||||
;;; core/test/helpers.el
|
||||
|
||||
(eval-and-compile
|
||||
(setq doom-interactive-mode 'test)
|
||||
(doom-initialize 'force 'noerror)
|
||||
(require 'buttercup)
|
||||
(setq split-width-threshold 0
|
||||
split-height-threshold 0
|
||||
window-min-width 0
|
||||
window-min-height 0))
|
||||
|
||||
;;
|
||||
;;; Buttercup extensions
|
||||
|
||||
(buttercup-define-matcher-for-binary-function :to-equal-file file-equal-p)
|
||||
|
||||
(buttercup-define-matcher :to-expand-into (form expected)
|
||||
(cl-destructuring-bind (form expected)
|
||||
(mapcar #'funcall (list form expected))
|
||||
(let ((expanded (macroexpand-1 form)))
|
||||
(if (equal expanded expected)
|
||||
(cons t (format "Expected `%S' to not expand to `%S'"
|
||||
form expected))
|
||||
(cons nil (format "Expected `%S' to not expand to `%S', but got `%S' instead"
|
||||
form expected expanded))))))
|
||||
|
||||
(buttercup-define-matcher :to-output (form &optional expected-output)
|
||||
(let ((expected-output (and (functionp expected-output)
|
||||
(funcall expected-output)))
|
||||
output)
|
||||
(with-current-buffer (get-buffer "*Messages*")
|
||||
(let ((standard-output (current-buffer))
|
||||
(start (point)))
|
||||
(let ((inhibit-message t))
|
||||
(funcall form))
|
||||
(setq output (buffer-substring-no-properties start (point-max)))
|
||||
(with-silent-modifications (erase-buffer))))
|
||||
(cond ((null expected-output)
|
||||
(if (string-empty-p output)
|
||||
(cons nil (format "Expected output %S, but got none"
|
||||
expected-output))
|
||||
(cons t (format "Expected no output, but got %S"
|
||||
output))))
|
||||
((not (equal expected-output output))
|
||||
(cons nil (format "Expected output %S, but got %S instead"
|
||||
expected-output output)))
|
||||
((cons t (format "Expected to not get %S as output"
|
||||
expected-output))))))
|
||||
|
||||
(buttercup-define-matcher :to-contain-items (items expected)
|
||||
(cl-destructuring-bind (items expected)
|
||||
(mapcar #'funcall (list items expected))
|
||||
(if-let (missing (cl-set-difference expected items))
|
||||
(cons nil (format "Expected list to contain %S, but it was missing %S"
|
||||
expected missing))
|
||||
(cons t (format "Expected list to not contain %S, but it did: %S"
|
||||
expected items)))))
|
||||
|
||||
|
||||
;;
|
||||
;;; Helper macros
|
||||
|
||||
(defmacro insert!! (&rest text)
|
||||
"Insert TEXT in buffer, then move cursor to last {0} marker."
|
||||
`(progn
|
||||
(insert ,@text)
|
||||
(when (search-backward "{0}" nil t)
|
||||
(replace-match "" t t))))
|
||||
@@ -1,17 +0,0 @@
|
||||
;;; core/test/init.el -*- lexical-binding: t; no-byte-compile: t; -*-
|
||||
|
||||
;; An init.el for our unit test suites. Do not use this!
|
||||
|
||||
(doom! :completion
|
||||
company
|
||||
:ui
|
||||
doom-dashboard
|
||||
popup
|
||||
workspaces
|
||||
:editor
|
||||
evil
|
||||
:tools
|
||||
pass
|
||||
:lang
|
||||
org
|
||||
web)
|
||||
@@ -1,4 +0,0 @@
|
||||
;; -*- no-byte-compile: t; -*-
|
||||
;;; core/test/packages.el
|
||||
|
||||
(package! buttercup)
|
||||
@@ -3,9 +3,9 @@
|
||||
|
||||
(describe "core/autoload/format"
|
||||
(describe "format!"
|
||||
:var (doom-format-backend)
|
||||
:var (doom-output-backend)
|
||||
(before-all
|
||||
(setq doom-format-backend 'ansi))
|
||||
(setq doom-output-backend 'ansi))
|
||||
|
||||
(it "should be a drop-in replacement for `format'"
|
||||
(expect (format! "Hello %s" "World")
|
||||
@@ -16,7 +16,7 @@
|
||||
:to-equal "[31mHello World[0m"))
|
||||
|
||||
(it "supports text properties in interactive sessions"
|
||||
(let ((doom-format-backend 'text-properties))
|
||||
(let ((doom-output-backend 'text-properties))
|
||||
(expect (get-text-property 0 'face (format! (red "Hello %s") "World"))
|
||||
:to-equal (list :foreground (face-foreground 'term-color-red)))))
|
||||
|
||||
|
||||
@@ -101,12 +101,6 @@
|
||||
(expect (appendq! list '(d e f))
|
||||
:to-equal '(a b c d e f)))))
|
||||
|
||||
(describe "nconcq!"
|
||||
(it "nconc's a list to a list symbol"
|
||||
(let ((list '(a b c)))
|
||||
(expect (nconcq! list '(d e f))
|
||||
:to-equal '(a b c d e f)))))
|
||||
|
||||
(describe "delq!"
|
||||
(it "delete's a symbol from a list"
|
||||
(let ((list '(a b c)))
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
;;; core/test/test-core.el
|
||||
|
||||
(describe "core"
|
||||
:var (doom-interactive-mode)
|
||||
:var (doom-interactive-p)
|
||||
(before-each
|
||||
(setq doom-interactive-mode nil))
|
||||
(setq doom-interactive-p nil))
|
||||
|
||||
(describe "initialization"
|
||||
(describe "doom-initialize"
|
||||
@@ -33,7 +33,7 @@
|
||||
(expect 'doom-initialize-packages :to-have-been-called))
|
||||
|
||||
(it "doesn't initialize packages if core autoload file was loaded"
|
||||
(let ((doom-interactive-mode t))
|
||||
(let ((doom-interactive-p t))
|
||||
(spy-on 'doom-load-autoloads-file :and-return-value t)
|
||||
(doom-initialize nil 'noerror)
|
||||
(expect 'doom-load-autoloads-file :to-have-been-called-with doom-package-autoload-file)
|
||||
|
||||
@@ -18,8 +18,8 @@ It is integrated into Helpful, in Doom.
|
||||
- [[#disable-packages][disable-packages!]]
|
||||
- [[#doom][doom!]]
|
||||
- [[#file-exists-p][file-exists-p!]]
|
||||
- [[#lambda][lambda!]]
|
||||
- [[#lambda-1][lambda!!]]
|
||||
- [[#cmd][cmd!]]
|
||||
- [[#cmd-1][cmd!!]]
|
||||
- [[#letenv][letenv!]]
|
||||
- [[#load][load!]]
|
||||
- [[#map][map!]]
|
||||
@@ -28,11 +28,12 @@ It is integrated into Helpful, in Doom.
|
||||
- [[#prependq][prependq!]]
|
||||
- [[#quiet][quiet!]]
|
||||
- [[#remove-hook][remove-hook!]]
|
||||
- [[#setq][setq!]]
|
||||
- [[#setq-hook][setq-hook!]]
|
||||
- [[#unsetq-hook][unsetq-hook!]]
|
||||
- [[#use-package][use-package!]]
|
||||
- [[#interesting-snippets][Interesting snippets]]
|
||||
- [[#persist-emacs-initial-frame-size-across-sessions][Persist Emacs' initial frame size across sessions]]
|
||||
- [[#center-emacs-initial-frame-with-a-fixed-size][Center Emacs' initial frame with a fixed size]]
|
||||
- [[#persist-emacs-initial-frame-position-dimensions-andor-full-screen-state-across-sessions][Persist Emacs' initial frame position, dimensions and/or full-screen state across sessions]]
|
||||
- [[#update-cursor-shape-under-terminal-emacs][Update cursor shape under terminal Emacs]]
|
||||
|
||||
@@ -237,38 +238,30 @@ It is integrated into Helpful, in Doom.
|
||||
#+RESULTS:
|
||||
: /home/hlissner/.emacs.d/LICENSE
|
||||
|
||||
*** lambda!
|
||||
*** cmd!
|
||||
#+BEGIN_SRC elisp :eval no
|
||||
(map! "C-j" (lambda! (newline) (indent-according-to-mode)))
|
||||
|
||||
;; The `λ!' short-form alias exists. If you have the snippets module enabled and
|
||||
;; Doom's default snippets, the 'lam' snippet will expand into 'λ!'. Otherwise,
|
||||
;; you can use `lambda!'.
|
||||
(map! "C-j" (λ! (newline) (indent-according-to-mode)))
|
||||
(map! "C-j" (cmd! (newline) (indent-according-to-mode)))
|
||||
#+END_SRC
|
||||
*** lambda!!
|
||||
|
||||
*** cmd!!
|
||||
When ~newline~ is passed a numerical prefix argument (=C-u 5 M-x newline=), it
|
||||
inserts N newlines. We can use ~lambda!!~ to easily create a keybinds that bakes
|
||||
in the prefix arg into the command call:
|
||||
inserts N newlines. We can use ~cmd!!~ to easily create a keybinds that bakes in
|
||||
the prefix arg into the command call:
|
||||
|
||||
#+BEGIN_SRC elisp :eval no
|
||||
(map! "C-j" (lambda!! #'newline 5))
|
||||
|
||||
;; The `λ!!' short-form alias exists. If you have the snippets module enabled
|
||||
;; and Doom's default snippets, a 'lam' snippet is available to expand into
|
||||
;; 'λ!'. Otherwise, you can use `lambda!!'.
|
||||
(map! "C-j" (λ!! #'newline 5))
|
||||
(map! "C-j" (cmd!! #'newline 5))
|
||||
#+END_SRC
|
||||
|
||||
Or to create aliases for functions that behave differently:
|
||||
|
||||
#+BEGIN_SRC elisp :eval no
|
||||
(fset 'insert-5-newlines (lambda!! #'newline 5))
|
||||
(fset 'insert-5-newlines (cmd!! #'newline 5))
|
||||
|
||||
;; The equivalent of C-u M-x org-global-cycle, which resets the org document to
|
||||
;; its startup visibility settings.
|
||||
(fset 'org-reset-global-visibility (lambda!! #'org-global-cycle '(4))
|
||||
(fset 'org-reset-global-visibility (cmd!! #'org-global-cycle '(4))
|
||||
#+END_SRC
|
||||
|
||||
*** letenv!
|
||||
#+BEGIN_SRC elisp
|
||||
(letenv! (("SHELL" "/bin/sh"))
|
||||
@@ -387,7 +380,7 @@ These are side-by-side comparisons, showing how to bind keys with and without
|
||||
*** package!
|
||||
#+BEGIN_SRC elisp :eval no
|
||||
;; To install a package that can be found on ELPA or any of the sources
|
||||
;; specified in `doom-core-package-sources':
|
||||
;; specified in `straight-recipe-repositories':
|
||||
(package! evil)
|
||||
(package! js2-mode)
|
||||
(package! rainbow-delimiters)
|
||||
@@ -404,15 +397,12 @@ These are side-by-side comparisons, showing how to bind keys with and without
|
||||
;; you can tell the package manager not to clone the repo recursively:
|
||||
(package! ansible :recipe (:nonrecursive t))
|
||||
|
||||
;; To install a particular branch, commit or tag:
|
||||
(package! evil
|
||||
;; if :host and :fetcher aren't specified, the package manager will fall back
|
||||
;; to evil's default source provided by their (M)ELPA recipes:
|
||||
:recipe (:commit "e7bc39de2f961505e8e112da8c1b315ae8afce52"))
|
||||
|
||||
;; To pin a package to a specific commit:
|
||||
(package! evil :pin "e7bc39de2f9")
|
||||
;; ...or branch:
|
||||
(package! evil :recipe (:branch "stable"))
|
||||
|
||||
(package! evil :recipe (:tag "1.2.9"))
|
||||
;; To unpin a pinned package:
|
||||
(package! evil :pin nil)
|
||||
|
||||
;; If you share your config between two computers, and don't want bin/doom
|
||||
;; refresh to delete packages used only on one system, use :ignore
|
||||
@@ -473,6 +463,14 @@ These are side-by-side comparisons, showing how to bind keys with and without
|
||||
;; Removing arbitrary forms (must be exactly the same as the definition)
|
||||
(remove-hook! (one-mode second-mode) (setq v 5) (setq a 2))
|
||||
#+END_SRC
|
||||
*** setq!
|
||||
#+BEGIN_SRC elisp
|
||||
;; Each of these have a setter associated with them, which must be triggered in
|
||||
;; order for their new values to have an effect.
|
||||
(setq! evil-want-Y-yank-to-eol nil
|
||||
evil-want-C-u-scroll nil
|
||||
evil-want-C-d-scroll nil)
|
||||
#+END_SRC
|
||||
*** setq-hook!
|
||||
#+BEGIN_SRC elisp :eval no
|
||||
;; Set multiple variables after a hook
|
||||
@@ -515,21 +513,21 @@ These are side-by-side comparisons, showing how to bind keys with and without
|
||||
:defer-incrementally t)
|
||||
#+END_SRC
|
||||
* Interesting snippets
|
||||
** Persist Emacs' initial frame size across sessions
|
||||
** Center Emacs' initial frame with a fixed size
|
||||
#+BEGIN_SRC elisp
|
||||
(let ((display-height (display-pixel-height))
|
||||
(display-width (display-pixel-width)))
|
||||
(add-to-list 'initial-frame-alist
|
||||
`((left . ,(/ new-frame-width 2))
|
||||
(top . ,(/ new-frame-height 2))
|
||||
(width . ,(/ display-width 2))
|
||||
(height . ,(/ display-height 2)))))
|
||||
(pushnew! initial-frame-alist
|
||||
`(left . ,(/ display-width 2))
|
||||
`(top . ,(/ display-height 2))
|
||||
`(width . ,display-width)
|
||||
`(height . ,display-height)))
|
||||
#+END_SRC
|
||||
|
||||
** Persist Emacs' initial frame position, dimensions and/or full-screen state across sessions
|
||||
#+BEGIN_SRC elisp
|
||||
;; add to ~/.doom.d/config.el
|
||||
(when-let (dims (doom-cache-get 'last-frame-size))
|
||||
(when-let (dims (doom-store-get 'last-frame-size))
|
||||
(cl-destructuring-bind ((left . top) width height fullscreen) dims
|
||||
(setq initial-frame-alist
|
||||
(append initial-frame-alist
|
||||
@@ -540,7 +538,7 @@ These are side-by-side comparisons, showing how to bind keys with and without
|
||||
(fullscreen . ,fullscreen))))))
|
||||
|
||||
(defun save-frame-dimensions ()
|
||||
(doom-cache-set 'last-frame-size
|
||||
(doom-store-put 'last-frame-size
|
||||
(list (frame-position)
|
||||
(frame-width)
|
||||
(frame-height)
|
||||
@@ -567,3 +565,24 @@ than unwarranted characters.
|
||||
|
||||
Alternatively, an updated version exists at
|
||||
[[https://github.com/amosbird/evil-terminal-cursor-changer][amosbird/evil-terminal-cursor-changer]], with support for urxvt and tmux.
|
||||
|
||||
** Create a paste-transient-state to cycle through kill ring on paste
|
||||
Replaces the default evil-paste binding to paste then let you cycle through entries in your kill ring. Gives you more flexibility when copying to your clipboard, making edits, then deciding to paste after.
|
||||
|
||||
You will need to enable the `hydra` module first.
|
||||
|
||||
#+BEGIN_SRC elisp
|
||||
(defhydra hydra-paste (:color red
|
||||
:hint nil)
|
||||
"\n[%s(length kill-ring-yank-pointer)/%s(length kill-ring)] \
|
||||
[_C-j_/_C-k_] cycles through yanked text, [_p_/_P_] pastes the same text \
|
||||
above or below. Anything else exits."
|
||||
("C-j" evil-paste-pop)
|
||||
("C-k" evil-paste-pop-next)
|
||||
("p" evil-paste-after)
|
||||
("P" evil-paste-before))
|
||||
|
||||
(map! :nv "p" #'hydra-paste/evil-paste-after
|
||||
:nv "P" #'hydra-paste/evil-paste-before)
|
||||
#+END_SRC
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
#+TITLE: Contributing
|
||||
#+STARTUP: nofold
|
||||
|
||||
I can't say Doom Emacs is a one man show anymore. It wouldn't have gotten this
|
||||
far without the help of folks like you! Still, I struggle to maintain it all;
|
||||
especially the modules I do not use. If Doom has been useful to you, consider
|
||||
pitching in and helping me out.
|
||||
Doom Emacs is an active and ongoing project, maintained mostly by a single
|
||||
person, but includes the efforts of 200 contributors and growing. There is no
|
||||
shortage of things that need doing; bugs that need stomping, features that need
|
||||
implementing, and documentation that needs documenting. If Doom's been useful to
|
||||
you, convert some caffiene into code; it'd be a huge help!
|
||||
|
||||
Help can range from reporting bugs, proposing enhancements, submitting code and
|
||||
documentation, or just spreading the good word. To ensure no toes get stepped on
|
||||
or wires crossed, this guide was created to help you help us.
|
||||
You are welcome to [[https://discord.gg/qvGgnVx][join us on our Discord server]], otherwise read on to learn how
|
||||
to contribute to our fine corner of the interwebs.
|
||||
|
||||
* Table of Contents :TOC_3:
|
||||
- [[#where-can-i-help][Where can I help?]]
|
||||
@@ -32,19 +32,20 @@ or wires crossed, this guide was created to help you help us.
|
||||
- [[#contributing-documentation][Contributing documentation]]
|
||||
- [[#contributing-to-dooms-manual][Contributing to Doom's manual]]
|
||||
- [[#contributing-module-documentation][Contributing module documentation]]
|
||||
- [[#help-keep-packages-up-to-date][Help keep packages up-to-date!]]
|
||||
- [[#other-ways-to-support-doom-emacs][Other ways to support Doom Emacs]]
|
||||
- [[#special-thanks][Special thanks]]
|
||||
|
||||
* Where can I help?
|
||||
+ Our [[https://github.com/hlissner/doom-emacs/issues][issue tracker]] has many issues. If you find one that you have an answer to,
|
||||
please don't hold back!
|
||||
it would be a huge help!
|
||||
+ Look for issues tagged [[https://github.com/hlissner/doom-emacs/labels/good%20first%20issue][good first issue]]. These were judged to have a low
|
||||
barrier of entry.
|
||||
+ Look for issues tagged [[https://github.com/hlissner/doom-emacs/labels/help%20wanted][help wanted]]. These tend to be a little (or a lot)
|
||||
harder, and are issues outside my own expertise.
|
||||
+ If you've encountered a bug, [[https://github.com/hlissner/doom-emacs/issues/new/choose][file a bug report]].
|
||||
+ The [[https://github.com/hlissner/doom-emacs/projects/3][development roadmap board]] is a rough timeline of what is being worked on
|
||||
and when. It will give you some idea of what will change and where you can
|
||||
and when. It will give you an idea of what will change and where you can
|
||||
redirect your efforts.
|
||||
+ The [[https://github.com/hlissner/doom-emacs/projects/2][plugins under review board]] lists third party plugins being considered (or
|
||||
rejected) for inclusion in Doom Emacs. Approved and unclaimed packages are
|
||||
@@ -54,30 +55,21 @@ or wires crossed, this guide was created to help you help us.
|
||||
cause) perhaps you can address them at the source.
|
||||
|
||||
* TODO Reporting issues
|
||||
So you've found a problem. Before you fire off that bug report, there are a few
|
||||
things you should try first:
|
||||
You've found a problem and you're ready to fire off that bug report. Hold up!
|
||||
Before you do that, [[file:getting_started.org::*Troubleshoot][have a look at our Troubleshooting guide]]. If none of these
|
||||
suggestions pan out, /then/ it is time to file a bug report.
|
||||
|
||||
+ Make sure your configuration (or Doom Emacs) is *not* byte-compiled. Run ~doom
|
||||
clean~ to ensure it isn't. *Byte-compilation interferes with debugging!*
|
||||
+ Run ~bin/doom refresh~ to ensure all plugins are installed and autoload files
|
||||
generated.
|
||||
+ Run ~bin/doom doctor~ to diagnose common issues with your system.
|
||||
+ Check [[file:faq.org::*Common%20Issues][Common Issues]] in the FAQ to see if yours is a known issue.
|
||||
+ If you happen to know what module(s) are relevant to your issue, check their
|
||||
documentation (press =<leader> h m= to jump to a module's documentation). Your
|
||||
issue may be documented.
|
||||
+ If possible, check if the issue can be reproduced in vanilla Emacs (Emacs
|
||||
without Doom) and/or vanilla Doom (Doom without your private config). To test
|
||||
this, use ~M-x doom/sandbox~ (bound to =<leader> h E=). [[file:getting_started.org::*Use the sandbox][A guide for using the
|
||||
sandbox can be found in the manual]].
|
||||
+ Make sure your issue hasn't already been reported by searching the [[https://github.com/hlissner/doom-emacs/issues][issue
|
||||
tracker]].
|
||||
+ Make sure your issue hasn't been resolved on the =develop= branch of Doom.
|
||||
An effective bug report is informative. Please try to provide:
|
||||
|
||||
If these suggestions haven't worked for you, it's time [[https://github.com/hlissner/doom-emacs/issues/new/choose][to write a bug report]].
|
||||
Please make sure of the following before you submit:
|
||||
+ A backtrace of all mentioned errors.
|
||||
+ A step-by-step reproduction of the issue.
|
||||
+ Information about your Doom config and system environment.
|
||||
+ Screenshots/casts of the issue (if possible).
|
||||
|
||||
** TODO Collect backtraces of any error messages
|
||||
This section will show you how to collect this information.
|
||||
|
||||
** Acquire a backtrace from errors
|
||||
See "[[file:getting_started.org::*How to extract a backtrace from an error][How to extract a backtrace from an error]]" in the [[file:getting_started.org][Getting Started]] guide.
|
||||
|
||||
** TODO Create a step-by-step reproduction guide
|
||||
|
||||
@@ -165,6 +157,11 @@ contact via our [[https://discord.gg/bcZ6P3y][Discord server]] or [[mailto:henri
|
||||
|
||||
** TODO Contributing module documentation
|
||||
|
||||
* TODO Help keep packages up-to-date!
|
||||
Doom pins all its packages to reduce the likelihood of upstream breakage leaking
|
||||
into Doom Emacs. However, we may miss when a package releases hotfixes for
|
||||
critical issues. Let us know or PR a bump to our pinned packages.
|
||||
|
||||
* TODO Other ways to support Doom Emacs
|
||||
|
||||
* TODO Special thanks
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,16 +1,20 @@
|
||||
#+TITLE: Doom Emacs Documentation
|
||||
#+STARTUP: nofold
|
||||
|
||||
Doom Emacs is a configuration for [[https://www.gnu.org/software/emacs/][GNU Emacs]] written by a stubborn,
|
||||
shell-dwelling, and melodramatic ex-vimmer. It is designed to be a foundation
|
||||
for your own Emacs configuration or a resource for enthusiasts to learn more
|
||||
about our favorite OS.
|
||||
Doom is a configuration framework for [[https://www.gnu.org/software/emacs/][GNU Emacs 26.3+]] tailored for Emacs
|
||||
bankruptcy veterans who want less framework in their frameworks and the
|
||||
performance of a hand rolled config (or better). It can be a foundation for your
|
||||
own config or a resource for Emacs enthusiasts to learn more about our favorite
|
||||
OS.
|
||||
|
||||
Doom is an opinionated collection of reasonable (and optional) defaults with a
|
||||
focus on performance (both runtime and startup) and on abstraction-light,
|
||||
readable code design, so that there is less between you and Emacs.
|
||||
|
||||
#+begin_quote
|
||||
Github fails to render org links to sub-sections, so it is recommended that you
|
||||
view the documentation from within Doom Emacs by pressing =<help> d h= (=<help>=
|
||||
is =SPC h= for evil users and =C-h= for vanilla users) or searching it with
|
||||
=<help> d /=.
|
||||
The documentation is designed to be viewed within Doom Emacs. Access it by
|
||||
pressing =SPC h d h= (or =C-h d h= for non-evil users), or search it with =SPC h
|
||||
d s= (or =C-h d s=).
|
||||
#+end_quote
|
||||
|
||||
* Table of Contents :TOC:
|
||||
@@ -20,53 +24,47 @@ is =SPC h= for evil users and =C-h= for vanilla users) or searching it with
|
||||
- [[#frequently-asked-questions][Frequently Asked Questions]]
|
||||
- [[#contributing][Contributing]]
|
||||
- [[#workflow-tips-tricks--tutorials][Workflow Tips, Tricks & Tutorials]]
|
||||
- [[#module-appendix][Module Appendix]]
|
||||
- [[#community-resources][Community Resources]]
|
||||
- [[#asking-for-help][Asking for help]]
|
||||
- [[#project-roadmap][Project roadmap]]
|
||||
- [[#tutorials--guides][Tutorials & guides]]
|
||||
- [[#module-list][Module list]]
|
||||
- [[#app][:app]]
|
||||
- [[#completion][:completion]]
|
||||
- [[#config][:config]]
|
||||
- [[#editor][:editor]]
|
||||
- [[#emacs][:emacs]]
|
||||
- [[#email][:email]]
|
||||
- [[#input][:input]]
|
||||
- [[#lang][:lang]]
|
||||
- [[#term][:term]]
|
||||
- [[#tools][:tools]]
|
||||
- [[#ui][:ui]]
|
||||
- [[#projects-that-supportcomplement-doom][Projects that support/complement Doom]]
|
||||
- [[#similar-projects][Similar projects]]
|
||||
|
||||
* TODO Release Notes
|
||||
|
||||
* Documentation
|
||||
** [[file:getting_started.org][Getting Started]]
|
||||
- [[file:getting_started.org::*Install][Install]] - How to install Emacs, Doom and its plugins
|
||||
- [[file:getting_started.org::*Update][Update]] - Keep Doom and its packages up-to-date
|
||||
- [[file:getting_started.org::*Customize][Customize]] - A primer on customizing and reconfiguring Doom
|
||||
- [[file:getting_started.org::*Troubleshoot][Troubleshoot]] - How to debug Emacs & Doom, find help or look up documentation
|
||||
- [[file:getting_started.org::*Install][Install]]
|
||||
- [[file:getting_started.org::*Update & Rollback][Update & Rollback]]
|
||||
- [[file:getting_started.org::*Configure][Configure]]
|
||||
- [[file:getting_started.org::*Migrate][Migrate]]
|
||||
- [[file:getting_started.org::*Troubleshoot][Troubleshoot]]
|
||||
|
||||
** [[file:faq.org][Frequently Asked Questions]]
|
||||
- [[file:faq.org::*General][General]]
|
||||
- [[file:faq.org::*Configuration][Configuration]]
|
||||
- [[file:faq.org::*Package Management][Package Management]]
|
||||
- [[file:faq.org::*Defaults][Defaults]]
|
||||
- [[file:faq.org::Common Issues][Common Issues]]
|
||||
- [[file:faq.org::Contributing][Contributing]]
|
||||
|
||||
** TODO [[file:contributing.org][Contributing]]
|
||||
- [[file:contributing.org::*Where can I help?][Where to get help]]
|
||||
- Writing an effective bug report
|
||||
- Suggesting features, keybinds or enhancements
|
||||
- Contributing code
|
||||
- Contributing documentation
|
||||
- [[file:contributing.org::*Where can I help?][Where to get help?]]
|
||||
- Reporting issues
|
||||
- Suggesting features, keybinds and enhancements
|
||||
- Contributing code or documentation
|
||||
- Other ways to support Doom Emacs
|
||||
- Special thanks
|
||||
|
||||
** TODO [[file:workflow.org][Workflow Tips, Tricks & Tutorials]]
|
||||
|
||||
** [[file:modules.org][Module Appendix]]
|
||||
|
||||
* Community Resources
|
||||
** Asking for help
|
||||
- [[https://discord.gg/bcZ6P3y][Our Discord server]]
|
||||
- [[https://discord.gg/qvGgnVx][Our Discord server]]
|
||||
- [[https://github.com/hlissner/doom-emacs/issues][Our issue tracker]]
|
||||
|
||||
** Project roadmap
|
||||
@@ -79,11 +77,12 @@ is =SPC h= for evil users and =C-h= for vanilla users) or searching it with
|
||||
|
||||
** Tutorials & guides
|
||||
+ *Doom Emacs*
|
||||
- (videos) [[https://www.youtube.com/playlist?list=PLyy8KUDC8P7X6YkegqrnEnymzMWCNB4bN][Doom Emacs Tutorials]] by [[https://www.youtube.com/channel/UCVls1GmFKf6WlTraIb_IaJg][DistroTube]]
|
||||
- (videos) [[https://www.youtube.com/playlist?list=PLhXZp00uXBk4np17N39WvB80zgxlZfVwj][DoomCasts]] by @zaiste
|
||||
- [[https://noelwelsh.com/posts/2019-01-10-doom-emacs.html][Noel's crash course on Doom Emacs]]
|
||||
- [[https://medium.com/@aria_39488/getting-started-with-doom-emacs-a-great-transition-from-vim-to-emacs-9bab8e0d8458][Getting Started with Doom Emacs -- a great transition from Vim to Emacs]]
|
||||
- [[https://medium.com/@aria_39488/the-niceties-of-evil-in-doom-emacs-cabb46a9446b][The Niceties of evil in Doom Emacs]]
|
||||
- [[https://www.youtube.com/playlist?list=PLhXZp00uXBk4np17N39WvB80zgxlZfVwj][DoomCasts (youtube series)]]
|
||||
- [[https://www.youtube.com/watch?v=GK3fij-D1G8][Org-mode, literate programming in (Doom) Emacs]]
|
||||
- (video) [[https://www.youtube.com/watch?v=GK3fij-D1G8][Org-mode, literate programming in (Doom) Emacs]]
|
||||
+ *Emacs & Emacs Lisp*
|
||||
- [[https://www.gnu.org/software/emacs/manual/html_node/elisp/index.html][The Official Emacs manual]]
|
||||
- A variety of Emacs resources - https://github.com/ema2159/awesome-emacs
|
||||
@@ -92,185 +91,16 @@ is =SPC h= for evil users and =C-h= for vanilla users) or searching it with
|
||||
- http://steve-yegge.blogspot.com/2008/01/emergency-elisp.html
|
||||
- Workflows for customizing Emacs and its packages (and its C/C++ modes):
|
||||
- https://david.rothlis.net/emacs/customize_c.html
|
||||
+ *Tools in Emacs*
|
||||
- [[https://www.emacswiki.org/emacs/Calc_Tutorials_by_Andrew_Hyatt][How to use M-x calc]]
|
||||
- *Tools in Emacs*
|
||||
- [[https://www.emacswiki.org/emacs/Calc_Tutorials_by_Andrew_Hyatt][How to use M-x calc]]
|
||||
+ *Vim & Evil*
|
||||
- [[https://gist.github.com/dmsul/8bb08c686b70d5a68da0e2cb81cd857f][A crash course on modal editing and Ex commands]]
|
||||
|
||||
* Module list
|
||||
** :app
|
||||
Application modules are complex and opinionated modules that transform Emacs
|
||||
toward a specific purpose. They may have additional dependencies and should be
|
||||
loaded last, before =:config= modules.
|
||||
** Projects that support/complement Doom
|
||||
+ [[https://github.com/plexus/chemacs][plexus/chemacs]]
|
||||
+ [[https://github.com/r-darwish/topgrade][r-darwish/topgrade]]
|
||||
|
||||
+ [[file:../modules/app/calendar/README.org][calendar]] - TODO
|
||||
+ [[file:../modules/app/irc/README.org][irc]] - how neckbeards socialize
|
||||
+ rss =+org= - an RSS client in Emacs
|
||||
+ [[file:../modules/app/twitter/README.org][twitter]] - A twitter client for Emacs
|
||||
+ [[file:../modules/app/write/README.org][write]] =+wordnut +langtool= - Transforms emacs into an IDE for writers, and for
|
||||
writing fiction, notes, papers and so on.
|
||||
|
||||
** :completion
|
||||
Modules that provide new interfaces or frameworks for completion, including code
|
||||
completion.
|
||||
|
||||
+ [[file:../modules/completion/company/README.org][company]] =+childframe +tng= - The ultimate code completion backend
|
||||
+ helm =+fuzzy +childframe= - *Another* search engine for love and life
|
||||
+ ido - The /other/ *other* search engine for love and life
|
||||
+ [[file:../modules/completion/ivy/README.org][ivy]] =+fuzzy +prescient +childframe= - /The/ search engine for love and life
|
||||
|
||||
** :config
|
||||
Modules that configure Emacs one way or another, or focus on making it easier
|
||||
for you to customize it yourself. It is best to load these last.
|
||||
|
||||
+ literate - For users with literate configs. This will tangle+compile a
|
||||
config.org in your ~doom-private-dir~ when it changes.
|
||||
+ [[file:../modules/config/default/README.org][default]] =+bindings +smartparens= - The default module sets reasonable defaults
|
||||
for Emacs. It also provides a Spacemacs-inspired keybinding scheme and a
|
||||
smartparens config. Use it as a reference for your own modules.
|
||||
|
||||
** :editor
|
||||
Modules that affect and augment your ability to manipulate or insert text.
|
||||
|
||||
+ [[file:../modules/editor/evil/README.org][evil]] =+everywhere= - transforms Emacs into Vim
|
||||
+ [[file:../modules/editor/file-templates/README.org][file-templates]] - Auto-inserted templates in blank new files
|
||||
+ [[file:../modules/editor/fold/README.org][fold]] - universal code folding
|
||||
+ format =+onsave= - TODO
|
||||
+ god - run Emacs commands without modifier keys
|
||||
+ [[file:../modules/editor/lispy/README.org][lispy]] - TODO
|
||||
+ multiple-cursors - TODO
|
||||
+ [[file:../modules/editor/objed/README.org][objed]] - TODO
|
||||
+ [[file:../modules/editor/parinfer/README.org][parinfer]] - TODO
|
||||
+ rotate-text - TODO
|
||||
+ [[file:../modules/editor/snippets/README.org][snippets]] - Snippet expansion for lazy typists
|
||||
+ [[file:../modules/editor/word-wrap/README.org][word-wrap]] - soft wrapping with language-aware indent
|
||||
|
||||
** :emacs
|
||||
Modules that reconfigure or augment packages or features built into Emacs.
|
||||
|
||||
+ [[file:../modules/emacs/dired/README.org][dired]] =+ranger +icons= - TODO
|
||||
+ electric - TODO
|
||||
+ [[file:../modules/emacs/ibuffer/README.org][ibuffer]] =+icons= - TODO
|
||||
+ vc - TODO
|
||||
|
||||
** :email
|
||||
+ [[file:../modules/email/mu4e/README.org][mu4e]] =+gmail= - TODO
|
||||
+ notmuch - TODO
|
||||
+ wanderlust =+gmail= - TODO
|
||||
|
||||
** :input
|
||||
+ [[file:../modules/input/chinese/README.org][chinese]] - TODO
|
||||
+ [[file:../modules/input/japanese/README.org][japanese]] - TODO
|
||||
|
||||
** :lang
|
||||
Modules that bring support for a language or group of languages to Emacs.
|
||||
|
||||
+ [[file:../modules/lang/agda/README.org][agda]] - TODO
|
||||
+ assembly - TODO
|
||||
+ [[file:../modules/lang/cc/README.org][cc]] =+lsp= - TODO
|
||||
+ clojure - TODO
|
||||
+ common-lisp - TODO
|
||||
+ [[file:../modules/lang/coq/README.org][coq]] - TODO
|
||||
+ crystal - TODO
|
||||
+ [[file:../modules/lang/csharp/README.org][csharp]] - TODO
|
||||
+ data - TODO
|
||||
+ [[file:../modules/lang/elixir/README.org][elixir]] =+lsp= - TODO
|
||||
+ elm - TODO
|
||||
+ emacs-lisp - TODO
|
||||
+ erlang - TODO
|
||||
+ [[file:../modules/lang/ess/README.org][ess]] - TODO
|
||||
+ [[file:../modules/lang/faust/README.org][faust]] - TODO
|
||||
+ [[file:../modules/lang/fsharp/README.org][fsharp]] - TODO
|
||||
+ [[file:../modules/lang/go/README.org][go]] =+lsp= - TODO
|
||||
+ [[file:../modules/lang/haskell/README.org][haskell]] =+dante +intero +lsp= - TODO
|
||||
+ hy - TODO
|
||||
+ [[file:../modules/lang/idris/README.org][idris]] - TODO
|
||||
+ java =+meghanada +lsp= - TODO
|
||||
+ [[file:../modules/lang/javascript/README.org][javascript]] =+lsp= - JavaScript, TypeScript, and CoffeeScript support
|
||||
+ julia - TODO
|
||||
+ kotlin =+lsp+= - TODO
|
||||
+ [[file:../modules/lang/latex/README.org][latex]] - TODO
|
||||
+ lean - TODO
|
||||
+ [[file:../modules/lang/ledger/README.org][ledger]] - TODO
|
||||
+ lua =+moonscript= - TODO
|
||||
+ [[file:../modules/lang/markdown/README.org][markdown]] =+grip= - TODO
|
||||
+ [[file:../modules/lang/nim/README.org][nim]] - TODO
|
||||
+ nix - TODO
|
||||
+ [[file:../modules/lang/ocaml/README.org][ocaml]] =+lsp= - TODO
|
||||
+ [[file:../modules/lang/org/README.org][org]] =+dragndrop +gnuplot +hugo +ipython +pandoc +pomodoro +present= - TODO
|
||||
+ [[file:../modules/lang/perl/README.org][perl]] - TODO
|
||||
+ [[file:../modules/lang/php/README.org][php]] =+lsp= - TODO
|
||||
+ plantuml - TODO
|
||||
+ purescript - TODO
|
||||
+ [[file:../modules/lang/python/README.org][python]] =+lsp +pyenv +conda= - TODO
|
||||
+ qt - TODO
|
||||
+ racket - TODO
|
||||
+ [[file:../modules/lang/rest/README.org][rest]] - TODO
|
||||
+ ruby =+lsp +rvm +rbenv= - TODO
|
||||
+ [[file:../modules/lang/rust/README.org][rust]] =+lsp= - TODO
|
||||
+ scala =+lsp= - TODO
|
||||
+ [[file:../modules/lang/scheme/README.org][scheme]] - TODO
|
||||
+ [[file:../modules/lang/sh/README.org][sh]] =+fish +lsp= - TODO
|
||||
+ [[file:../modules/lang/solidity/README.org][solidity]] - TODO
|
||||
+ swift =+lsp= - TODO
|
||||
+ terra - TODO
|
||||
+ web =+lsp= - HTML and CSS (SCSS/SASS/LESS/Stylus) support.
|
||||
|
||||
** :term
|
||||
Modules that offer terminal emulation.
|
||||
|
||||
+ eshell - TODO
|
||||
+ shell - TODO
|
||||
+ term - TODO
|
||||
+ [[file:../modules/term/vterm/README.org][vterm]] - TODO
|
||||
|
||||
** :tools
|
||||
Small modules that give Emacs access to external tools & services.
|
||||
|
||||
+ ansible - TODO
|
||||
+ debugger - A (nigh-)universal debugger in Emacs
|
||||
+ [[file:../modules/tools/direnv/README.org][direnv]] - TODO
|
||||
+ [[file:../modules/tools/docker/README.org][docker]] - TODO
|
||||
+ [[file:../modules/tools/editorconfig/README.org][editorconfig]] - TODO
|
||||
+ [[file:../modules/tools/ein/README.org][ein]] - TODO
|
||||
+ [[file:../modules/tools/eval/README.org][eval]] =+overlay= - REPL & code evaluation support for a variety of languages
|
||||
+ flycheck - Live error/warning highlights
|
||||
+ flyspell - Spell checking
|
||||
+ gist - TODO
|
||||
+ [[file:../modules/tools/lookup/README.org][lookup]] =+docsets= - Universal jump-to & documentation lookup backend
|
||||
+ [[file:../modules/tools/lsp/README.org][lsp]] - TODO
|
||||
+ macos - TODO
|
||||
+ magit - TODO
|
||||
+ make - TODO
|
||||
+ pass - TODO
|
||||
+ pdf - TODO
|
||||
+ prodigy - TODO
|
||||
+ rgb - TODO
|
||||
+ [[file:../modules/tools/terraform/README.org][terraform]]
|
||||
+ tmux - TODO
|
||||
+ upload - TODO
|
||||
|
||||
** :ui
|
||||
Aesthetic modules that affect the Emacs interface or user experience.
|
||||
|
||||
+ [[file:../modules/ui/deft/README.org][deft]] - TODO
|
||||
+ [[file:../modules/ui/doom/README.org][doom]] - TODO
|
||||
+ [[file:../modules/ui/doom-dashboard/README.org][doom-dashboard]] - TODO
|
||||
+ [[file:../modules/ui/doom-quit/README.org][doom-quit]] - TODO
|
||||
+ fill-column - TODO
|
||||
+ [[file:../modules/ui/hl-todo/README.org][hl-todo]] - TODO
|
||||
+ [[file:../modules/ui/hydra/README.org][hydra]] - TODO
|
||||
+ indent-guides - TODO
|
||||
+ [[file:../modules/ui/modeline/README.org][modeline]] - TODO
|
||||
+ [[file:../modules/ui/nav-flash/README.org][nav-flash]] - TODO
|
||||
+ [[file:../modules/ui/neotree/README.org][neotree]] - TODO
|
||||
+ [[file:../modules/ui/ophints/README.org][ophints]] - TODO
|
||||
+ [[file:../modules/ui/popup/README.org][popup]] =+all +defaults= - Makes temporary/disposable windows less intrusive
|
||||
+ pretty-code - TODO
|
||||
+ [[file:../modules/ui/tabs/README.org][tabs]] - TODO
|
||||
+ treemacs - TODO
|
||||
+ [[file:../modules/ui/unicode/README.org][unicode]] - TODO
|
||||
+ vc-gutter - TODO
|
||||
+ vi-tilde-fringe - TODO
|
||||
+ [[file:../modules/ui/window-select/README.org][window-select]] =+switch-window +numbers= - TODO
|
||||
+ [[file:../modules/ui/workspaces/README.org][workspaces]] - Isolated workspaces
|
||||
** Similar projects
|
||||
+ [[https://github.com/purcell/emacs.d][purcell/emacs.d]]
|
||||
+ [[https://github.com/seagle0128/.emacs.d][seagle0128/.emacs.d]]
|
||||
+ [[https://github.com/syl20bnr/spacemacs][syl20bnr/spacemacs]]
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
#+TITLE: Workflow tips, tricks & tutorials
|
||||
#+TITLE: Getting to know Doom Emacs
|
||||
#+STARTUP: nofold
|
||||
|
||||
This page is a WIP.
|
||||
Once you've installed Doom and launched it, the next step of your masochistic
|
||||
journey is to master it. This guide will walk you through many Doom-centric
|
||||
workflows you'll commonly find in a text editor (and beyond). It isn't
|
||||
exhaustive because I don't have enough lives to make it so.
|
||||
|
||||
#+begin_quote
|
||||
If you feel like we've missed something, don't hesitate to let us know! You're
|
||||
welcome to [[https://discord.gg/qvGgnVx][join us on our Discord server]].
|
||||
#+end_quote
|
||||
|
||||
* Table of Contents :TOC:
|
||||
- [[#day-1-in-doom-emacs][Day 1 in Doom Emacs]]
|
||||
@@ -14,6 +22,7 @@ This page is a WIP.
|
||||
- [[#pipe-text-through-ex-commands-and-programs][Pipe text through ex commands and programs]]
|
||||
- [[#transposingswapping-text][Transposing/swapping text]]
|
||||
- [[#managing-your-projects][Managing your projects]]
|
||||
- [[#reconfiguring-emacs-on-a-per-project-basis][Reconfiguring Emacs on a per-project basis]]
|
||||
- [[#search--replace][Search & replace]]
|
||||
- [[#project-wide-text-search][Project-wide text search]]
|
||||
- [[#search--replace-1][Search & replace]]
|
||||
@@ -32,6 +41,8 @@ This page is a WIP.
|
||||
- [[#using-emacs-for][Using Emacs for...]]
|
||||
- [[#writing-fiction][Writing fiction]]
|
||||
- [[#writing-papers][Writing papers]]
|
||||
- [[#note-keeping][Note-keeping]]
|
||||
- [[#a-personal-organizer][A Personal Organizer]]
|
||||
- [[#composing-music][Composing music]]
|
||||
- [[#game-development][Game development]]
|
||||
- [[#web-development][Web development]]
|
||||
@@ -48,6 +59,9 @@ This page is a WIP.
|
||||
** TODO Pipe text through ex commands and programs
|
||||
** TODO Transposing/swapping text
|
||||
* TODO Managing your projects
|
||||
** TODO Reconfiguring Emacs on a per-project basis
|
||||
*** TODO .dir-locals.el
|
||||
*** TODO editorconfig
|
||||
* TODO Search & replace
|
||||
** TODO Project-wide text search
|
||||
** TODO Search & replace
|
||||
@@ -66,6 +80,8 @@ This page is a WIP.
|
||||
* TODO Using Emacs for...
|
||||
** TODO Writing fiction
|
||||
** TODO Writing papers
|
||||
** TODO Note-keeping
|
||||
** TODO A Personal Organizer
|
||||
** TODO Composing music
|
||||
** TODO Game development
|
||||
** TODO Web development
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
;; loaded, but after `early-init-file'. Doom handles package initialization, so
|
||||
;; we must prevent Emacs from doing it early!
|
||||
(setq package-enable-at-startup nil)
|
||||
(advice-add #'package--ensure-init-file :override #'ignore)
|
||||
|
||||
;; Prevent the glimpse of un-styled Emacs by disabling these UI elements early.
|
||||
(push '(menu-bar-lines . 0) default-frame-alist)
|
||||
|
||||
@@ -28,9 +28,8 @@
|
||||
;;; License: MIT
|
||||
|
||||
;; A big contributor to startup times is garbage collection. We up the gc
|
||||
;; threshold to temporarily prevent it from running, then reset it later with
|
||||
;; `doom-restore-garbage-collection-h'. Not resetting it will cause
|
||||
;; stuttering/freezes.
|
||||
;; threshold to temporarily prevent it from running, then reset it later by
|
||||
;; enabling `gcmh-mode'. Not resetting it will cause stuttering/freezes.
|
||||
(setq gc-cons-threshold most-positive-fixnum)
|
||||
|
||||
;; In noninteractive sessions, prioritize non-byte-compiled source files to
|
||||
@@ -48,9 +47,3 @@
|
||||
|
||||
;; And let 'er rip!
|
||||
(doom-initialize)
|
||||
(if noninteractive
|
||||
(doom-initialize-packages)
|
||||
(doom-initialize-core)
|
||||
(doom-initialize-modules)
|
||||
(add-hook 'window-setup-hook #'doom-display-benchmark-h)
|
||||
(add-to-list 'command-switch-alist (cons "--restore" #'doom-restore-session-handler)))
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
;;; init.el -*- lexical-binding: t; -*-
|
||||
|
||||
;; Copy this file to ~/.doom.d/init.el or ~/.config/doom/init.el ('doom install'
|
||||
;; will do this for you). The `doom!' block below controls what modules are
|
||||
;; enabled and in what order they will be loaded. Remember to run 'doom refresh'
|
||||
;; after modifying it.
|
||||
;; This file controls what Doom modules are enabled and what order they load
|
||||
;; in. Remember to run 'doom sync' after modifying it!
|
||||
|
||||
;; NOTE Press 'SPC h d h' (or 'C-h d h' for non-vim users) to access Doom's
|
||||
;; documentation. There you'll find a "Module Index" link where you'll find
|
||||
;; a comprehensive list of Doom's modules and what flags they support.
|
||||
|
||||
;; NOTE Move your cursor over a module's name (or its flags) and press 'K' (or
|
||||
;; 'C-c c k' for non-vim users) to view its documentation. This works on
|
||||
;; flags as well (those symbols that start with a plus).
|
||||
;;
|
||||
;; More information about these modules (and what flags they support) can be
|
||||
;; found in modules/README.org.
|
||||
;; Alternatively, press 'gd' (or 'C-c c d') on a module to browse its
|
||||
;; directory (for easy access to its source code).
|
||||
|
||||
(doom! :input
|
||||
;;chinese
|
||||
@@ -27,21 +33,21 @@
|
||||
hl-todo ; highlight TODO/FIXME/NOTE/DEPRECATED/HACK/REVIEW
|
||||
;;hydra
|
||||
;;indent-guides ; highlighted indent columns
|
||||
;;minimap ; show a map of the code on the side
|
||||
modeline ; snazzy, Atom-inspired modeline, plus API
|
||||
nav-flash ; blink the current line after jumping
|
||||
;;nav-flash ; blink cursor line after big motions
|
||||
;;neotree ; a project drawer, like NERDTree for vim
|
||||
ophints ; highlight the region an operation acts on
|
||||
(popup ; tame sudden yet inevitable temporary windows
|
||||
+all ; catch all popups that start with an asterix
|
||||
+defaults) ; default popup rules
|
||||
;;pretty-code ; replace bits of code with pretty symbols
|
||||
(popup +defaults) ; tame sudden yet inevitable temporary windows
|
||||
;;pretty-code ; ligatures or substitute text with pretty symbols
|
||||
;;tabs ; an tab bar for Emacs
|
||||
;;treemacs ; a project drawer, like neotree but cooler
|
||||
;;unicode ; extended unicode support for various languages
|
||||
vc-gutter ; vcs diff in the fringe
|
||||
vi-tilde-fringe ; fringe tildes to mark beyond EOB
|
||||
window-select ; visually switch windows
|
||||
;;window-select ; visually switch windows
|
||||
workspaces ; tab emulation, persistence & separate workspaces
|
||||
;;zen ; distraction-free coding or writing
|
||||
|
||||
:editor
|
||||
(evil +everywhere); come to the dark side, we have cookies
|
||||
@@ -50,24 +56,30 @@
|
||||
;;(format +onsave) ; automated prettiness
|
||||
;;god ; run Emacs commands without modifier keys
|
||||
;;lispy ; vim for lisp, for people who don't like vim
|
||||
multiple-cursors ; editing in many places at once
|
||||
;;multiple-cursors ; editing in many places at once
|
||||
;;objed ; text object editing for the innocent
|
||||
;;parinfer ; turn lisp into python, sort of
|
||||
rotate-text ; cycle region at point between text candidates
|
||||
;;rotate-text ; cycle region at point between text candidates
|
||||
snippets ; my elves. They type so I don't have to
|
||||
;;word-wrap ; soft wrapping with language-aware indent
|
||||
|
||||
:emacs
|
||||
dired ; making dired pretty [functional]
|
||||
electric ; smarter, keyword-based electric-indent
|
||||
ibuffer ; interactive buffer management
|
||||
;;ibuffer ; interactive buffer management
|
||||
undo ; persistent, smarter undo for your inevitable mistakes
|
||||
vc ; version-control and Emacs, sitting in a tree
|
||||
|
||||
:term
|
||||
;;eshell ; a consistent, cross-platform shell (WIP)
|
||||
;;shell ; a terminal REPL for Emacs
|
||||
;;term ; terminals in Emacs
|
||||
;;vterm ; another terminals in Emacs
|
||||
;;eshell ; the elisp shell that works everywhere
|
||||
;;shell ; simple shell REPL for Emacs
|
||||
;;term ; basic terminal emulator for Emacs
|
||||
;;vterm ; the best terminal emulation in Emacs
|
||||
|
||||
:checkers
|
||||
syntax ; tasing you for every semicolon you forget
|
||||
;;spell ; tasing you for misspelling mispelling
|
||||
;;grammar ; tasing grammar mistake every you make
|
||||
|
||||
:tools
|
||||
;;ansible
|
||||
@@ -77,11 +89,8 @@
|
||||
;;editorconfig ; let someone else argue about tabs vs spaces
|
||||
;;ein ; tame Jupyter notebooks with emacs
|
||||
(eval +overlay) ; run code, run (also, repls)
|
||||
flycheck ; tasing you for every semicolon you forget
|
||||
;;flyspell ; tasing you for misspelling mispelling
|
||||
;;gist ; interacting with github gists
|
||||
(lookup ; helps you navigate your code and documentation
|
||||
+docsets) ; ...or in Dash docsets locally
|
||||
lookup ; navigate your code and its documentation
|
||||
;;lsp
|
||||
;;macos ; MacOS-specific commands
|
||||
magit ; a git porcelain for Emacs
|
||||
@@ -90,20 +99,21 @@
|
||||
;;pdf ; pdf enhancements
|
||||
;;prodigy ; FIXME managing external services & code builders
|
||||
;;rgb ; creating color strings
|
||||
;;taskrunner ; taskrunner for all your projects
|
||||
;;terraform ; infrastructure as code
|
||||
;;tmux ; an API for interacting with tmux
|
||||
;;upload ; map local to remote projects via ssh/ftp
|
||||
|
||||
:lang
|
||||
;;agda ; types of types of types of types...
|
||||
;;assembly ; assembly for fun or debugging
|
||||
;;cc ; C/C++/Obj-C madness
|
||||
;;clojure ; java with a lisp
|
||||
;;common-lisp ; if you've seen one lisp, you've seen them all
|
||||
;;coq ; proofs-as-programs
|
||||
;;crystal ; ruby at the speed of c
|
||||
;;csharp ; unity, .NET, and mono shenanigans
|
||||
data ; config/data formats
|
||||
;;data ; config/data formats
|
||||
;;(dart +flutter) ; paint ui and not much else
|
||||
;;elixir ; erlang done right
|
||||
;;elm ; care for a cup of TEA?
|
||||
emacs-lisp ; drown in parentheses
|
||||
@@ -111,10 +121,13 @@
|
||||
;;ess ; emacs speaks statistics
|
||||
;;faust ; dsp, but you get to keep your soul
|
||||
;;fsharp ; ML stands for Microsoft's Language
|
||||
;;go ; the hipster dialect
|
||||
;;fstar ; (dependent) types and (monadic) effects and Z3
|
||||
;;gdscript ; the language you waited for
|
||||
;;(go +lsp) ; the hipster dialect
|
||||
;;(haskell +dante) ; a language that's lazier than I am
|
||||
;;hy ; readability of scheme w/ speed of python
|
||||
;;idris ;
|
||||
;;json ; At least it ain't XML
|
||||
;;(java +meghanada) ; the poster child for carpal tunnel syndrome
|
||||
;;javascript ; all(hope(abandon(ye(who(enter(here))))))
|
||||
;;julia ; a better, faster MATLAB
|
||||
@@ -128,31 +141,27 @@
|
||||
;;nim ; python + lisp at the speed of c
|
||||
;;nix ; I hereby declare "nix geht mehr!"
|
||||
;;ocaml ; an objective camel
|
||||
(org ; organize your plain life in plain text
|
||||
+dragndrop ; drag & drop files/images into org buffers
|
||||
;;+hugo ; use Emacs for hugo blogging
|
||||
+ipython ; ipython/jupyter support for babel
|
||||
+pandoc ; export-with-pandoc support
|
||||
;;+pomodoro ; be fruitful with the tomato technique
|
||||
+present) ; using org-mode for presentations
|
||||
;;perl ; write code no one else can comprehend
|
||||
org ; organize your plain life in plain text
|
||||
;;php ; perl's insecure younger brother
|
||||
;;plantuml ; diagrams for confusing people more
|
||||
;;purescript ; javascript, but functional
|
||||
;;python ; beautiful is better than ugly
|
||||
;;qt ; the 'cutest' gui framework ever
|
||||
;;racket ; a DSL for DSLs
|
||||
;;raku ; the artist formerly known as perl6
|
||||
;;rest ; Emacs as a REST client
|
||||
;;rst ; ReST in peace
|
||||
;;ruby ; 1.step {|i| p "Ruby is #{i.even? ? 'love' : 'life'}"}
|
||||
;;(ruby +rails) ; 1.step {|i| p "Ruby is #{i.even? ? 'love' : 'life'}"}
|
||||
;;rust ; Fe2O3.unwrap().unwrap().unwrap().unwrap()
|
||||
;;scala ; java, but good
|
||||
;;scheme ; a fully conniving family of lisps
|
||||
sh ; she sells {ba,z,fi}sh shells on the C xor
|
||||
;;sml
|
||||
;;solidity ; do you need a blockchain? No.
|
||||
;;swift ; who asked for emoji variables?
|
||||
;;terra ; Earth and Moon in alignment for performance.
|
||||
;;web ; the tubes
|
||||
;;yaml ; JSON, but readable
|
||||
|
||||
:email
|
||||
;;(mu4e +gmail)
|
||||
@@ -164,7 +173,6 @@
|
||||
;;irc ; how neckbeards socialize
|
||||
;;(rss +org) ; emacs as an RSS reader
|
||||
;;twitter ; twitter client https://twitter.com/vnought
|
||||
;;write ; emacs for writers (fiction, notes, papers, etc.)
|
||||
|
||||
:config
|
||||
;;literate
|
||||
|
||||
@@ -62,5 +62,5 @@ To control what org files ~clfw:org-create-source~ will use, ~let~-bind
|
||||
The [[https://github.com/kiwanami/emacs-calfw][kiwanami/emacs-calfw]] project readme contains more examples.
|
||||
|
||||
** Synchronizing Org and Google Calendar
|
||||
The [[https://github.com/myuhe/org-gcal.el][myuhe/org-gcal.el]] project README contains more detailed instructions on how
|
||||
The [[https://github.com/kidd/org-gcal.el][kidd/org-gcal.el]] project README contains more detailed instructions on how
|
||||
to link your calendar with Google calendars.
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
(defvar +calendar--wconf nil)
|
||||
|
||||
(defun +calendar--init ()
|
||||
(if-let* ((win (cl-loop for win in (doom-visible-windows)
|
||||
if (string-match-p "^\\*cfw:" (buffer-name (window-buffer win)))
|
||||
return win)))
|
||||
(if-let (win (cl-find-if (lambda (b) (string-match-p "^\\*cfw:" (buffer-name b)))
|
||||
(doom-visible-windows)
|
||||
:key #'window-buffer))
|
||||
(select-window win)
|
||||
(call-interactively +calendar-open-function)))
|
||||
|
||||
|
||||
@@ -42,10 +42,10 @@
|
||||
org-gcal-fetch
|
||||
org-gcal-post-at-point
|
||||
org-gcal-delete-at-point)
|
||||
:init
|
||||
(defvar org-gcal-dir (concat doom-cache-dir "org-gcal/"))
|
||||
(defvar org-gcal-token-file (concat org-gcal-dir "token.gpg"))
|
||||
:config
|
||||
;; hack to avoid the deferred.el error
|
||||
(defun org-gcal--notify (title mes)
|
||||
(message "org-gcal::%s - %s" title mes)))
|
||||
|
||||
|
||||
;; (use-package! alert)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
;; -*- no-byte-compile: t; -*-
|
||||
;;; app/calendar/packages.el
|
||||
|
||||
(package! calfw)
|
||||
(package! calfw-org)
|
||||
(package! org-gcal)
|
||||
(package! calfw :pin "03abce97620a4a7f7ec5f911e669da9031ab9088")
|
||||
(package! calfw-org :pin "03abce97620a4a7f7ec5f911e669da9031ab9088")
|
||||
(package! org-gcal :pin "744505832b34e07b44a5d97d8720b2d7492d7fc9")
|
||||
|
||||
@@ -7,8 +7,11 @@
|
||||
- [[#description][Description]]
|
||||
- [[#module-flags][Module Flags]]
|
||||
- [[#plugins][Plugins]]
|
||||
- [[#dependencies][Dependencies]]
|
||||
- [[#prerequisites][Prerequisites]]
|
||||
- [[#macos][macOS]]
|
||||
- [[#debian--ubuntu][Debian / Ubuntu]]
|
||||
- [[#arch-linux][Arch Linux]]
|
||||
- [[#nixos][NixOS]]
|
||||
- [[#features][Features]]
|
||||
- [[#an-irc-client-in-emacs][An IRC Client in Emacs]]
|
||||
- [[#configuration][Configuration]]
|
||||
@@ -17,7 +20,7 @@
|
||||
- [[#troubleshooting][Troubleshooting]]
|
||||
|
||||
* Description
|
||||
This module turns adds an IRC client to Emacs with OS notifications.
|
||||
This module turns Emacs into an IRC client, capable of OS notifications.
|
||||
|
||||
** Module Flags
|
||||
This module provides no flags.
|
||||
@@ -26,11 +29,27 @@ This module provides no flags.
|
||||
+ [[https://github.com/jorgenschaefer/circe][circe]]
|
||||
+ [[https://github.com/eqyiel/circe-notifications][circe-notifications]]
|
||||
|
||||
* Dependencies
|
||||
This module requires =gnutls-cli= or =openssl= for secure connections.
|
||||
|
||||
* Prerequisites
|
||||
This module has no direct prerequisites.
|
||||
This module requires =gnutls= for secure IRC connections to work.
|
||||
|
||||
** macOS
|
||||
#+BEGIN_SRC sh
|
||||
brew install gnutls
|
||||
#+END_SRC
|
||||
|
||||
** Debian / Ubuntu
|
||||
#+BEGIN_SRC sh
|
||||
apt install gnutls-bin
|
||||
#+END_SRC
|
||||
|
||||
** Arch Linux
|
||||
#+BEGIN_SRC sh
|
||||
pacman -S gnutls
|
||||
#+END_SRC
|
||||
** NixOS
|
||||
#+BEGIN_SRC nix
|
||||
environment.systemPackages = [ pkgs.gnutls ];
|
||||
#+END_SRC
|
||||
|
||||
* Features
|
||||
** An IRC Client in Emacs
|
||||
@@ -54,20 +73,23 @@ When in a circe buffer these keybindings will be available.
|
||||
| ~circe-reconnect~ | =SPC m R= | Reconnect the current server |
|
||||
|
||||
* Configuration
|
||||
Use ~set-irc-server!~ to configure IRC servers. Its second argument (a plist)
|
||||
Use ~set-irc-server! SERVER PLIST~ to configure IRC servers. Its second argument (a plist)
|
||||
takes the same arguments as ~circe-network-options~.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp :tangle no
|
||||
(set-irc-server! "chat.freenode.net"
|
||||
`(:tls t
|
||||
:nick "doom"
|
||||
:sasl-username "myusername"
|
||||
:sasl-password "mypassword"
|
||||
:channels ("#emacs")))
|
||||
;; if you omit =:host=, ~SERVER~ will be used instead.
|
||||
(after! circe
|
||||
(set-irc-server! "chat.freenode.net"
|
||||
`(:tls t
|
||||
:port 6697
|
||||
:nick "doom"
|
||||
:sasl-username "myusername"
|
||||
:sasl-password "mypassword"
|
||||
:channels ("#emacs"))))
|
||||
#+END_SRC
|
||||
|
||||
*It is a obviously a bad idea to store auth-details in plaintext,* so here are
|
||||
some ways to avoid that:
|
||||
However, *it is a obviously a bad idea to store your password in plaintext,* so
|
||||
here are ways to avoid that:
|
||||
|
||||
** Pass: the unix password manager
|
||||
[[https://www.passwordstore.org/][Pass]] is my tool of choice. I use it to manage my passwords. If you activate the
|
||||
@@ -80,6 +102,7 @@ password store.
|
||||
#+BEGIN_SRC emacs-lisp :tangle no
|
||||
(set-irc-server! "chat.freenode.net"
|
||||
`(:tls t
|
||||
:port 6697
|
||||
:nick "doom"
|
||||
:sasl-username ,(+pass-get-user "irc/freenode.net")
|
||||
:sasl-password ,(+pass-get-secret "irc/freenode.net")
|
||||
@@ -105,10 +128,10 @@ Note that =+pass-get-user= tries to find your username by looking for the fields
|
||||
listed in =+pass-user-fields= (by default =login=, =user==, =username== and
|
||||
=email=)=). An example configuration looks like
|
||||
|
||||
#+BEGIN_SRC txt :tangle no
|
||||
#+begin_example
|
||||
mysecretpassword
|
||||
username: myusername
|
||||
#+END_SRC
|
||||
#+end_example
|
||||
|
||||
** Emacs' auth-source API
|
||||
~auth-source~ is built into Emacs. As suggested [[https://github.com/jorgenschaefer/circe/wiki/Configuration#safer-password-management][in the circe wiki]], you can store
|
||||
|
||||
@@ -3,15 +3,18 @@
|
||||
(defvar +irc--workspace-name "*IRC*")
|
||||
|
||||
(defun +irc-setup-wconf (&optional inhibit-workspace)
|
||||
(unless inhibit-workspace
|
||||
(+workspace-switch +irc--workspace-name t))
|
||||
(when (and (featurep! :ui workspaces)
|
||||
(not inhibit-workspace))
|
||||
(+workspace-switch +irc--workspace-name 'auto-create))
|
||||
(let ((buffers (doom-buffers-in-mode 'circe-mode nil t)))
|
||||
(if buffers
|
||||
(ignore (switch-to-buffer (car buffers)))
|
||||
(require 'circe)
|
||||
(delete-other-windows)
|
||||
(switch-to-buffer (doom-fallback-buffer))
|
||||
t)))
|
||||
(if (not (member (window-buffer) buffers))
|
||||
(if buffers
|
||||
(ignore (switch-to-buffer (car buffers)))
|
||||
(require 'circe)
|
||||
(delete-other-windows)
|
||||
(switch-to-buffer (doom-fallback-buffer))
|
||||
t)
|
||||
(user-error "IRC buffer is already active and selected"))))
|
||||
|
||||
;;;###autoload
|
||||
(defun =irc (&optional inhibit-workspace)
|
||||
@@ -20,17 +23,12 @@
|
||||
If INHIBIT-WORKSPACE (the universal argument) is non-nil, don't spawn a new
|
||||
workspace for it."
|
||||
(interactive "P")
|
||||
(cond ((and (featurep! :ui workspaces)
|
||||
(+workspace-exists-p +irc--workspace-name))
|
||||
(+workspace-switch +irc--workspace-name))
|
||||
((not (+irc-setup-wconf inhibit-workspace))
|
||||
(user-error "Couldn't start up a workspace for IRC")))
|
||||
(if (doom-buffers-in-mode 'circe-mode (buffer-list) t)
|
||||
(message "Circe buffers are already open")
|
||||
(if circe-network-options
|
||||
(cl-loop for network in circe-network-options
|
||||
collect (circe (car network)))
|
||||
(call-interactively #'circe))))
|
||||
(+irc-setup-wconf inhibit-workspace)
|
||||
(cond ((doom-buffers-in-mode 'circe-mode (doom-buffer-list) t)
|
||||
(message "Circe buffers are already open"))
|
||||
(circe-network-options
|
||||
(mapc #'circe (mapcar #'car circe-network-options)))
|
||||
((call-interactively #'circe))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +irc/connect (&optional inhibit-workspace)
|
||||
@@ -52,16 +50,17 @@ workspace for it."
|
||||
(defun +irc/quit ()
|
||||
"Kill current circe session and workgroup."
|
||||
(interactive)
|
||||
(if (y-or-n-p "Really kill IRC session?")
|
||||
(let (circe-channel-killed-confirmation
|
||||
circe-server-killed-confirmation)
|
||||
(when +irc--defer-timer
|
||||
(cancel-timer +irc--defer-timer))
|
||||
(disable-circe-notifications)
|
||||
(mapc #'kill-buffer (doom-buffers-in-mode 'circe-mode (buffer-list) t))
|
||||
(when (equal (+workspace-current-name) +irc--workspace-name)
|
||||
(+workspace/delete +irc--workspace-name)))
|
||||
(message "Aborted")))
|
||||
(unless (y-or-n-p "Really kill IRC session?")
|
||||
(user-error "Aborted"))
|
||||
(let (circe-channel-killed-confirmation
|
||||
circe-server-killed-confirmation)
|
||||
(when +irc--defer-timer
|
||||
(cancel-timer +irc--defer-timer))
|
||||
(disable-circe-notifications)
|
||||
(mapc #'kill-buffer (doom-buffers-in-mode 'circe-mode (buffer-list) t))
|
||||
(when (featurep! :ui workspaces)
|
||||
(when (equal (+workspace-current-name) +irc--workspace-name)
|
||||
(+workspace/delete +irc--workspace-name)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +irc/ivy-jump-to-channel (&optional this-server)
|
||||
@@ -93,7 +92,7 @@ argument) is non-nil only show channels in current server."
|
||||
|
||||
;;;###autoload
|
||||
(defun +irc/tracking-next-buffer ()
|
||||
"Dissables switching to an unread buffer unless in the irc workspace."
|
||||
"Disables switching to an unread buffer unless in the irc workspace."
|
||||
(interactive)
|
||||
(when (derived-mode-p 'circe-mode)
|
||||
(tracking-next-buffer)))
|
||||
@@ -106,13 +105,12 @@ argument) is non-nil only show channels in current server."
|
||||
(defun +circe-buffer-p (buf)
|
||||
"Return non-nil if BUF is a `circe-mode' buffer."
|
||||
(with-current-buffer buf
|
||||
(and (derived-mode-p 'circe-mode)
|
||||
(eq (safe-persp-name (get-current-persp))
|
||||
+irc--workspace-name))))
|
||||
(derived-mode-p 'circe-mode)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +irc--add-circe-buffer-to-persp-h ()
|
||||
(when (bound-and-true-p persp-mode)
|
||||
(when (and (bound-and-true-p persp-mode)
|
||||
(+workspace-exists-p +irc--workspace-name))
|
||||
(let ((persp (get-current-persp))
|
||||
(buf (current-buffer)))
|
||||
;; Add a new circe buffer to irc workspace when we're in another workspace
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
;;; app/irc/autoload/settings.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;;###autodef
|
||||
(defun set-irc-server! (server letvars)
|
||||
(defun set-irc-server! (server plist)
|
||||
"Registers an irc SERVER for circe.
|
||||
|
||||
SERVER can either be a name for the network (in which case you must specify a
|
||||
:host), or it may be the hostname itself, in which case it will be used as the
|
||||
:host.
|
||||
|
||||
See `circe-network-options' for details."
|
||||
(after! circe
|
||||
(push (cons server letvars) circe-network-options)))
|
||||
(unless (plist-member plist :host)
|
||||
(plist-put! plist :host server))
|
||||
(setf (alist-get server circe-network-options
|
||||
nil nil #'equal)
|
||||
plist)))
|
||||
|
||||
@@ -48,7 +48,6 @@ playback.")
|
||||
|
||||
(use-package! circe
|
||||
:commands circe circe-server-buffers
|
||||
:init (setq circe-network-defaults nil)
|
||||
:config
|
||||
(setq circe-default-quit-message nil
|
||||
circe-default-part-message nil
|
||||
@@ -93,6 +92,26 @@ playback.")
|
||||
(add-hook 'doom-real-buffer-functions #'+circe-buffer-p)
|
||||
(add-hook 'circe-channel-mode-hook #'turn-on-visual-line-mode)
|
||||
(add-hook 'circe-mode-hook #'+irc--add-circe-buffer-to-persp-h)
|
||||
(add-hook 'circe-mode-hook #'turn-off-smartparens-mode)
|
||||
|
||||
;; HACK Fix #1862: circe hangs on TLS connections when using OpenSSL versions
|
||||
;; > 1.1.0, where tls.el does not correctly determine the end of the info
|
||||
;; block. This fixes proposed in jorgenschaefer/circe#340
|
||||
(setq-hook! 'circe-mode-hook
|
||||
tls-end-of-info
|
||||
(concat "\\("
|
||||
;; `openssl s_client' regexp. See ssl/ssl_txt.c lines 219-220.
|
||||
;; According to apps/s_client.c line 1515 `---' is always the last
|
||||
;; line that is printed by s_client before the real data.
|
||||
"^ Verify return code: .+\n\\(\\|^ Extended master secret: .+\n\\)\\(\\|^ Max Early Data: .+\n\\)---\n\\|"
|
||||
;; `gnutls' regexp. See src/cli.c lines 721-.
|
||||
"^- Simple Client Mode:\n"
|
||||
"\\(\n\\|" ; ignore blank lines
|
||||
;; According to GnuTLS v2.1.5 src/cli.c lines 640-650 and 705-715 in
|
||||
;; `main' the handshake will start after this message. If the
|
||||
;; handshake fails, the programs will abort.
|
||||
"^\\*\\*\\* Starting TLS handshake\n\\)*"
|
||||
"\\)"))
|
||||
|
||||
(defadvice! +irc--circe-run-disconnect-hook-a (&rest _)
|
||||
"Runs `+irc-disconnect-hook' after circe disconnects."
|
||||
@@ -175,7 +194,7 @@ playback.")
|
||||
(define-key lui-mode-map "\C-u" #'lui-kill-to-beginning-of-line)
|
||||
(setq lui-fill-type nil)
|
||||
|
||||
(when (featurep! :tools flyspell)
|
||||
(when (featurep! :checkers spell)
|
||||
(setq lui-flyspell-p t))
|
||||
|
||||
(after! evil
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
;; -*- no-byte-compile: t; -*-
|
||||
;;; app/irc/packages.el
|
||||
|
||||
(package! circe)
|
||||
(package! circe-notifications)
|
||||
(package! circe :pin "e5bf5f89741a9c43aa406491e94dd8d58c302fb4")
|
||||
(package! circe-notifications :pin "291149ac12877bbd062da993479d3533a26862b0")
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
;;; app/regex/autoload/export.el
|
||||
|
||||
;;;###autoload
|
||||
(defun +regex/export () (interactive)) ; TODO +regex/export
|
||||
|
||||
|
||||
;;
|
||||
(defun +regex-export-python ()) ; import (re|regex)
|
||||
|
||||
(defun +regex-export-php ()) ; preg_(match(_all)?|replace)
|
||||
|
||||
(defun +regex-export-ruby ()) ; %r[.+]
|
||||
|
||||
(defun +regex-export-js ()) ; /.+/
|
||||
@@ -1,272 +0,0 @@
|
||||
;;; app/regex/autoload/regex.el
|
||||
|
||||
(defvar +regex--text-buffer nil)
|
||||
(defvar +regex--text-replace-buffer nil)
|
||||
(defvar +regex--expr-buffer nil)
|
||||
(defvar +regex--expr-replace-buffer nil)
|
||||
(defvar +regex--groups-buffer nil)
|
||||
(defvar +regex--replace-buffer nil)
|
||||
|
||||
;;
|
||||
(defface +regex-match-0-face
|
||||
`((t (:foreground "Black" :background ,(doom-color 'magenta) :bold t)))
|
||||
"TODO"
|
||||
:group 'faces)
|
||||
|
||||
(defface +regex-match-1-face
|
||||
`((t (:foreground "Black" :background ,(doom-color 'blue) :bold t)))
|
||||
"TODO"
|
||||
:group 'faces)
|
||||
|
||||
(defface +regex-match-2-face
|
||||
`((t (:foreground "Black" :background ,(doom-color 'green) :bold t)))
|
||||
"TODO"
|
||||
:group 'faces)
|
||||
|
||||
(defvar +regex-faces
|
||||
'(+regex-match-0-face +regex-match-1-face +regex-match-2-face)
|
||||
"TODO")
|
||||
|
||||
;;
|
||||
(defvar +regex-mode-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
(define-key map "\C-c\C-c" #'+regex-update-buffers)
|
||||
(define-key map "\C-c\C-r" #'=regex/replace)
|
||||
(define-key map "\C-c\C-k" #'+regex/quit)
|
||||
(define-key map [remap kill-current-buffer] #'+regex/quit)
|
||||
(define-key map [remap kill-buffer] #'+regex/quit)
|
||||
map)
|
||||
"TODO")
|
||||
|
||||
;;;###autoload
|
||||
(define-minor-mode +regex-mode
|
||||
"TODO"
|
||||
:init-value nil
|
||||
:global nil
|
||||
:lighter ""
|
||||
:keymap +regex-mode-map
|
||||
(if +regex-mode
|
||||
(add-hook 'after-change-functions #'+regex-update-buffers nil t)
|
||||
(remove-hook 'after-change-functions #'+regex-update-buffers t)))
|
||||
|
||||
;;;###autoload
|
||||
(defun =regex (&optional dummy-text)
|
||||
"Start the Regex IDE."
|
||||
(interactive "P")
|
||||
(unless (buffer-live-p +regex--expr-buffer)
|
||||
(condition-case ex
|
||||
(progn
|
||||
(setq +regex--expr-buffer (get-buffer-create "*doom-regex*")
|
||||
+regex--text-buffer (if dummy-text (get-buffer-create "*doom-regex-text*") (current-buffer))
|
||||
+regex--groups-buffer (get-buffer-create "*doom-regex-groups*"))
|
||||
(when dummy-text
|
||||
(+workspace-switch +regex-workspace-name t)
|
||||
(switch-to-buffer +regex--text-buffer)
|
||||
(with-current-buffer +regex--text-buffer
|
||||
(insert +regex-dummy-text)))
|
||||
(pop-to-buffer +regex--groups-buffer)
|
||||
(pop-to-buffer +regex--expr-buffer)
|
||||
(with-current-buffer +regex--expr-buffer
|
||||
(conf-mode)
|
||||
(rainbow-delimiters-mode +1)
|
||||
(doom/toggle-line-numbers +1)
|
||||
(setq-local require-final-newline nil)
|
||||
(+regex-mode +1)
|
||||
(text-scale-set 3)))
|
||||
('error
|
||||
(+regex/quit)
|
||||
(error "Failed to open the Regexp IDE: %s" ex)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun =regex/replace ()
|
||||
(interactive)
|
||||
(unless (buffer-live-p +regex--replace-buffer)
|
||||
(let (text)
|
||||
(=regex t)
|
||||
(with-selected-window (get-buffer-window +regex--text-buffer)
|
||||
(setq text (buffer-string))
|
||||
(select-window (split-window-right))
|
||||
(switch-to-buffer (get-buffer-create "*doom-regex-text-repl*"))
|
||||
(erase-buffer)
|
||||
(insert text)
|
||||
(read-only-mode +1)
|
||||
(setq +regex--text-replace-buffer (current-buffer)))
|
||||
(with-current-buffer +regex--expr-buffer
|
||||
(select-window (split-window-right))
|
||||
(switch-to-buffer (get-buffer-create "*doom-regex-repl*"))
|
||||
(conf-mode)
|
||||
(rainbow-delimiters-mode +1)
|
||||
(doom/toggle-line-numbers -1)
|
||||
(setq-local require-final-newline nil)
|
||||
(setq mode-line-format nil
|
||||
+regex--expr-replace-buffer (current-buffer))
|
||||
(+regex-mode +1)
|
||||
(text-scale-set 3)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +regex/quit ()
|
||||
"TODO"
|
||||
(interactive)
|
||||
(when (and +regex--text-buffer (buffer-live-p +regex--text-buffer))
|
||||
(with-current-buffer +regex--text-buffer
|
||||
(+regex-mode -1)
|
||||
(remove-overlays nil nil 'category '+regex))
|
||||
(when (equal (buffer-name +regex--text-buffer) "*doom-regex-text*")
|
||||
(kill-buffer +regex--text-buffer)))
|
||||
(when (equal (+workspace-current-name) +regex-workspace-name)
|
||||
(+workspace/delete +regex-workspace-name))
|
||||
(mapc (lambda (bufname)
|
||||
(let ((buf (symbol-value bufname)))
|
||||
(when (and buf (buffer-live-p buf))
|
||||
(kill-buffer buf)
|
||||
(set bufname nil))))
|
||||
(list '+regex--text-replace-buffer
|
||||
'+regex--expr-replace-buffer
|
||||
'+regex--expr-buffer
|
||||
'+regex--groups-buffer
|
||||
'+regex--replace-buffer)))
|
||||
|
||||
(defun +regex--expr ()
|
||||
(when (buffer-live-p +regex--expr-buffer)
|
||||
(with-current-buffer +regex--expr-buffer
|
||||
(string-trim (buffer-string)))))
|
||||
|
||||
(defun +regex--expr-replace ()
|
||||
(when (buffer-live-p +regex--expr-replace-buffer)
|
||||
(with-current-buffer +regex--expr-replace-buffer
|
||||
(string-trim (buffer-string)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +regex-update-buffers (&optional beg end len)
|
||||
(interactive)
|
||||
(let* ((inhibit-read-only t)
|
||||
(regex (or (+regex--expr) ""))
|
||||
(replace (or (+regex--expr-replace) ""))
|
||||
(str (or (with-current-buffer +regex--text-buffer (buffer-string)) "")))
|
||||
(with-current-buffer +regex--groups-buffer
|
||||
(erase-buffer))
|
||||
(with-current-buffer +regex--text-buffer
|
||||
(remove-overlays nil nil 'category '+regex)
|
||||
(when (> (length regex) 0)
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(pcase +regex-default-backend
|
||||
('emacs (+regex-backend-emacs regex replace str))
|
||||
('perl (+regex-backend-perl regex replace str))))))
|
||||
(with-current-buffer +regex--groups-buffer
|
||||
(goto-char (point-min)))))
|
||||
|
||||
|
||||
;; --- backends ---------------------------
|
||||
|
||||
(defun +regex--render-perl (regex text)
|
||||
"From <https://github.com/jwiegley/regex-tool>"
|
||||
(with-temp-buffer
|
||||
(insert (format "@lines = <DATA>;
|
||||
$line = join(\"\", @lines);
|
||||
print \"(\";
|
||||
while ($line =~ m/%s/gm) {
|
||||
print \"(\", length($`), \" \", length($&), \" \";
|
||||
for $i (1 .. 20) {
|
||||
if ($$i) {
|
||||
my $group = $$i;
|
||||
$group =~ s/([\\\\\"])/\\\\\\1/g;
|
||||
print \"(\", $i, \" . \\\"\", $group, \"\\\") \";
|
||||
}
|
||||
}
|
||||
print \")\";
|
||||
}
|
||||
print \")\";
|
||||
__DATA__
|
||||
%s" (replace-regexp-in-string "/" "\\/" regex nil t) text))
|
||||
(call-process-region (point-min) (point-max) "perl" t t)
|
||||
(goto-char (point-min))
|
||||
(read (current-buffer))))
|
||||
|
||||
(defun +regex--replace-perl (regex replace text)
|
||||
(unless (or (string-empty-p regex)
|
||||
(string-empty-p replace)
|
||||
(string-empty-p text))
|
||||
(with-temp-buffer
|
||||
(insert (format "@lines = <DATA>;
|
||||
$line = join(\"\", @lines);
|
||||
$line =~ s/%s/%s/gm;
|
||||
print $line;
|
||||
__DATA__
|
||||
%s" (replace-regexp-in-string "/" "\\/" regex nil t) (replace-regexp-in-string "/" "\\/" replace nil t) text))
|
||||
(call-process-region (point-min) (point-max) "perl" t t)
|
||||
(buffer-string))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +regex-backend-perl (regex replace str)
|
||||
"TODO"
|
||||
(cl-assert (stringp regex))
|
||||
(cl-assert (stringp replace))
|
||||
(cl-assert (stringp str))
|
||||
(let ((i 0)
|
||||
(results (+regex--render-perl regex str)))
|
||||
(when (buffer-live-p +regex--text-replace-buffer)
|
||||
(let ((replace (+regex--replace-perl regex replace str)))
|
||||
(with-current-buffer +regex--text-replace-buffer
|
||||
(erase-buffer)
|
||||
(insert
|
||||
(if (and (listp results)
|
||||
replace
|
||||
(not (string-empty-p replace)))
|
||||
replace
|
||||
str)))))
|
||||
(dolist (result (if (listp results) results))
|
||||
(let* ((offset (nth 0 result))
|
||||
(length (nth 1 result))
|
||||
(matches (nthcdr 2 result))
|
||||
(ov (make-overlay (1+ offset) (+ offset length 1))))
|
||||
(overlay-put ov 'face (nth (mod i 3) +regex-faces))
|
||||
(overlay-put ov 'category '+regex)
|
||||
(cl-incf i)
|
||||
(let* ((match-zero (buffer-substring (1+ offset) (+ offset length 1)))
|
||||
(line (format "Match: %s\n" (propertize match-zero 'face 'font-lock-string-face))))
|
||||
(with-current-buffer +regex--groups-buffer
|
||||
(insert line)))
|
||||
(dolist (match matches)
|
||||
(with-current-buffer +regex--groups-buffer
|
||||
(goto-char (point-max))
|
||||
(insert (format "Group %d: %s\n"
|
||||
(propertize (car match) 'face 'font-lock-constant-face)
|
||||
(propertize (cdr match) 'face 'font-lock-string-face)))))
|
||||
(with-current-buffer +regex--groups-buffer
|
||||
(insert ?\n))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +regex-backend-emacs (regex replace str)
|
||||
"TODO"
|
||||
(cl-assert (stringp regex))
|
||||
(cl-assert (stringp replace))
|
||||
(cl-assert (stringp str))
|
||||
(let ((i 0)
|
||||
pos)
|
||||
(when (buffer-live-p +regex--text-replace-buffer)
|
||||
(with-current-buffer +regex--text-replace-buffer
|
||||
(erase-buffer)
|
||||
(insert str)
|
||||
(when (and (listp results) (string-empty-p replace))
|
||||
(replace-regexp regex replace))))
|
||||
(while (and (setq pos (point))
|
||||
(re-search-forward regex nil t))
|
||||
(if (= (point) pos)
|
||||
(forward-char 1)
|
||||
(let ((ov (make-overlay (match-beginning 0) (match-end 0))))
|
||||
(overlay-put ov 'face (nth (mod i 3) +regex-faces))
|
||||
(overlay-put ov 'category '+regex))
|
||||
(cl-incf i)
|
||||
(dotimes (i 10)
|
||||
(when-let (text (match-string i))
|
||||
(save-match-data
|
||||
(with-current-buffer +regex--groups-buffer
|
||||
(goto-char (point-max))
|
||||
(insert
|
||||
(format "Group %d: %s\n"
|
||||
(propertize i 'face 'font-lock-constant-face)
|
||||
(propertize text 'face 'font-lock-string-face)))))))
|
||||
(with-current-buffer +regex--groups-buffer
|
||||
(insert ?\n))))))
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
;;; app/regex/config.el
|
||||
|
||||
;; Often, I find myself writing regular expressions that could terrify seasoned
|
||||
;; programmers (or little children). To hone my regex fu, I need a regex
|
||||
;; playground. Sure, there's regexr.com, but don't be silly, that's not Emacs.
|
||||
;;
|
||||
;; Sadly, the Emacs' regex syntax is niche and lacks support for a few
|
||||
;; questionably useful features, like lookaround assertions, conditionals, case
|
||||
;; modifiers or backreferences, among others. No, I want PCRE. I am going to
|
||||
;; have my cake and eat it too, damn it!
|
||||
;;
|
||||
;; Workflow:
|
||||
;; + Invoke `=regex' (if opened with C-u, opens in separate workspace with a
|
||||
;; dummy text buffer).
|
||||
;; + A regex window will popup up. Any matches will be highlighted in the
|
||||
;; original buffer.
|
||||
;; + C-c C-k to close it
|
||||
;; + TODO C-c C-e to export to various langauges
|
||||
;;
|
||||
;; WARNING: THIS IS A WORK IN PROGRESS
|
||||
|
||||
(defvar +regex-workspace-name "*regex*"
|
||||
"TODO")
|
||||
|
||||
(defvar +regex-default-backend 'perl
|
||||
"The backend used to process regular expressions.
|
||||
The `emacs' backend handles regular expressions directly.
|
||||
The `perl' backend talks to a perl subprocess to do the handling.")
|
||||
|
||||
(defvar +regex-dummy-text
|
||||
"Welcome to DOOM Emacs, proudly hosted by the demons of hell!
|
||||
|
||||
Edit the Expression & Text to see matches. Roll over matches or the expression
|
||||
for details. Undo mistakes with ctrl-z. Save Favorites & Share expressions with
|
||||
friends or the Community. Explore your results with Tools. A full Reference &
|
||||
Help is available in the Library, or watch the video Tutorial.
|
||||
|
||||
Sample text for testing:
|
||||
abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ
|
||||
0123456789 _+-.,!@#$%^&*();\/|<>\"'
|
||||
12345 -98.7 3.141 .6180 9,000 +42
|
||||
555.123.4567 +1-(800)-555-2468
|
||||
foo@demo.net bar.ba@test.co.uk
|
||||
www.demo.com http://foo.co.uk/
|
||||
http://regexr.com/foo.html?q=bar
|
||||
https://mediatemple.net"
|
||||
"TODO")
|
||||
|
||||
(set-popup-rules!
|
||||
'(("^\\*doom-regex\\*$" :size 4 :quit nil)
|
||||
("^\\*doom-regex-groups" :side 'left :size 28 :select nil :quit nil)))
|
||||
@@ -70,7 +70,7 @@
|
||||
(let ((search-buffers (doom-buffers-in-mode 'elfeed-search-mode))
|
||||
(show-buffers (doom-buffers-in-mode 'elfeed-show-mode))
|
||||
kill-buffer-query-functions)
|
||||
(dolist (file +rss-elfeed-files)
|
||||
(dolist (file (bound-and-true-p rmh-elfeed-org-files))
|
||||
(when-let (buf (get-file-buffer (expand-file-name file org-directory)))
|
||||
(kill-buffer buf)))
|
||||
(dolist (b search-buffers)
|
||||
@@ -101,10 +101,9 @@
|
||||
;;;###autoload
|
||||
(defun +rss-put-sliced-image-fn (spec alt &optional flags)
|
||||
"TODO"
|
||||
(cl-letf (((symbol-function #'insert-image)
|
||||
(lambda (image &optional alt _area _slice)
|
||||
(let ((height (cdr (image-size image t))))
|
||||
(insert-sliced-image image alt nil (max 1 (/ height 20.0)) 1)))))
|
||||
(letf! (defun insert-image (image &optional alt _area _slice)
|
||||
(let ((height (cdr (image-size image t))))
|
||||
(insert-sliced-image image alt nil (max 1 (/ height 20.0)) 1)))
|
||||
(shr-put-image spec alt flags)))
|
||||
|
||||
;;;###autoload
|
||||
|
||||
@@ -4,10 +4,6 @@
|
||||
;; by apps Reeder and Readkit. It can be invoked via `=rss'. Otherwise, if you
|
||||
;; don't care for the UI you can invoke elfeed directly with `elfeed'.
|
||||
|
||||
(defvar +rss-elfeed-files (list "elfeed.org")
|
||||
"Where to look for elfeed.org files, relative to `org-directory'. Can be
|
||||
absolute paths.")
|
||||
|
||||
(defvar +rss-split-direction 'below
|
||||
"What direction to pop up the entry buffer in elfeed.")
|
||||
|
||||
@@ -21,10 +17,11 @@ easier to scroll through.")
|
||||
|
||||
(use-package! elfeed
|
||||
:commands elfeed
|
||||
:init
|
||||
(setq elfeed-db-directory (concat doom-local-dir "elfeed/db/")
|
||||
elfeed-enclosure-default-dir (concat doom-local-dir "elfeed/enclosures/"))
|
||||
:config
|
||||
(setq elfeed-search-filter "@2-week-ago "
|
||||
elfeed-db-directory (concat doom-local-dir "elfeed/db/")
|
||||
elfeed-enclosure-default-dir (concat doom-local-dir "elfeed/enclosures/")
|
||||
elfeed-show-entry-switch #'pop-to-buffer
|
||||
elfeed-show-entry-delete #'+rss/delete-pane
|
||||
shr-max-image-proportion 0.8)
|
||||
@@ -67,8 +64,11 @@ easier to scroll through.")
|
||||
(use-package! elfeed-org
|
||||
:when (featurep! +org)
|
||||
:after elfeed
|
||||
:preface
|
||||
(setq rmh-elfeed-org-files (list "elfeed.org"))
|
||||
:config
|
||||
(let ((default-directory org-directory))
|
||||
(setq rmh-elfeed-org-files
|
||||
(mapcar #'expand-file-name +rss-elfeed-files)))
|
||||
(elfeed-org))
|
||||
(and (let ((default-directory org-directory))
|
||||
(setq rmh-elfeed-org-files
|
||||
(cl-remove-if-not
|
||||
#'file-exists-p (mapcar #'expand-file-name rmh-elfeed-org-files))))
|
||||
(elfeed-org)))
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
;; -*- no-byte-compile: t; -*-
|
||||
;;; app/rss/packages.el
|
||||
|
||||
(package! elfeed)
|
||||
(package! elfeed-org)
|
||||
(package! elfeed :pin "d0405e63863e54a01200740a6717ac875eceabc1")
|
||||
(package! elfeed-org :pin "77b6bbf222487809813de260447d31c4c59902c9")
|
||||
|
||||
@@ -83,6 +83,7 @@ that works with the feature/popup module."
|
||||
"Open a visible link, username or hashtag in a `twittering-mode' buffer."
|
||||
(interactive)
|
||||
(require 'avy)
|
||||
;; REVIEW Is this necessary anymore with `link-hint'
|
||||
(let ((pt (avy-with +twitter/ace-link
|
||||
(avy--process
|
||||
(+twitter--collect-links)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
;; -*- no-byte-compile: t; -*-
|
||||
;;; app/twitter/packages.el
|
||||
|
||||
(package! twittering-mode)
|
||||
(package! avy)
|
||||
(package! twittering-mode :pin "114891e8fdb4f06b1326a6cf795e49c205cf9e29")
|
||||
(package! avy :pin "509471bad0e8094b8639729ec39ca141fae7d4bd")
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
#+TITLE: app/write
|
||||
#+DATE: October 10, 2019
|
||||
#+SINCE: v1.3
|
||||
#+STARTUP: inlineimages
|
||||
|
||||
* Table of Contents :TOC_3:noexport:
|
||||
- [[#description][Description]]
|
||||
- [[#module-flags][Module Flags]]
|
||||
- [[#plugins][Plugins]]
|
||||
- [[#prerequisites][Prerequisites]]
|
||||
- [[#language-tool][Language Tool]]
|
||||
- [[#wordnut][Wordnut]]
|
||||
- [[#features][Features]]
|
||||
- [[#m-x-write-mode][~M-x +write-mode~]]
|
||||
- [[#language-tool-langtool][Language Tool ~+langtool~]]
|
||||
- [[#commands][Commands]]
|
||||
- [[#wordnut-wordnut][Wordnut ~+wordnut~]]
|
||||
- [[#commands-1][Commands]]
|
||||
- [[#synosaurus][Synosaurus]]
|
||||
- [[#commands-2][Commands]]
|
||||
- [[#configuration][Configuration]]
|
||||
- [[#mixed-pitch-mode][mixed-pitch-mode]]
|
||||
- [[#appendix][Appendix]]
|
||||
- [[#minor-modes][Minor modes]]
|
||||
- [[#commands-3][Commands]]
|
||||
|
||||
* Description
|
||||
Adds word processing tools and the ~+write-mode~ minor mode, which converts
|
||||
Emacs into a more comfortable writing environment.
|
||||
|
||||
** Module Flags
|
||||
This module provides two module flags:
|
||||
|
||||
- ~+langtool~ Enables language tool integration.
|
||||
- ~+wordnut~ Enables wordnet integration.
|
||||
|
||||
** Plugins
|
||||
+ [[https://github.com/hpdeifel/synosaurus][synosaurus]]
|
||||
+ [[https://gitlab.com/jabranham/mixed-pitch][mixed-pitch]]
|
||||
+ [[https://github.com/joostkremers/visual-fill-column][visual-fill-column]]
|
||||
+ [[https://github.com/mhayashi1120/Emacs-langtool][langtool]]* (=+langtool=)
|
||||
+ [[https://github.com/gromnitsky/wordnut][wordnut]]* (=+wordnut=)
|
||||
|
||||
* Prerequisites
|
||||
** Language Tool
|
||||
Either download and deploy it from https://languagetool.org/ or install it
|
||||
through your OS package manager:
|
||||
|
||||
#+BEGIN_SRC sh
|
||||
# MacOS/Homebrew users:
|
||||
brew install languagetool
|
||||
|
||||
# Arch Linux users:
|
||||
sudo pacman -S languagetool
|
||||
#+END_SRC
|
||||
|
||||
This module tries to guess the location of languagetool-commandline.jar. If you
|
||||
get a warning that Doom =couldn't find languagetool-commandline.jar=, you will
|
||||
need to find langaugetool-commandline.jar and set ~langtool-language-tool-jar~
|
||||
to its path.
|
||||
|
||||
** Wordnut
|
||||
This requires =wordnet= to be installed, which should be available through your
|
||||
OS package manager:
|
||||
|
||||
#+BEGIN_SRC sh
|
||||
# MacOS/Homebrew users:
|
||||
brew install wordnet
|
||||
|
||||
# Arch Linux users:
|
||||
sudo pacaur -S wordnet # on the AUR
|
||||
#+END_SRC
|
||||
|
||||
* Features
|
||||
** ~M-x +write-mode~
|
||||
Write mode makes Emacs a more comfortable writing environment by:
|
||||
|
||||
- Centering the buffer (with ~visual-fill-column-mode~), ala distraction-free
|
||||
mode from other text editors.
|
||||
- Soft-wrapping long text lines with ~visual-line-mode~.
|
||||
- Enabling ~mixed-pitch-mode~, allowing fixed-width and variable-pitch fonts to
|
||||
co-exist in one buffer. For example, a monospace font for SRC blocks and Arial
|
||||
for everything else.
|
||||
- In org-mode:
|
||||
- Turns on ~org-indent-mode~
|
||||
- Turns on ~+org-pretty-mode~
|
||||
|
||||
** Language Tool ~+langtool~
|
||||
[[https://www.languagetool.org/][Language Tool]] is a polyglot proofreader service that checks for grammar and
|
||||
stylistic issues in your writing. This requires Java 1.8+.
|
||||
|
||||
#+begin_quote
|
||||
This requires Java 1.8+
|
||||
#+end_quote
|
||||
|
||||
*** Commands
|
||||
- ~langtool-check~
|
||||
- ~langtool-correct-buffer~
|
||||
|
||||
** Wordnut ~+wordnut~
|
||||
Wordnut provides a searchable dictionary frontend for Emacs. This requires
|
||||
~wordnet~, which should be available in your OS's package manager.
|
||||
|
||||
*** Commands
|
||||
- ~wordnut-search~
|
||||
- ~wordnut-lookup-curent-word~
|
||||
|
||||
** Synosaurus
|
||||
Synosaurus provides a service for looking up synonyms. It requires an internet
|
||||
connection.
|
||||
|
||||
*** Commands
|
||||
- ~synosaurus-lookup~
|
||||
- ~synosaurus-choose-and-replace~
|
||||
|
||||
* Configuration
|
||||
** mixed-pitch-mode
|
||||
To configure which faces are displayed with fixed-pitch fonts in
|
||||
~mixed-pitch-mode~, look into ~mixed-pitch-fixed-pitch-faces~.
|
||||
|
||||
* Appendix
|
||||
** Minor modes
|
||||
- ~+write-mode~
|
||||
- ~mixed-pitch-mode~
|
||||
** Commands
|
||||
- ~langtool-check~
|
||||
- ~langtool-correct-buffer~
|
||||
- ~synosaurus-choose-and-replace~
|
||||
- ~synosaurus-lookup~
|
||||
- ~wordnut-lookup-curent-word~
|
||||
- ~wordnut-search~
|
||||
@@ -1,43 +0,0 @@
|
||||
;;; app/write/autoload.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;;###autoload
|
||||
(defvar +write-mode-map (make-sparse-keymap)
|
||||
"TODO")
|
||||
|
||||
;;;###autoload
|
||||
(define-minor-mode +write-mode
|
||||
"Turns Emacs into a more comfortable writing environment and word processor."
|
||||
:init-value nil
|
||||
:keymap +write-mode-map
|
||||
(setq-local visual-fill-column-center-text t)
|
||||
(when +write-text-scale
|
||||
(text-scale-set (if +write-mode 2 0)))
|
||||
(when +write-line-spacing
|
||||
(setq-local line-spacing +write-line-spacing)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +write-init-org-mode-h ()
|
||||
"Initializes `org-mode' specific settings for `+write-mode'."
|
||||
(when (eq major-mode 'org-mode)
|
||||
(+org-pretty-mode (if +write-mode +1 -1))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +write-init-line-numbers-h ()
|
||||
(display-line-numbers-mode (if +write-mode +1 -1)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +write-init-mixed-pitch-h ()
|
||||
(mixed-pitch-mode (if +write-mode +1 -1)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +write-init-visual-fill-column-h ()
|
||||
(visual-fill-column-mode (if +write-mode +1 -1)))
|
||||
|
||||
;;;###autoload
|
||||
(add-hook! '+write-mode-hook
|
||||
#'(flyspell-mode
|
||||
visual-line-mode
|
||||
+write-init-mixed-pitch-h
|
||||
+write-init-visual-fill-column-h
|
||||
+write-init-line-numbers-h
|
||||
+write-init-org-mode-h))
|
||||
@@ -1,56 +0,0 @@
|
||||
;;; app/write/config.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defvar +write-text-scale nil
|
||||
"What to scale the text up to in `+write-mode'. Uses `text-scale-set'.")
|
||||
|
||||
(defvar +write-line-spacing nil
|
||||
"What to set `line-spacing' in `+write-mode'.")
|
||||
|
||||
;;
|
||||
;; Packages
|
||||
|
||||
(use-package! langtool
|
||||
:when (featurep! +langtool)
|
||||
:commands (langtool-check
|
||||
langtool-check-done
|
||||
langtool-show-message-at-point
|
||||
langtool-correct-buffer)
|
||||
:init (setq langtool-default-language "en-US")
|
||||
:config
|
||||
(unless langtool-language-tool-jar
|
||||
(setq langtool-language-tool-jar
|
||||
(cond (IS-MAC
|
||||
(locate-file "libexec/languagetool-commandline.jar"
|
||||
(doom-files-in "/usr/local/Cellar/languagetool"
|
||||
:type 'dirs
|
||||
:depth 2)))
|
||||
(IS-LINUX
|
||||
"/usr/share/java/languagetool/languagetool-commandline.jar")))))
|
||||
|
||||
|
||||
;; `synosaurus'
|
||||
(setq synosaurus-choose-method 'default)
|
||||
|
||||
|
||||
;; `mixed-pitch'
|
||||
(after! mixed-pitch
|
||||
(setq mixed-pitch-fixed-pitch-faces
|
||||
(append mixed-pitch-fixed-pitch-faces
|
||||
'(org-todo-keyword-todo
|
||||
org-todo-keyword-habt
|
||||
org-todo-keyword-done
|
||||
org-todo-keyword-wait
|
||||
org-todo-keyword-kill
|
||||
org-todo-keyword-outd
|
||||
org-todo
|
||||
org-indent
|
||||
line-number
|
||||
line-number-current-line
|
||||
org-special-keyword
|
||||
org-date
|
||||
org-property-value
|
||||
org-special-keyword
|
||||
org-property-value
|
||||
org-ref-cite-face
|
||||
org-tag
|
||||
font-lock-comment-face))))
|
||||
@@ -1,7 +0,0 @@
|
||||
;; -*- lexical-binding: t; no-byte-compile: t; -*-
|
||||
;;; app/write/doctor.el
|
||||
|
||||
(when (featurep! +langtool)
|
||||
(require 'langtool)
|
||||
(unless (file-exists-p langtool-language-tool-jar)
|
||||
(warn! "Couldn't find languagetool-commandline.jar")))
|
||||
@@ -1,12 +0,0 @@
|
||||
;; -*- no-byte-compile: t; -*-
|
||||
;;; app/write/packages.el
|
||||
|
||||
(package! synosaurus)
|
||||
(package! mixed-pitch)
|
||||
|
||||
(when (featurep! +langtool)
|
||||
(package! langtool))
|
||||
(when (featurep! +wordnut)
|
||||
(package! wordnut))
|
||||
|
||||
(package! visual-fill-column)
|
||||
@@ -116,7 +116,7 @@ There is no guarantee your language mode will have completion support.
|
||||
|
||||
Some, like ~lua-mode~, don't have completion support in Emacs at all. Others may
|
||||
requires additional setup to get code completion working. For instance,
|
||||
~go-mode~ requires ~guru~ to be installed on your system, and ~enh-ruby-mode~
|
||||
~go-mode~ requires ~guru~ to be installed on your system, and ~ruby-mode~
|
||||
requires that you have a Robe server running (~M-x robe-start~).
|
||||
|
||||
Check the relevant module's documentation for this kind of information.
|
||||
|
||||
@@ -67,11 +67,10 @@ Examples:
|
||||
;;;###autoload
|
||||
(defun +company-init-backends-h ()
|
||||
"Set `company-backends' for the current buffer."
|
||||
(if (not company-mode)
|
||||
(remove-hook 'change-major-mode-after-body-hook #'+company-init-backends-h 'local)
|
||||
(unless (eq major-mode 'fundamental-mode)
|
||||
(setq-local company-backends (+company--backends)))
|
||||
(add-hook 'change-major-mode-after-body-hook #'+company-init-backends-h nil 'local)))
|
||||
(or (memq major-mode '(fundamental-mode special-mode))
|
||||
buffer-read-only
|
||||
(doom-temp-buffer-p (or (buffer-base-buffer) (current-buffer)))
|
||||
(setq-local company-backends (+company--backends))))
|
||||
|
||||
(put '+company-init-backends-h 'permanent-local-hook t)
|
||||
|
||||
|
||||
@@ -2,25 +2,49 @@
|
||||
|
||||
(use-package! company
|
||||
:commands company-complete-common company-manual-begin company-grab-line
|
||||
:after-call pre-command-hook after-find-file
|
||||
:hook (doom-first-input . global-company-mode)
|
||||
:init
|
||||
(setq company-minimum-prefix-length 2
|
||||
(setq company-idle-delay 0.25
|
||||
company-minimum-prefix-length 2
|
||||
company-tooltip-limit 14
|
||||
company-dabbrev-downcase nil
|
||||
company-dabbrev-ignore-case nil
|
||||
company-dabbrev-code-other-buffers t
|
||||
company-tooltip-align-annotations t
|
||||
company-require-match 'never
|
||||
company-global-modes
|
||||
'(not erc-mode message-mode help-mode gud-mode eshell-mode)
|
||||
company-backends '(company-capf)
|
||||
company-frontends
|
||||
'(company-pseudo-tooltip-frontend
|
||||
company-echo-metadata-frontend))
|
||||
'(not erc-mode message-mode help-mode gud-mode)
|
||||
company-frontends '(company-pseudo-tooltip-frontend
|
||||
company-echo-metadata-frontend)
|
||||
|
||||
;; Buffer-local backends will be computed when loading a major mode, so
|
||||
;; only specify a global default here.
|
||||
company-backends '(company-capf)
|
||||
|
||||
;; Company overrides `company-active-map' based on
|
||||
;; `company-auto-complete-chars'; no magic please!
|
||||
company-auto-complete-chars nil
|
||||
|
||||
;; Only search the current buffer for `company-dabbrev' (a backend that
|
||||
;; suggests text your open buffers). This prevents Company from causing
|
||||
;; lag once you have a lot of buffers open.
|
||||
company-dabbrev-other-buffers nil
|
||||
;; Make `company-dabbrev' fully case-sensitive, to improve UX with
|
||||
;; domain-specific words with particular casing.
|
||||
company-dabbrev-ignore-case nil
|
||||
company-dabbrev-downcase nil)
|
||||
|
||||
:config
|
||||
(when (featurep! :editor evil)
|
||||
(add-hook 'company-mode-hook #'evil-normalize-keymaps)
|
||||
|
||||
(unless (featurep! +childframe)
|
||||
;; Don't persist company popups when switching back to normal mode.
|
||||
;; `company-box' aborts on mode switch so it doesn't need this.
|
||||
(add-hook! 'evil-normal-state-entry-hook
|
||||
(defun +company-abort-h ()
|
||||
;; HACK `company-abort' doesn't no-op if company isn't active; causing
|
||||
;; unwanted side-effects, like the suppression of messages in the
|
||||
;; echo-area.
|
||||
;; REVIEW Revisit this to refactor; shouldn't be necessary!
|
||||
(when company-candidates
|
||||
(company-abort)))))
|
||||
;; Allow users to switch between backends on the fly. E.g. C-x C-s followed
|
||||
;; by C-x C-n, will switch from `company-yasnippet' to
|
||||
;; `company-dabbrev-code'.
|
||||
@@ -28,8 +52,7 @@
|
||||
:before #'company-begin-backend
|
||||
(company-abort)))
|
||||
|
||||
(add-hook 'company-mode-hook #'+company-init-backends-h)
|
||||
(global-company-mode +1))
|
||||
(add-hook 'after-change-major-mode-hook #'+company-init-backends-h 'append))
|
||||
|
||||
|
||||
(use-package! company-tng
|
||||
@@ -49,8 +72,7 @@
|
||||
;; Packages
|
||||
|
||||
(after! company-files
|
||||
(pushnew! company-files--regexps
|
||||
"file:\\(\\(?:\\.\\{1,2\\}/\\|~/\\|/\\)[^\]\n]*\\)"))
|
||||
(add-to-list 'company-files--regexps "file:\\(\\(?:\\.\\{1,2\\}/\\|~/\\|/\\)[^\]\n]*\\)"))
|
||||
|
||||
|
||||
(use-package! company-prescient
|
||||
@@ -70,47 +92,44 @@
|
||||
company-box-max-candidates 50
|
||||
company-box-icons-alist 'company-box-icons-all-the-icons
|
||||
company-box-icons-functions
|
||||
'(+company-box-icons--yasnippet-fn
|
||||
company-box-icons--lsp
|
||||
+company-box-icons--elisp-fn
|
||||
company-box-icons--acphp)
|
||||
(cons #'+company-box-icons--elisp-fn
|
||||
(delq 'company-box-icons--elisp
|
||||
company-box-icons-functions))
|
||||
company-box-icons-all-the-icons
|
||||
`((Unknown . ,(all-the-icons-material "find_in_page" :height 0.8 :face 'all-the-icons-purple))
|
||||
(Text . ,(all-the-icons-material "text_fields" :height 0.8 :face 'all-the-icons-green))
|
||||
(Method . ,(all-the-icons-material "functions" :height 0.8 :face 'all-the-icons-red))
|
||||
(Function . ,(all-the-icons-material "functions" :height 0.8 :face 'all-the-icons-red))
|
||||
(Constructor . ,(all-the-icons-material "functions" :height 0.8 :face 'all-the-icons-red))
|
||||
(Field . ,(all-the-icons-material "functions" :height 0.8 :face 'all-the-icons-red))
|
||||
(Variable . ,(all-the-icons-material "adjust" :height 0.8 :face 'all-the-icons-blue))
|
||||
(Class . ,(all-the-icons-material "class" :height 0.8 :face 'all-the-icons-red))
|
||||
(Interface . ,(all-the-icons-material "settings_input_component" :height 0.8 :face 'all-the-icons-red))
|
||||
(Module . ,(all-the-icons-material "view_module" :height 0.8 :face 'all-the-icons-red))
|
||||
(Property . ,(all-the-icons-material "settings" :height 0.8 :face 'all-the-icons-red))
|
||||
(Unit . ,(all-the-icons-material "straighten" :height 0.8 :face 'all-the-icons-red))
|
||||
(Value . ,(all-the-icons-material "filter_1" :height 0.8 :face 'all-the-icons-red))
|
||||
(Enum . ,(all-the-icons-material "plus_one" :height 0.8 :face 'all-the-icons-red))
|
||||
(Keyword . ,(all-the-icons-material "filter_center_focus" :height 0.8 :face 'all-the-icons-red))
|
||||
(Snippet . ,(all-the-icons-material "short_text" :height 0.8 :face 'all-the-icons-red))
|
||||
(Color . ,(all-the-icons-material "color_lens" :height 0.8 :face 'all-the-icons-red))
|
||||
(File . ,(all-the-icons-material "insert_drive_file" :height 0.8 :face 'all-the-icons-red))
|
||||
(Reference . ,(all-the-icons-material "collections_bookmark" :height 0.8 :face 'all-the-icons-red))
|
||||
(Folder . ,(all-the-icons-material "folder" :height 0.8 :face 'all-the-icons-red))
|
||||
(EnumMember . ,(all-the-icons-material "people" :height 0.8 :face 'all-the-icons-red))
|
||||
(Constant . ,(all-the-icons-material "pause_circle_filled" :height 0.8 :face 'all-the-icons-red))
|
||||
(Struct . ,(all-the-icons-material "streetview" :height 0.8 :face 'all-the-icons-red))
|
||||
(Event . ,(all-the-icons-material "event" :height 0.8 :face 'all-the-icons-red))
|
||||
(Operator . ,(all-the-icons-material "control_point" :height 0.8 :face 'all-the-icons-red))
|
||||
(TypeParameter . ,(all-the-icons-material "class" :height 0.8 :face 'all-the-icons-red))
|
||||
;; (Template . ,(company-box-icons-image "Template.png"))))
|
||||
(Yasnippet . ,(all-the-icons-material "short_text" :height 0.8 :face 'all-the-icons-green))
|
||||
(ElispFunction . ,(all-the-icons-material "functions" :height 0.8 :face 'all-the-icons-red))
|
||||
(ElispVariable . ,(all-the-icons-material "check_circle" :height 0.8 :face 'all-the-icons-blue))
|
||||
(ElispFeature . ,(all-the-icons-material "stars" :height 0.8 :face 'all-the-icons-orange))
|
||||
(ElispFace . ,(all-the-icons-material "format_paint" :height 0.8 :face 'all-the-icons-pink))))
|
||||
(let ((all-the-icons-scale-factor 0.8))
|
||||
`((Unknown . ,(all-the-icons-material "find_in_page" :face 'all-the-icons-purple))
|
||||
(Text . ,(all-the-icons-material "text_fields" :face 'all-the-icons-green))
|
||||
(Method . ,(all-the-icons-material "functions" :face 'all-the-icons-red))
|
||||
(Function . ,(all-the-icons-material "functions" :face 'all-the-icons-red))
|
||||
(Constructor . ,(all-the-icons-material "functions" :face 'all-the-icons-red))
|
||||
(Field . ,(all-the-icons-material "functions" :face 'all-the-icons-red))
|
||||
(Variable . ,(all-the-icons-material "adjust" :face 'all-the-icons-blue))
|
||||
(Class . ,(all-the-icons-material "class" :face 'all-the-icons-red))
|
||||
(Interface . ,(all-the-icons-material "settings_input_component" :face 'all-the-icons-red))
|
||||
(Module . ,(all-the-icons-material "view_module" :face 'all-the-icons-red))
|
||||
(Property . ,(all-the-icons-material "settings" :face 'all-the-icons-red))
|
||||
(Unit . ,(all-the-icons-material "straighten" :face 'all-the-icons-red))
|
||||
(Value . ,(all-the-icons-material "filter_1" :face 'all-the-icons-red))
|
||||
(Enum . ,(all-the-icons-material "plus_one" :face 'all-the-icons-red))
|
||||
(Keyword . ,(all-the-icons-material "filter_center_focus" :face 'all-the-icons-red))
|
||||
(Snippet . ,(all-the-icons-material "short_text" :face 'all-the-icons-red))
|
||||
(Color . ,(all-the-icons-material "color_lens" :face 'all-the-icons-red))
|
||||
(File . ,(all-the-icons-material "insert_drive_file" :face 'all-the-icons-red))
|
||||
(Reference . ,(all-the-icons-material "collections_bookmark" :face 'all-the-icons-red))
|
||||
(Folder . ,(all-the-icons-material "folder" :face 'all-the-icons-red))
|
||||
(EnumMember . ,(all-the-icons-material "people" :face 'all-the-icons-red))
|
||||
(Constant . ,(all-the-icons-material "pause_circle_filled" :face 'all-the-icons-red))
|
||||
(Struct . ,(all-the-icons-material "streetview" :face 'all-the-icons-red))
|
||||
(Event . ,(all-the-icons-material "event" :face 'all-the-icons-red))
|
||||
(Operator . ,(all-the-icons-material "control_point" :face 'all-the-icons-red))
|
||||
(TypeParameter . ,(all-the-icons-material "class" :face 'all-the-icons-red))
|
||||
(Template . ,(all-the-icons-material "short_text" :face 'all-the-icons-green))
|
||||
(ElispFunction . ,(all-the-icons-material "functions" :face 'all-the-icons-red))
|
||||
(ElispVariable . ,(all-the-icons-material "check_circle" :face 'all-the-icons-blue))
|
||||
(ElispFeature . ,(all-the-icons-material "stars" :face 'all-the-icons-orange))
|
||||
(ElispFace . ,(all-the-icons-material "format_paint" :face 'all-the-icons-pink)))))
|
||||
|
||||
(defun +company-box-icons--yasnippet-fn (candidate)
|
||||
(when (get-text-property 0 'yas-annotation candidate)
|
||||
'Yasnippet))
|
||||
(delq! 'company-echo-metadata-frontend company-frontends)
|
||||
|
||||
(defun +company-box-icons--elisp-fn (candidate)
|
||||
(when (derived-mode-p 'emacs-lisp-mode)
|
||||
@@ -118,7 +137,14 @@
|
||||
(cond ((fboundp sym) 'ElispFunction)
|
||||
((boundp sym) 'ElispVariable)
|
||||
((featurep sym) 'ElispFeature)
|
||||
((facep sym) 'ElispFace))))))
|
||||
((facep sym) 'ElispFace)))))
|
||||
|
||||
(defadvice! +company-remove-scrollbar-a (orig-fn &rest args)
|
||||
"This disables the company-box scrollbar, because:
|
||||
https://github.com/sebastiencs/company-box/issues/44"
|
||||
:around #'company-box--update-scrollbar
|
||||
(letf! ((#'display-buffer-in-side-window #'ignore))
|
||||
(apply orig-fn args))))
|
||||
|
||||
|
||||
(use-package! company-dict
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
;; -*- no-byte-compile: t; -*-
|
||||
;;; completion/company/packages.el
|
||||
|
||||
(package! company)
|
||||
(package! company-dict)
|
||||
(package! company-prescient)
|
||||
(package! company :pin "6333fc4ebbbf4d28e834de8715561e984f149ecb")
|
||||
(package! company-dict :pin "cd7b8394f6014c57897f65d335d6b2bd65dab1f4")
|
||||
(package! company-prescient :pin "0f4a89bdec61395138d968a38d375e63ccfbed63")
|
||||
(when (featurep! +childframe)
|
||||
(package! company-box))
|
||||
(package! company-box :pin "3814fcb14e92f4b85b19e664e216a7c8d5c7144d"))
|
||||
|
||||
@@ -38,7 +38,7 @@ workspace."
|
||||
;;; Project search
|
||||
|
||||
;;;###autoload
|
||||
(cl-defun +helm-file-search (&key query in all-files (recursive t))
|
||||
(cl-defun +helm-file-search (&key query in all-files (recursive t) _prompt args)
|
||||
"Conduct a file search using ripgrep.
|
||||
|
||||
:query STRING
|
||||
@@ -52,10 +52,13 @@ workspace."
|
||||
(unless (executable-find "rg")
|
||||
(user-error "Couldn't find ripgrep in your PATH"))
|
||||
(require 'helm-rg)
|
||||
(let ((helm-rg-default-directory (or in (doom-project-root) default-directory))
|
||||
(let ((this-command 'helm-rg)
|
||||
(helm-rg-default-directory (or in (doom-project-root) default-directory))
|
||||
(helm-rg-default-extra-args
|
||||
(delq nil (list (when all-files "-z -uu")
|
||||
(unless recursive "--maxdepth 1")))))
|
||||
(delq nil (append (list (when all-files "-z -uu")
|
||||
(unless recursive "--maxdepth 1"))
|
||||
args))))
|
||||
(setq deactivate-mark t)
|
||||
(helm-rg (or query
|
||||
(when (use-region-p)
|
||||
(let ((beg (or (bound-and-true-p evil-visual-beginning) (region-beginning)))
|
||||
|
||||
@@ -23,6 +23,7 @@ bottom, which is easier on the eyes on big displays."
|
||||
(setq +helm--posframe-buffer buffer)
|
||||
:position (point)
|
||||
:poshandler +helm-posframe-handler
|
||||
:respect-header-line helm-echo-input-in-header-line
|
||||
:width
|
||||
(max (cl-typecase .width
|
||||
(integer .width)
|
||||
|
||||
@@ -23,8 +23,7 @@ be negative.")
|
||||
;;; Packages
|
||||
|
||||
(use-package! helm-mode
|
||||
:defer t
|
||||
:after-call pre-command-hook
|
||||
:hook (doom-first-input . helm-mode)
|
||||
:init
|
||||
(map! [remap apropos] #'helm-apropos
|
||||
[remap find-library] #'helm-locate-library
|
||||
@@ -43,7 +42,6 @@ be negative.")
|
||||
[remap recentf-open-files] #'helm-recentf
|
||||
[remap yank-pop] #'helm-show-kill-ring)
|
||||
:config
|
||||
(helm-mode +1)
|
||||
;; helm is too heavy for `find-file-at-point'
|
||||
(add-to-list 'helm-completing-read-handlers-alist (cons #'find-file-at-point nil)))
|
||||
|
||||
@@ -57,8 +55,6 @@ be negative.")
|
||||
helm-mode-line-string nil
|
||||
helm-ff-auto-update-initial-value nil
|
||||
helm-find-files-doc-header nil
|
||||
;; Don't override evil-ex's completion
|
||||
helm-mode-handle-completion-in-region nil
|
||||
;; Default helm window sizes
|
||||
helm-display-buffer-default-width nil
|
||||
helm-display-buffer-default-height 0.25
|
||||
@@ -73,38 +69,37 @@ be negative.")
|
||||
|
||||
:init
|
||||
(when (featurep! +childframe)
|
||||
;; If this is set to 'iconify-top-level then Emacs will be minimized upon
|
||||
;; helm completion.
|
||||
(setq iconify-child-frame 'make-invisible)
|
||||
(setq helm-display-function #'+helm-posframe-display-fn))
|
||||
|
||||
(let ((fuzzy (featurep! +fuzzy)))
|
||||
(setq helm-M-x-fuzzy-match fuzzy
|
||||
helm-apropos-fuzzy-match fuzzy
|
||||
helm-apropos-fuzzy-match fuzzy
|
||||
(setq helm-apropos-fuzzy-match fuzzy
|
||||
helm-bookmark-show-location fuzzy
|
||||
helm-buffers-fuzzy-matching fuzzy
|
||||
helm-completion-in-region-fuzzy-match fuzzy
|
||||
helm-completion-in-region-fuzzy-match fuzzy
|
||||
helm-ff-fuzzy-matching fuzzy
|
||||
helm-file-cache-fuzzy-match fuzzy
|
||||
helm-flx-for-helm-locate fuzzy
|
||||
helm-imenu-fuzzy-match fuzzy
|
||||
helm-lisp-fuzzy-completion fuzzy
|
||||
helm-locate-fuzzy-match fuzzy
|
||||
helm-mode-fuzzy-match fuzzy
|
||||
helm-projectile-fuzzy-match fuzzy
|
||||
helm-recentf-fuzzy-match fuzzy
|
||||
helm-semantic-fuzzy-match fuzzy))
|
||||
helm-semantic-fuzzy-match fuzzy)
|
||||
;; Make sure that we have helm-multi-matching or fuzzy matching,
|
||||
;; (as prescribed by the fuzzy flag) also in the following cases:
|
||||
;; - helmized commands that use `completion-at-point' and similar functions
|
||||
;; - native commands that fall back to `completion-styles' like `helm-M-x'
|
||||
(push (if EMACS27+
|
||||
(if fuzzy 'flex 'helm)
|
||||
(if fuzzy 'helm-flex 'helm))
|
||||
completion-styles))
|
||||
|
||||
:config
|
||||
(set-popup-rule! "^\\*helm" :vslot -100 :size 0.22 :ttl nil)
|
||||
|
||||
;; HACK Doom doesn't support these commands, which invite the user to install
|
||||
;; the package via ELPA. Force them to use +helm/* instead, because they work
|
||||
;; out of the box.
|
||||
(advice-add #'helm-projectile-rg :override #'+helm/project-search)
|
||||
(advice-add #'helm-projectile-ag :override #'+helm/project-search)
|
||||
(advice-add #'helm-projectile-grep :override #'+helm/project-search)
|
||||
|
||||
;; Hide the modeline
|
||||
;; Hide the modeline in helm windows as it serves little purpose.
|
||||
(defun +helm--hide-mode-line (&rest _)
|
||||
(with-current-buffer (helm-buffer-get)
|
||||
(unless helm-mode-line-string
|
||||
@@ -113,11 +108,13 @@ be negative.")
|
||||
(advice-add #'helm-display-mode-line :override #'+helm--hide-mode-line)
|
||||
(advice-add #'helm-ag-show-status-default-mode-line :override #'ignore)
|
||||
|
||||
;; Hide minibuffer if `helm-echo-input-in-header-line'
|
||||
(add-hook 'helm-minibuffer-set-up-hook #'helm-hide-minibuffer-maybe)
|
||||
|
||||
;; Use helpful instead of describe-* to display documentation
|
||||
(dolist (fn '(helm-describe-variable helm-describe-function))
|
||||
(advice-add fn :around #'doom-use-helpful-a)))
|
||||
|
||||
|
||||
(use-package! helm-flx
|
||||
:when (featurep! +fuzzy)
|
||||
:hook (helm-mode . helm-flx-mode)
|
||||
@@ -131,7 +128,7 @@ be negative.")
|
||||
"C-c C-e" #'helm-rg--bounce)
|
||||
(map! :map helm-rg--bounce-mode-map
|
||||
"q" #'kill-current-buffer
|
||||
"C-c C-c" (λ! (helm-rg--bounce-dump) (kill-current-buffer))
|
||||
"C-c C-c" (cmd! (helm-rg--bounce-dump) (kill-current-buffer))
|
||||
"C-x C-c" #'helm-rg--bounce-dump-current-file
|
||||
"C-c C-k" #'kill-current-buffer))
|
||||
|
||||
@@ -183,3 +180,7 @@ be negative.")
|
||||
(lambda (buf &optional _resume) (pop-to-buffer buf)))
|
||||
(global-set-key [remap swiper] #'swiper-helm)
|
||||
(add-to-list 'swiper-font-lock-exclude #'+doom-dashboard-mode nil #'eq))
|
||||
|
||||
|
||||
(use-package! helm-descbinds
|
||||
:hook (helm-mode . helm-descbinds-mode))
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
;; -*- no-byte-compile: t; -*-
|
||||
;;; completion/helm/packages.el
|
||||
|
||||
(package! helm)
|
||||
(package! helm-rg)
|
||||
(package! helm-c-yasnippet)
|
||||
(package! helm-company)
|
||||
(package! helm-describe-modes :recipe (:host github :repo "emacs-helm/helm-describe-modes"))
|
||||
(package! helm-projectile)
|
||||
(package! swiper-helm)
|
||||
(package! helm :pin "b6db9fb47a8900704394e63b795f4a54cb4701a8")
|
||||
(package! helm-rg :pin "785a80fe5cc87e27c5ea3d00a70049028d9e2847")
|
||||
(package! helm-c-yasnippet :pin "65ca732b510bfc31636708aebcfe4d2d845b59b0")
|
||||
(package! helm-company :pin "6eb5c2d730a60e394e005b47c1db018697094dde")
|
||||
(package! helm-describe-modes
|
||||
:recipe (:host github :repo "emacs-helm/helm-describe-modes")
|
||||
:pin "11fb36af119b784539d31c6160002de1957408aa")
|
||||
(package! helm-projectile :pin "5328b74dddcee8d1913803ca8167868831a07463")
|
||||
(package! swiper-helm :pin "93fb6db87bc6a5967898b5fd3286954cc72a0008")
|
||||
(when (featurep! +fuzzy)
|
||||
(package! helm-flx))
|
||||
(package! helm-flx :pin "6640fac5cb16bee73c95b8ed1248a4e5e113690e"))
|
||||
(when (featurep! +childframe)
|
||||
(package! posframe))
|
||||
(package! posframe :pin "093b29a53cbeda6d637ccc9ef4dfc47123e79b9e"))
|
||||
(when (featurep! :lang org)
|
||||
(package! helm-org))
|
||||
(package! helm-org :pin "b7a18dfc17e8b933956d61d68c435eee03a96c24"))
|
||||
(package! helm-descbinds :pin "b72515982396b6e336ad7beb6767e95a80fca192")
|
||||
|
||||
@@ -1,59 +1,62 @@
|
||||
;;; completion/ido/config.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defun +ido-init-h ()
|
||||
(setq ido-ignore-buffers
|
||||
'("\\` " "^\\*ESS\\*" "^\\*Messages\\*" "^\\*Help\\*" "^\\*Buffer"
|
||||
"^\\*.*Completions\\*$" "^\\*Ediff" "^\\*tramp" "^\\*cvs-"
|
||||
"_region_" " output\\*$" "^TAGS$" "^\*Ido")
|
||||
ido-use-faces nil
|
||||
ido-confirm-unique-completion t
|
||||
ido-case-fold t
|
||||
ido-enable-tramp-completion nil
|
||||
ido-enable-flex-matching t
|
||||
ido-create-new-buffer 'always
|
||||
ido-enable-tramp-completion t
|
||||
ido-enable-last-directory-history t
|
||||
ido-save-directory-list-file (concat doom-cache-dir "ido.last"))
|
||||
(defvar ido-mode-hook nil
|
||||
"List of hooks to run when `ido-mode' is activated.")
|
||||
|
||||
(unless (member "\\`.DS_Store$" ido-ignore-files)
|
||||
(push "\\`.DS_Store$" ido-ignore-files)
|
||||
(push "Icon\\?$" ido-ignore-files))
|
||||
|
||||
(define-key! (ido-common-completion-map ido-completion-map ido-file-completion-map)
|
||||
"\C-n" #'ido-next-match
|
||||
"\C-p" #'ido-prev-match
|
||||
"\C-w" #'ido-delete-backward-word-updir
|
||||
;; Go to $HOME with ~
|
||||
"~" (λ! (if (looking-back "/" (point-min))
|
||||
(insert "~/")
|
||||
(call-interactively #'self-insert-command))))
|
||||
|
||||
(defadvice! +ido--sort-mtime-a ()
|
||||
"Sort ido filelist by mtime instead of alphabetically."
|
||||
:override #'ido-sort-mtime
|
||||
(setq ido-temp-list
|
||||
(sort ido-temp-list
|
||||
(lambda (a b)
|
||||
(time-less-p
|
||||
(sixth (file-attributes (concat ido-current-directory b)))
|
||||
(sixth (file-attributes (concat ido-current-directory a)))))))
|
||||
(ido-to-end ;; move . files to end (again)
|
||||
(cl-loop for x in ido-temp-list
|
||||
if (char-equal (string-to-char x) ?.)
|
||||
collect x)))
|
||||
(add-hook! '(ido-make-file-list-hook ido-make-dir-list-hook)
|
||||
#'ido-sort-mtime)
|
||||
|
||||
;;
|
||||
(ido-mode 1)
|
||||
(ido-everywhere 1)
|
||||
(ido-ubiquitous-mode 1)
|
||||
(ido-vertical-mode 1)
|
||||
(flx-ido-mode +1)
|
||||
(crm-custom-mode +1)
|
||||
|
||||
;;
|
||||
(remove-hook 'ido-setup-hook #'+ido-init-h))
|
||||
|
||||
;;
|
||||
(add-hook 'ido-setup-hook #'+ido-init-h)
|
||||
;;; Packages
|
||||
|
||||
(use-package! ido
|
||||
:hook (doom-first-input . ido-mode)
|
||||
:hook (ido-mode . ido-everywhere)
|
||||
:hook (ido-mode . ido-ubiquitous-mode)
|
||||
:preface
|
||||
;; HACK `ido' is a really old package. It defines `ido-mode' manually and
|
||||
;; doesn't define a hook, so we define one for it, so we can use it!
|
||||
(defadvice! +ido-run-hooks-a (&rest _)
|
||||
:after #'ido-mode
|
||||
(run-hooks 'ido-mode-hook))
|
||||
:init
|
||||
(setq ido-save-directory-list-file (concat doom-cache-dir "ido.last"))
|
||||
:config
|
||||
(pushnew! ido-ignore-files "\\`.DS_Store$" "Icon\\?$")
|
||||
(setq ido-ignore-buffers
|
||||
'("\\` " "^\\*ESS\\*" "^\\*Messages\\*" "^\\*[Hh]elp" "^\\*Buffer"
|
||||
"^\\*.*Completions\\*$" "^\\*Ediff" "^\\*tramp" "^\\*cvs-" "_region_"
|
||||
" output\\*$" "^TAGS$" "^\*Ido")
|
||||
ido-auto-merge-work-directories-length -1
|
||||
ido-confirm-unique-completion t
|
||||
ido-case-fold t
|
||||
ido-create-new-buffer 'always
|
||||
ido-enable-flex-matching t)
|
||||
|
||||
(map! :map (ido-common-completion-map ido-file-completion-map)
|
||||
"C-w" #'ido-delete-backward-word-updir
|
||||
:map (ido-common-completion-map ido-file-dir-completion-map)
|
||||
"C-n" #'ido-next-match
|
||||
"C-p" #'ido-prev-match
|
||||
[down] #'ido-next-match
|
||||
[up] #'ido-prev-match
|
||||
:map ido-file-completion-map
|
||||
;; Go to $HOME with ~
|
||||
"~" (cmd! (if (looking-back "/" (point-min))
|
||||
(insert "~/")
|
||||
(call-interactively #'self-insert-command)))))
|
||||
|
||||
|
||||
(use-package! ido-vertical-mode
|
||||
:hook (ido-mode . ido-vertical-mode)
|
||||
:config (setq ido-vertical-show-count t))
|
||||
|
||||
|
||||
(use-package! ido-sort-mtime
|
||||
:hook (ido-mode . ido-sort-mtime-mode))
|
||||
|
||||
|
||||
(use-package! crm-custom
|
||||
:hook (ido-mode . crm-custom-mode))
|
||||
|
||||
|
||||
(use-package! flx-ido
|
||||
:hook (ido-mode . flx-ido-mode))
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
;; -*- no-byte-compile: t; -*-
|
||||
;;; completion/ido/packages.el
|
||||
|
||||
(package! flx-ido)
|
||||
(package! ido-completing-read+)
|
||||
(package! ido-vertical-mode)
|
||||
(package! crm-custom)
|
||||
(package! flx-ido :pin "17f5c9cb2af18aa6f52910ff4a5a63591261ced5")
|
||||
(package! ido-completing-read+ :pin "98d3a6e56b1d3652da7b47f49f76d77f82ea80ba")
|
||||
(package! ido-sort-mtime :pin "f638ff0c922af862f5211779f2311a27fde428eb")
|
||||
(package! ido-vertical-mode :pin "16c4c1a112796ee0bcf401ea39d3e2643a89feaf")
|
||||
(package! crm-custom :pin "f1aaccf64306a5f99d9bf7ba815d7ea41c15518d")
|
||||
|
||||
@@ -136,7 +136,7 @@ These keybindings are available while a search is active:
|
||||
| =C-c C-o= | Open a buffer with your search results |
|
||||
| =C-c C-e= | Open a writable buffer of your search results |
|
||||
| =C-SPC= | Preview the current candidate |
|
||||
| =M-RET= | Open the selected candidate in other-window |
|
||||
| =C-RET= | Open the selected candidate in other-window |
|
||||
|
||||
Changes to the resulting wgrep buffer (opened by =C-c C-e=) can be committed
|
||||
with =C-c C-c= and aborted with =C-c C-k= (alternatively =ZZ= and =ZQ=, for evil
|
||||
|
||||
@@ -13,16 +13,6 @@
|
||||
(and (not (eq buffer (current-buffer)))
|
||||
(+workspace-contains-buffer-p buffer))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +ivy-standard-search (str)
|
||||
"TODO"
|
||||
(funcall +ivy-standard-search-fn str))
|
||||
|
||||
;;;###autoload
|
||||
(defun +ivy-alternative-search (str)
|
||||
"TODO"
|
||||
(funcall +ivy-alternative-search-fn str))
|
||||
|
||||
;;;###autoload
|
||||
(defun +ivy-rich-buffer-name (candidate)
|
||||
"Display the buffer name.
|
||||
@@ -188,7 +178,7 @@ If ARG (universal argument), open selection in other-window."
|
||||
(user-error "%S doesn't support wgrep" caller)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +ivy-yas-prompt (prompt choices &optional display-fn)
|
||||
(defun +ivy-yas-prompt-fn (prompt choices &optional display-fn)
|
||||
(yas-completing-prompt prompt choices display-fn #'ivy-completing-read))
|
||||
|
||||
;;;###autoload
|
||||
@@ -217,28 +207,33 @@ If ARG (universal argument), open selection in other-window."
|
||||
;;;###autoload
|
||||
(defun +ivy/projectile-find-file ()
|
||||
"A more sensible `counsel-projectile-find-file', which will revert to
|
||||
`counsel-find-file' if invoked from $HOME, `counsel-file-jump' if invoked from a
|
||||
non-project, `projectile-find-file' if in a big project (more than
|
||||
`counsel-find-file' if invoked from $HOME or /, `counsel-file-jump' if invoked
|
||||
from a non-project, `projectile-find-file' if in a big project (more than
|
||||
`ivy-sort-max-size' files), or `counsel-projectile-find-file' otherwise.
|
||||
|
||||
The point of this is to avoid Emacs locking up indexing massive file trees."
|
||||
(interactive)
|
||||
(call-interactively
|
||||
(cond ((or (file-equal-p default-directory "~")
|
||||
(when-let (proot (doom-project-root))
|
||||
(file-equal-p proot "~")))
|
||||
#'counsel-find-file)
|
||||
;; Spoof the command so that ivy/counsel will display the (well fleshed-out)
|
||||
;; actions list for `counsel-find-file' on C-o. The actions list for the other
|
||||
;; commands aren't as well configured or are empty.
|
||||
(let ((this-command 'counsel-find-file))
|
||||
(call-interactively
|
||||
(cond ((or (file-equal-p default-directory "~")
|
||||
(file-equal-p default-directory "/")
|
||||
(when-let (proot (doom-project-root))
|
||||
(file-equal-p proot "~")))
|
||||
#'counsel-find-file)
|
||||
|
||||
((doom-project-p)
|
||||
(let ((files (projectile-current-project-files)))
|
||||
(if (<= (length files) ivy-sort-max-size)
|
||||
#'counsel-projectile-find-file
|
||||
#'projectile-find-file)))
|
||||
((doom-project-p)
|
||||
(let ((files (projectile-current-project-files)))
|
||||
(if (<= (length files) ivy-sort-max-size)
|
||||
#'counsel-projectile-find-file
|
||||
#'projectile-find-file)))
|
||||
|
||||
(#'counsel-file-jump))))
|
||||
(#'counsel-file-jump)))))
|
||||
|
||||
;;;###autoload
|
||||
(cl-defun +ivy-file-search (&key query in all-files (recursive t))
|
||||
(cl-defun +ivy-file-search (&key query in all-files (recursive t) prompt args)
|
||||
"Conduct a file search using ripgrep.
|
||||
|
||||
:query STRING
|
||||
@@ -252,36 +247,34 @@ The point of this is to avoid Emacs locking up indexing massive file trees."
|
||||
(unless (executable-find "rg")
|
||||
(user-error "Couldn't find ripgrep in your PATH"))
|
||||
(require 'counsel)
|
||||
(let* ((ivy-more-chars-alist '((t . 1)))
|
||||
(let* ((this-command 'counsel-rg)
|
||||
(project-root (or (doom-project-root) default-directory))
|
||||
(directory (or in project-root))
|
||||
(default-directory directory)
|
||||
(args (concat (if all-files " -uu")
|
||||
(unless recursive " --maxdepth 1"))))
|
||||
(unless recursive " --maxdepth 1")
|
||||
" " (mapconcat #'shell-quote-argument args " "))))
|
||||
(setq deactivate-mark t)
|
||||
(counsel-rg
|
||||
(or (if query query)
|
||||
(when (use-region-p)
|
||||
(let ((beg (or (bound-and-true-p evil-visual-beginning) (region-beginning)))
|
||||
(end (or (bound-and-true-p evil-visual-end) (region-end))))
|
||||
(when (> (abs (- end beg)) 1)
|
||||
(let ((query (buffer-substring-no-properties beg end)))
|
||||
;; Escape characters that are special to ivy searches
|
||||
(replace-regexp-in-string "[! |]" (lambda (substr)
|
||||
(cond ((and (string= substr " ")
|
||||
(not (featurep! +fuzzy)))
|
||||
" ")
|
||||
((string= substr "|")
|
||||
"\\\\\\\\|")
|
||||
((concat "\\\\" substr))))
|
||||
(rxt-quote-pcre query)))))))
|
||||
(or query
|
||||
(when (doom-region-active-p)
|
||||
(replace-regexp-in-string
|
||||
"[! |]" (lambda (substr)
|
||||
(cond ((and (string= substr " ")
|
||||
(not (featurep! +fuzzy)))
|
||||
" ")
|
||||
((string= substr "|")
|
||||
"\\\\\\\\|")
|
||||
((concat "\\\\" substr))))
|
||||
(rxt-quote-pcre (doom-thing-at-point-or-region)))))
|
||||
directory args
|
||||
(format "rg%s %s"
|
||||
args
|
||||
(cond ((equal directory default-directory)
|
||||
"./")
|
||||
((equal directory project-root)
|
||||
(projectile-project-name))
|
||||
((file-relative-name directory project-root)))))))
|
||||
(or prompt
|
||||
(format "rg%s [%s]: "
|
||||
args
|
||||
(cond ((equal directory default-directory)
|
||||
"./")
|
||||
((equal directory project-root)
|
||||
(projectile-project-name))
|
||||
((file-relative-name directory project-root))))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +ivy/project-search (&optional arg initial-query directory)
|
||||
|
||||
@@ -14,33 +14,31 @@ When 'everything, also preview virtual buffers")
|
||||
"A plist mapping ivy/counsel commands to commands that generate an editable
|
||||
results buffer.")
|
||||
|
||||
(defvar +ivy-standard-search-fn
|
||||
(if (featurep! +prescient)
|
||||
#'+ivy-prescient-non-fuzzy
|
||||
#'ivy--regex-plus)
|
||||
"Function to use for non-fuzzy search commands.
|
||||
This uses the standard search algorithm ivy uses (or a variant of it).")
|
||||
|
||||
(defvar +ivy-alternative-search-fn
|
||||
(cond ((featurep! +prescient) #'ivy-prescient-re-builder)
|
||||
((featurep! +fuzzy) #'ivy--regex-fuzzy)
|
||||
;; Ignore order for non-fuzzy searches by default
|
||||
(#'ivy--regex-ignore-order))
|
||||
"Function to use for fuzzy search commands.
|
||||
This uses a search algorithm other than ivy's default.")
|
||||
|
||||
|
||||
;;
|
||||
;;; Packages
|
||||
|
||||
(use-package! ivy
|
||||
:after-call pre-command-hook
|
||||
:hook (doom-first-input . ivy-mode)
|
||||
:init
|
||||
(setq ivy-re-builders-alist
|
||||
`((counsel-rg . +ivy-standard-search)
|
||||
(swiper . +ivy-standard-search)
|
||||
(swiper-isearch . +ivy-standard-search)
|
||||
(t . +ivy-alternative-search)))
|
||||
(let ((standard-search-fn
|
||||
(if (featurep! +prescient)
|
||||
#'+ivy-prescient-non-fuzzy
|
||||
#'ivy--regex-plus))
|
||||
(alt-search-fn
|
||||
(if (featurep! +fuzzy)
|
||||
#'ivy--regex-fuzzy
|
||||
;; Ignore order for non-fuzzy searches by default
|
||||
#'ivy--regex-ignore-order)))
|
||||
(setq ivy-re-builders-alist
|
||||
`((counsel-rg . ,standard-search-fn)
|
||||
(swiper . ,standard-search-fn)
|
||||
(swiper-isearch . ,standard-search-fn)
|
||||
(t . ,alt-search-fn))
|
||||
ivy-more-chars-alist
|
||||
'((counsel-rg . 1)
|
||||
(counsel-search . 2)
|
||||
(t . 3))))
|
||||
|
||||
(define-key!
|
||||
[remap switch-to-buffer] #'+ivy/switch-buffer
|
||||
@@ -90,7 +88,7 @@ This uses a search algorithm other than ivy's default.")
|
||||
(setq +ivy--origin nil)))
|
||||
|
||||
(after! yasnippet
|
||||
(add-hook 'yas-prompt-functions #'+ivy-yas-prompt))
|
||||
(add-hook 'yas-prompt-functions #'+ivy-yas-prompt-fn))
|
||||
|
||||
(defadvice! +ivy--inhibit-completion-in-region-a (orig-fn &rest args)
|
||||
"`ivy-completion-in-region' struggles with completing certain
|
||||
@@ -99,19 +97,11 @@ evil-ex-specific constructs, so we disable it solely in evil-ex."
|
||||
(let ((completion-in-region-function #'completion--in-region))
|
||||
(apply orig-fn args)))
|
||||
|
||||
(define-key ivy-minibuffer-map (kbd "C-c C-e") #'+ivy/woccur)
|
||||
|
||||
(ivy-mode +1)
|
||||
|
||||
(use-package! ivy-hydra
|
||||
:commands (ivy-dispatching-done ivy--matcher-desc ivy-hydra/body)
|
||||
:init
|
||||
(define-key! ivy-minibuffer-map
|
||||
"C-o" #'ivy-dispatching-done
|
||||
"M-o" #'hydra-ivy/body)
|
||||
:config
|
||||
;; ivy-hydra rebinds this, so we have to do so again
|
||||
(define-key ivy-minibuffer-map (kbd "M-o") #'hydra-ivy/body)))
|
||||
(define-key! ivy-minibuffer-map
|
||||
[remap doom/delete-backward-word] #'ivy-backward-kill-word
|
||||
"C-c C-e" #'+ivy/woccur
|
||||
"C-o" #'ivy-dispatching-done
|
||||
"M-o" #'hydra-ivy/body))
|
||||
|
||||
|
||||
(use-package! ivy-rich
|
||||
@@ -122,15 +112,27 @@ evil-ex-specific constructs, so we disable it solely in evil-ex."
|
||||
(when (featurep! +icons)
|
||||
(cl-pushnew '(+ivy-rich-buffer-icon)
|
||||
(cadr (plist-get ivy-rich-display-transformers-list
|
||||
'ivy-switch-buffer))))
|
||||
'ivy-switch-buffer))
|
||||
:test #'equal))
|
||||
|
||||
;; Include variable value in `counsel-describe-variable'
|
||||
;; Enahnce the appearance of a couple counsel commands
|
||||
(plist-put! ivy-rich-display-transformers-list
|
||||
'counsel-describe-variable
|
||||
'(:columns
|
||||
((counsel-describe-variable-transformer (:width 40)) ; the original transformer
|
||||
(+ivy-rich-describe-variable-transformer (:width 50))
|
||||
(ivy-rich-counsel-variable-docstring (:face font-lock-doc-face)))))
|
||||
(+ivy-rich-describe-variable-transformer (:width 50)) ; display variable value
|
||||
(ivy-rich-counsel-variable-docstring (:face font-lock-doc-face))))
|
||||
'counsel-M-x
|
||||
'(:columns
|
||||
((counsel-M-x-transformer (:width 60))
|
||||
(ivy-rich-counsel-function-docstring (:face font-lock-doc-face))))
|
||||
;; Apply switch buffer transformers to `counsel-projectile-switch-to-buffer' as well
|
||||
'counsel-projectile-switch-to-buffer
|
||||
(plist-get ivy-rich-display-transformers-list 'ivy-switch-buffer)
|
||||
'counsel-bookmark
|
||||
'(:columns
|
||||
((ivy-rich-candidate (:width 0.5))
|
||||
(ivy-rich-bookmark-filename (:width 60)))))
|
||||
|
||||
;; Remove built-in coloring of buffer list; we do our own
|
||||
(setq ivy-switch-buffer-faces-alist nil)
|
||||
@@ -138,15 +140,9 @@ evil-ex-specific constructs, so we disable it solely in evil-ex."
|
||||
|
||||
;; Highlight buffers differently based on whether they're in the same project
|
||||
;; as the current project or not.
|
||||
(let* ((plist (plist-get ivy-rich-display-transformers-list 'ivy-switch-buffer))
|
||||
(switch-buffer-alist (assq 'ivy-rich-candidate (plist-get plist :columns))))
|
||||
(when switch-buffer-alist
|
||||
(setcar switch-buffer-alist '+ivy-rich-buffer-name)))
|
||||
|
||||
;; Apply switch buffer transformers to `counsel-projectile-switch-to-buffer' as well
|
||||
(plist-put! ivy-rich-display-transformers-list
|
||||
'counsel-projectile-switch-to-buffer
|
||||
(plist-get ivy-rich-display-transformers-list 'ivy-switch-buffer))
|
||||
(when-let* ((plist (plist-get ivy-rich-display-transformers-list 'ivy-switch-buffer))
|
||||
(switch-buffer-alist (assq 'ivy-rich-candidate (plist-get plist :columns))))
|
||||
(setcar switch-buffer-alist '+ivy-rich-buffer-name))
|
||||
|
||||
(ivy-rich-mode +1))
|
||||
|
||||
@@ -161,9 +157,10 @@ evil-ex-specific constructs, so we disable it solely in evil-ex."
|
||||
|
||||
(all-the-icons-ivy-setup)
|
||||
(after! counsel-projectile
|
||||
(let ((all-the-icons-ivy-file-commands '(counsel-projectile
|
||||
counsel-projectile-find-file
|
||||
counsel-projectile-find-dir)))
|
||||
(let ((all-the-icons-ivy-file-commands
|
||||
'(counsel-projectile
|
||||
counsel-projectile-find-file
|
||||
counsel-projectile-find-dir)))
|
||||
(all-the-icons-ivy-setup))))
|
||||
|
||||
|
||||
@@ -173,62 +170,69 @@ evil-ex-specific constructs, so we disable it solely in evil-ex."
|
||||
(define-key!
|
||||
[remap apropos] #'counsel-apropos
|
||||
[remap bookmark-jump] #'counsel-bookmark
|
||||
[remap compile] #'+ivy/compile
|
||||
[remap describe-bindings] #'counsel-descbinds
|
||||
[remap describe-face] #'counsel-faces
|
||||
[remap describe-function] #'counsel-describe-function
|
||||
[remap describe-variable] #'counsel-describe-variable
|
||||
[remap describe-bindings] #'counsel-descbinds
|
||||
[remap set-variable] #'counsel-set-variable
|
||||
[remap evil-ex-registers] #'counsel-evil-registers
|
||||
[remap evil-show-marks] #'counsel-mark-ring
|
||||
[remap execute-extended-command] #'counsel-M-x
|
||||
[remap find-file] #'counsel-find-file
|
||||
[remap find-library] #'counsel-find-library
|
||||
[remap info-lookup-symbol] #'counsel-info-lookup-symbol
|
||||
[remap imenu] #'counsel-imenu
|
||||
[remap recentf-open-files] #'counsel-recentf
|
||||
[remap swiper] #'counsel-grep-or-swiper
|
||||
[remap evil-ex-registers] #'counsel-evil-registers
|
||||
[remap evil-show-marks] #'counsel-mark-ring
|
||||
[remap yank-pop] #'counsel-yank-pop
|
||||
[remap info-lookup-symbol] #'counsel-info-lookup-symbol
|
||||
[remap load-theme] #'counsel-load-theme
|
||||
[remap locate] #'counsel-locate
|
||||
[remap org-goto] #'counsel-org-goto
|
||||
[remap org-set-tags-command] #'counsel-org-tag
|
||||
[remap projectile-compile-project] #'+ivy/project-compile
|
||||
[remap recentf-open-files] #'counsel-recentf
|
||||
[remap set-variable] #'counsel-set-variable
|
||||
[remap swiper] #'counsel-grep-or-swiper
|
||||
[remap unicode-chars-list-chars] #'counsel-unicode-char
|
||||
[remap compile] #'+ivy/compile
|
||||
[remap projectile-compile-project] #'+ivy/project-compile)
|
||||
[remap yank-pop] #'counsel-yank-pop)
|
||||
:config
|
||||
(set-popup-rule! "^\\*ivy-occur" :size 0.35 :ttl 0 :quit nil)
|
||||
|
||||
;; HACK Fix an issue where `counsel-projectile-find-file-action' would try to
|
||||
;; open a candidate in an occur buffer relative to the wrong buffer,
|
||||
;; causing it to fail to find the file we want.
|
||||
(defadvice! +ivy--run-from-ivy-directory-a (orig-fn &rest args)
|
||||
:around #'counsel-projectile-find-file-action
|
||||
(let ((default-directory (ivy-state-directory ivy-last)))
|
||||
(apply orig-fn args)))
|
||||
|
||||
;; Don't use ^ as initial input. Set this here because `counsel' defines more
|
||||
;; of its own, on top of the defaults.
|
||||
(setq ivy-initial-inputs-alist nil)
|
||||
|
||||
;; REVIEW Move this somewhere else and perhaps generalize this so both
|
||||
;; ivy/helm users can enjoy it.
|
||||
(defadvice! +ivy--counsel-file-jump-use-fd-rg-a (args)
|
||||
"Change `counsel-file-jump' to use fd or ripgrep, if they are available."
|
||||
:override #'counsel--find-return-list
|
||||
(cl-destructuring-bind (find-program . args)
|
||||
(cond ((executable-find "fd")
|
||||
(cons "fd" (list "-t" "f" "-E" ".git")))
|
||||
((executable-find "rg")
|
||||
(cons "rg" (list "--files" "--hidden" "--no-messages")))
|
||||
((cons find-program args)))
|
||||
(unless (listp args)
|
||||
(user-error "`counsel-file-jump-args' is a list now, please customize accordingly."))
|
||||
(counsel--call
|
||||
(cons find-program args)
|
||||
(lambda ()
|
||||
(goto-char (point-min))
|
||||
(let ((offset (if (member find-program '("fd" "rg")) 0 2))
|
||||
files)
|
||||
(while (< (point) (point-max))
|
||||
(push (buffer-substring
|
||||
(+ offset (line-beginning-position)) (line-end-position)) files)
|
||||
(forward-line 1))
|
||||
(nreverse files))))))
|
||||
;; REVIEW Counsel allows `counsel-rg-base-command' to be a string or list.
|
||||
;; This backwards compatibility complicates things for Doom. Simpler to
|
||||
;; just force it to always be a list.
|
||||
(when (stringp counsel-rg-base-command)
|
||||
(setq counsel-rg-base-command (split-string counsel-rg-base-command)))
|
||||
|
||||
;; REVIEW Fix #3215: prevents mingw on Windows throwing an error trying to
|
||||
;; expand / to an absolute path. Remove this when it is fixed upstream
|
||||
;; in counsel.
|
||||
(when (and (memq system-type '(windows-nt ms-dos))
|
||||
(listp counsel-rg-base-command)
|
||||
(member "--path-separator" counsel-rg-base-command))
|
||||
(setf (cadr (member "--path-separator" counsel-rg-base-command))
|
||||
"//"))
|
||||
|
||||
;; Integrate with `helpful'
|
||||
(setq counsel-describe-function-function #'helpful-callable
|
||||
counsel-describe-variable-function #'helpful-variable)
|
||||
|
||||
;; Record in jumplist when opening files via counsel-{ag,rg,pt,git-grep}
|
||||
(add-hook 'counsel-grep-post-action-hook #'better-jumper-set-jump)
|
||||
(add-hook 'counsel-grep-post-action-hook #'recenter)
|
||||
(ivy-add-actions
|
||||
'counsel-rg ; also applies to `counsel-rg'
|
||||
'(("O" +ivy-git-grep-other-window-action "open in other window")))
|
||||
|
||||
;; Make `counsel-compile' projectile-aware (if you prefer it over
|
||||
;; `+ivy/compile' and `+ivy/project-compile')
|
||||
(add-to-list 'counsel-compile-root-functions #'projectile-project-root)
|
||||
@@ -236,33 +240,69 @@ evil-ex-specific constructs, so we disable it solely in evil-ex."
|
||||
;; Persist `counsel-compile' history
|
||||
(add-to-list 'savehist-additional-variables 'counsel-compile-history))
|
||||
|
||||
;; Use spotlight on mac for `counsel-locate' by default, since it doesn't need
|
||||
;; any additional setup.
|
||||
;; `counsel-imenu' -- no sorting for imenu. Sort it by appearance in page.
|
||||
(add-to-list 'ivy-sort-functions-alist '(counsel-imenu))
|
||||
|
||||
;; `counsel-locate'
|
||||
(when IS-MAC
|
||||
;; Use spotlight on mac by default since it doesn't need any additional setup
|
||||
(setq counsel-locate-cmd #'counsel-locate-cmd-mdfind))
|
||||
|
||||
;; `swiper'
|
||||
;; Don't mess with font-locking on the dashboard; it causes breakages
|
||||
(add-to-list 'swiper-font-lock-exclude #'+doom-dashboard-mode)
|
||||
|
||||
;; Record in jumplist when opening files via counsel-{ag,rg,pt,git-grep}
|
||||
(add-hook 'counsel-grep-post-action-hook #'better-jumper-set-jump)
|
||||
|
||||
;; Configure `counsel-find-file'
|
||||
;; `counsel-find-file'
|
||||
(setq counsel-find-file-ignore-regexp "\\(?:^[#.]\\)\\|\\(?:[#~]$\\)\\|\\(?:^Icon?\\)")
|
||||
(ivy-add-actions
|
||||
'counsel-find-file
|
||||
'(("p" (lambda (path) (with-ivy-window (insert (file-relative-name path default-directory))))
|
||||
"insert relative path")
|
||||
("P" (lambda (path) (with-ivy-window (insert path)))
|
||||
"insert absolute path")
|
||||
("l" (lambda (path) (with-ivy-window (insert (format "[[./%s]]" (file-relative-name path default-directory)))))
|
||||
"insert relative org-link")
|
||||
("L" (lambda (path) (with-ivy-window (insert (format "[[%s]]" path))))
|
||||
"Insert absolute org-link")))
|
||||
(dolist (fn '(counsel-rg counsel-find-file))
|
||||
(ivy-add-actions
|
||||
fn '(("p" (lambda (path) (with-ivy-window (insert (file-relative-name path default-directory))))
|
||||
"insert relative path")
|
||||
("P" (lambda (path) (with-ivy-window (insert path)))
|
||||
"insert absolute path")
|
||||
("l" (lambda (path) (with-ivy-window (insert (format "[[./%s]]" (file-relative-name path default-directory)))))
|
||||
"insert relative org-link")
|
||||
("L" (lambda (path) (with-ivy-window (insert (format "[[%s]]" path))))
|
||||
"Insert absolute org-link"))))
|
||||
|
||||
(ivy-add-actions
|
||||
'counsel-ag ; also applies to `counsel-rg'
|
||||
'(("O" +ivy-git-grep-other-window-action "open in other window"))))
|
||||
(ivy-add-actions 'counsel-file-jump (plist-get ivy--actions-list 'counsel-find-file))
|
||||
|
||||
;; `counsel-search': use normal page for displaying results, so that we see
|
||||
;; custom ddg themes (if one is set).
|
||||
(setf (nth 1 (alist-get 'ddg counsel-search-engines-alist))
|
||||
"https://duckduckgo.com/?q=")
|
||||
|
||||
;; REVIEW Move this somewhere else and perhaps generalize this so both
|
||||
;; ivy/helm users can enjoy it.
|
||||
(defadvice! +ivy--counsel-file-jump-use-fd-rg-a (args)
|
||||
"Change `counsel-file-jump' to use fd or ripgrep, if they are available."
|
||||
:override #'counsel--find-return-list
|
||||
(cl-destructuring-bind (find-program . args)
|
||||
(cond ((executable-find doom-projectile-fd-binary)
|
||||
(append (list doom-projectile-fd-binary
|
||||
"--color=never" "-E" ".git"
|
||||
"--type" "file" "--type" "symlink" "--follow")
|
||||
(if IS-WINDOWS '("--path-separator=/"))))
|
||||
((executable-find "rg")
|
||||
(append (list "rg" "--files" "--follow" "--color=never" "--hidden" "--no-messages")
|
||||
(cl-loop for dir in projectile-globally-ignored-directories
|
||||
collect "--glob"
|
||||
collect (concat "!" dir))
|
||||
(if IS-WINDOWS (list "--path-separator" "/"))))
|
||||
((cons find-program args)))
|
||||
(unless (listp args)
|
||||
(user-error "`counsel-file-jump-args' is a list now, please customize accordingly."))
|
||||
(counsel--call
|
||||
(cons find-program args)
|
||||
(lambda ()
|
||||
(goto-char (point-min))
|
||||
(let ((offset (if (member find-program (list "rg" doom-projectile-fd-binary)) 0 2))
|
||||
files)
|
||||
(while (< (point) (point-max))
|
||||
(push (buffer-substring (+ offset (line-beginning-position)) (line-end-position))
|
||||
files)
|
||||
(forward-line 1))
|
||||
(nreverse files)))))))
|
||||
|
||||
|
||||
(use-package! counsel-projectile
|
||||
@@ -284,7 +324,10 @@ evil-ex-specific constructs, so we disable it solely in evil-ex."
|
||||
#'+ivy/projectile-find-file)
|
||||
|
||||
;; no highlighting visited files; slows down the filtering
|
||||
(ivy-set-display-transformer #'counsel-projectile-find-file nil))
|
||||
(ivy-set-display-transformer #'counsel-projectile-find-file nil)
|
||||
|
||||
(when (featurep! +prescient)
|
||||
(setq counsel-projectile-sort-files t)))
|
||||
|
||||
|
||||
(use-package! wgrep
|
||||
@@ -311,7 +354,9 @@ evil-ex-specific constructs, so we disable it solely in evil-ex."
|
||||
;; posframe.
|
||||
(dolist (fn '(swiper counsel-rg counsel-grep counsel-git-grep))
|
||||
(setf (alist-get fn ivy-posframe-display-functions-alist)
|
||||
#'ivy-display-function-fallback)))
|
||||
#'ivy-display-function-fallback))
|
||||
|
||||
(add-hook 'doom-reload-hook #'posframe-delete-all))
|
||||
|
||||
|
||||
(use-package! flx
|
||||
@@ -322,24 +367,26 @@ evil-ex-specific constructs, so we disable it solely in evil-ex."
|
||||
|
||||
|
||||
(use-package! ivy-prescient
|
||||
:hook (ivy-mode . ivy-prescient-mode)
|
||||
:when (featurep! +prescient)
|
||||
:hook (ivy-mode . ivy-prescient-mode)
|
||||
:hook (ivy-prescient-mode . prescient-persist-mode)
|
||||
:init
|
||||
(setq prescient-filter-method
|
||||
(if (featurep! +fuzzy)
|
||||
'(literal regexp initialism fuzzy)
|
||||
'(literal regexp initialism))
|
||||
ivy-prescient-enable-filtering nil ; we do this ourselves
|
||||
ivy-prescient-retain-classic-highlighting t)
|
||||
|
||||
'(literal regexp initialism)))
|
||||
:config
|
||||
(setq ivy-prescient-sort-commands
|
||||
'(:not swiper swiper-isearch ivy-switch-buffer counsel-grep
|
||||
counsel-git-grep counsel-ag counsel-rg counsel-imenu
|
||||
counsel-yank-pop counsel-recentf counsel-buffer-or-recentf)
|
||||
ivy-prescient-retain-classic-highlighting t)
|
||||
(defun +ivy-prescient-non-fuzzy (str)
|
||||
(let ((prescient-filter-method '(literal regexp)))
|
||||
(ivy-prescient-re-builder str)))
|
||||
|
||||
;; NOTE prescient config duplicated with `company'
|
||||
(setq prescient-save-file (concat doom-cache-dir "prescient-save.el"))
|
||||
(prescient-persist-mode +1))
|
||||
(setq prescient-save-file (concat doom-cache-dir "prescient-save.el")))
|
||||
|
||||
|
||||
;;;###package swiper
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
;; -*- no-byte-compile: t; -*-
|
||||
;;; completion/ivy/packages.el
|
||||
|
||||
(package! amx)
|
||||
(package! swiper :pin "544e7de63a4543a74596c5d95efa0bb9da25791e")
|
||||
(package! ivy)
|
||||
(package! counsel)
|
||||
(package! counsel-projectile)
|
||||
(package! swiper)
|
||||
(package! ivy-hydra)
|
||||
(package! ivy-rich)
|
||||
(package! wgrep)
|
||||
(package! counsel)
|
||||
|
||||
(package! amx :pin "7fb7b874291e0cdeb1f0acb18564a686ec86788d")
|
||||
(package! counsel-projectile :pin "77392cbbc42e98fc137b43f1db1b111ba6e2dd75")
|
||||
(package! ivy-rich :pin "10970130b41c6ef9570893cdab8dfbe720e2b1a9")
|
||||
(package! wgrep :pin "f0ef9bfa44db503cdb2f83fcfbd2fa4e2382ef1f")
|
||||
|
||||
(if (featurep! +prescient)
|
||||
(package! ivy-prescient)
|
||||
(package! ivy-prescient :pin "3ab7605d997fb8337bf5ded2ad960b98ac0e1fd7")
|
||||
(when (featurep! +fuzzy)
|
||||
(package! flx)))
|
||||
(package! flx :pin "17f5c9cb2af18aa6f52910ff4a5a63591261ced5")))
|
||||
|
||||
(when (featurep! +childframe)
|
||||
(package! ivy-posframe))
|
||||
(package! ivy-posframe :pin "44749562a9e68bd43ccaa225b31311476fab1251"))
|
||||
|
||||
(when (featurep! +icons)
|
||||
(package! all-the-icons-ivy))
|
||||
(package! all-the-icons-ivy :pin "a70cbfa1effe36efc946a823a580cec686d5e88d"))
|
||||
|
||||
@@ -25,221 +25,390 @@
|
||||
(:prefix ("l" . "<localleader>")) ; bound locally
|
||||
(:prefix ("!" . "checkers")) ; bound by flycheck
|
||||
|
||||
;;; <leader> c --- code
|
||||
(:prefix-map ("c" . "code")
|
||||
:desc "Compile" "c" #'compile
|
||||
:desc "Recompile" "C" #'recompile
|
||||
:desc "Jump to definition" "d" #'+lookup/definition
|
||||
:desc "Jump to references" "D" #'+lookup/references
|
||||
:desc "Evaluate buffer/region" "e" #'+eval/buffer-or-region
|
||||
:desc "Evaluate & replace region" "E" #'+eval/region-and-replace
|
||||
:desc "Format buffer/region" "f" #'+format/region-or-buffer
|
||||
:desc "Jump to documentation" "k" #'+lookup/documentation
|
||||
:desc "Send to repl" "s" #'+eval/send-region-to-repl
|
||||
:desc "Delete trailing whitespace" "w" #'delete-trailing-whitespace
|
||||
:desc "Delete trailing newlines" "W" #'doom/delete-trailing-newlines
|
||||
:desc "List errors" "x" #'flymake-show-diagnostics-buffer
|
||||
(:when (featurep! :checkers syntax)
|
||||
:desc "List errors" "x" #'flycheck-list-errors)
|
||||
(:when (and (featurep! :tools lsp) (not (featurep! :tools lsp +eglot)))
|
||||
:desc "LSP Code actions" "a" #'lsp-execute-code-action
|
||||
:desc "LSP Organize imports" "i" #'lsp-organize-imports
|
||||
:desc "LSP Rename" "r" #'lsp-rename
|
||||
(:after lsp-mode
|
||||
:desc "LSP" "l" lsp-command-map)
|
||||
(:when (featurep! :completion ivy)
|
||||
:desc "Jump to symbol in current workspace" "j" #'lsp-ivy-workspace-symbol
|
||||
:desc "Jump to symbol in any workspace" "J" #'lsp-ivy-global-workspace-symbol)
|
||||
(:when (featurep! :completion helm)
|
||||
:desc "Jump to symbol in current workspace" "j" #'helm-lsp-workspace-symbol
|
||||
:desc "Jump to symbol in any workspace" "J" #'helm-lsp-global-workspace-symbol))
|
||||
(:when (featurep! :tools lsp +eglot)
|
||||
:desc "LSP Execute code action" "a" #'eglot-code-actions
|
||||
:desc "LSP Format buffer/region" "F" #'eglot-format
|
||||
:desc "LSP Rename" "r" #'eglot-rename
|
||||
:desc "LSP Find declaration" "j" #'eglot-find-declaration
|
||||
:desc "LSP Find implementation" "J" #'eglot-find-implementation))
|
||||
|
||||
;;; <leader> f --- file
|
||||
(:prefix-map ("f" . "file")
|
||||
:desc "Open project editorconfig" "." #'editorconfig-find-current-editorconfig
|
||||
:desc "Find other file" "a" #'projectile-find-other-file
|
||||
:desc "Browse private config" "c" #'doom/open-private-config
|
||||
:desc "Find file in private config" "C" #'doom/find-file-in-private-config
|
||||
:desc "Find directory" "d" #'dired
|
||||
:desc "Find file in emacs.d" "e" #'+default/find-in-emacsd
|
||||
:desc "Browse emacs.d" "E" #'+default/browse-emacsd
|
||||
:desc "Find file from here" "f" (if (fboundp 'counsel-file-jump) #'counsel-file-jump #'find-file)
|
||||
:desc "Find file in other project" "F" #'doom/browse-in-other-project
|
||||
:desc "Delete this file" "K" #'doom/delete-this-file
|
||||
:desc "Move this file" "m" #'doom/move-this-file
|
||||
:desc "Find file in project" "p" #'projectile-find-file
|
||||
:desc "Find file in other project" "P" #'doom/find-file-in-other-project
|
||||
:desc "Recent files" "r" #'recentf-open-files
|
||||
:desc "Recent project files" "R" #'projectile-recentf
|
||||
:desc "Sudo this file" "s" #'doom/sudo-this-file
|
||||
:desc "Sudo find file" "S" #'doom/sudo-find-file
|
||||
:desc "Yank filename" "y" #'+default/yank-buffer-filename
|
||||
:desc "Open scratch buffer" "x" #'doom/open-scratch-buffer
|
||||
:desc "Open project scratch buffer" "X" #'doom/switch-to-scratch-buffer)
|
||||
(:when (featurep! :tools editorconfig)
|
||||
:desc "Open project editorconfig" "c" #'editorconfig-find-current-editorconfig)
|
||||
:desc "Copy this file" "C" #'doom/copy-this-file
|
||||
:desc "Find directory" "d" #'dired
|
||||
:desc "Delete this file" "D" #'doom/delete-this-file
|
||||
:desc "Find file in emacs.d" "e" #'+default/find-in-emacsd
|
||||
:desc "Browse emacs.d" "E" #'+default/browse-emacsd
|
||||
:desc "Find file" "f" #'find-file
|
||||
:desc "Find file from here" "F" #'+default/find-file-under-here
|
||||
:desc "Locate file" "l" #'locate
|
||||
:desc "Rename/move this file" "m" #'doom/move-this-file
|
||||
:desc "Find file in private config" "p" #'doom/open-private-config
|
||||
:desc "Browse private config" "P" #'doom/open-private-config
|
||||
:desc "Recent files" "r" #'recentf-open-files
|
||||
:desc "Recent project files" "R" #'projectile-recentf
|
||||
:desc "Sudo this file" "u" #'doom/sudo-this-file
|
||||
:desc "Sudo find file" "U" #'doom/sudo-find-file
|
||||
:desc "Yank filename" "y" #'+default/yank-buffer-filename
|
||||
:desc "Open scratch buffer" "x" #'doom/open-scratch-buffer
|
||||
:desc "Switch to scratch buffer" "X" #'doom/switch-to-scratch-buffer)
|
||||
|
||||
;;; <leader> g --- lookup
|
||||
(:when (featurep! :tools lookup)
|
||||
(:prefix-map ("g" . "lookup")
|
||||
"k" #'+lookup/documentation
|
||||
"d" #'+lookup/definition
|
||||
"D" #'+lookup/references
|
||||
"f" #'+lookup/file
|
||||
"o" #'+lookup/online-select
|
||||
"i" #'+lookup/in-docsets
|
||||
"I" #'+lookup/in-all-docsets))
|
||||
;;; <leader> r --- remote
|
||||
(:when (featurep! :tools upload)
|
||||
(:prefix-map ("r" . "remote")
|
||||
:desc "Browse remote" "b" #'ssh-deploy-browse-remote-base-handler
|
||||
:desc "Browse relative" "B" #'ssh-deploy-browse-remote-handler
|
||||
:desc "Download remote" "d" #'ssh-deploy-download-handler
|
||||
:desc "Delete local & remote" "D" #'ssh-deploy-delete-handler
|
||||
:desc "Eshell base terminal" "e" #'ssh-deploy-remote-terminal-eshell-base-handler
|
||||
:desc "Eshell relative terminal" "E" #'ssh-deploy-remote-terminal-eshell-handler
|
||||
:desc "Move/rename local & remote" "m" #'ssh-deploy-rename-handler
|
||||
:desc "Open this file on remote" "o" #'ssh-deploy-open-remote-file-handler
|
||||
:desc "Run deploy script" "s" #'ssh-deploy-run-deploy-script-handler
|
||||
:desc "Upload local" "u" #'ssh-deploy-upload-handler
|
||||
:desc "Upload local (force)" "U" #'ssh-deploy-upload-handler-forced
|
||||
:desc "Diff local & remote" "x" #'ssh-deploy-diff-handler
|
||||
:desc "Browse remote files" "." #'ssh-deploy-browse-remote-handler
|
||||
:desc "Detect remote changes" ">" #'ssh-deploy-remote-changes-handler))
|
||||
|
||||
;;; <leader> s --- search
|
||||
(:prefix-map ("s" . "search")
|
||||
:desc "Search project for symbol" "." #'+default/search-project-for-symbol-at-point
|
||||
:desc "Search buffer" "b" #'swiper
|
||||
:desc "Search current directory" "d" #'+default/search-cwd
|
||||
:desc "Search other directory" "D" #'+default/search-other-cwd
|
||||
:desc "Locate file" "f" #'+lookup/file
|
||||
:desc "Jump to symbol" "i" #'imenu
|
||||
:desc "Jump to visible link" "l" #'link-hint-open-link
|
||||
:desc "Jump to link" "L" #'ffap-menu
|
||||
:desc "Jump to bookmark" "m" #'bookmark-jump
|
||||
:desc "Look up online" "o" #'+lookup/online
|
||||
:desc "Look up online (w/ prompt)" "O" #'+lookup/online-select
|
||||
:desc "Look up in local docsets" "k" #'+lookup/in-docsets
|
||||
:desc "Look up in all docsets" "K" #'+lookup/in-all-docsets
|
||||
:desc "Search project" "p" #'+default/search-project
|
||||
:desc "Search other project" "P" #'+default/search-other-project
|
||||
:desc "Search buffer" "s" #'swiper-isearch
|
||||
:desc "Search buffer for thing at point" "S" #'swiper-isearch-thing-at-point
|
||||
:desc "Dictionary" "t" #'+lookup/dictionary-definition
|
||||
:desc "Thesaurus" "T" #'+lookup/synonyms)
|
||||
|
||||
;;; <leader> i --- insert
|
||||
(:prefix-map ("i" . "insert")
|
||||
:desc "Current file name" "f" #'+default/insert-file-path
|
||||
:desc "Current file path" "F" (cmd!! #'+default/insert-file-path t)
|
||||
:desc "Snippet" "s" #'yas-insert-snippet
|
||||
:desc "Unicode" "u" #'unicode-chars-list-chars
|
||||
:desc "From clipboard" "y" #'+default/yank-pop)
|
||||
|
||||
;;; <leader> n --- notes
|
||||
(:prefix-map ("n" . "notes")
|
||||
:desc "Search notes for symbol" "." #'+default/search-notes-for-symbol-at-point
|
||||
:desc "Org agenda" "a" #'org-agenda
|
||||
(:when (featurep! :tools biblio)
|
||||
:desc "Bibliographic entries" "b"
|
||||
(cond ((featurep! :completion ivy) #'ivy-bibtex)
|
||||
((featurep! :completion helm) #'helm-bibtex)))
|
||||
|
||||
:desc "Toggle org-clock" "c" #'+org/toggle-clock
|
||||
:desc "Cancel org-clock" "C" #'org-clock-cancel
|
||||
:desc "Open deft" "d" #'deft
|
||||
(:when (featurep! :lang org +noter)
|
||||
:desc "Org noter" "e" #'org-noter)
|
||||
|
||||
:desc "Find file in notes" "f" #'+default/find-in-notes
|
||||
:desc "Browse notes" "F" #'+default/browse-notes
|
||||
:desc "Org store link" "l" #'org-store-link
|
||||
:desc "Tags search" "m" #'org-tags-view
|
||||
:desc "Org capture" "n" #'org-capture
|
||||
:desc "Goto capture" "N" #'org-capture-goto-target
|
||||
:desc "Active org-clock" "o" #'org-clock-goto
|
||||
:desc "Todo list" "t" #'org-todo-list
|
||||
:desc "Search notes" "s" #'+default/org-notes-search
|
||||
:desc "Search org agenda headlines" "S" #'+default/org-notes-headlines
|
||||
:desc "View search" "v" #'org-search-view
|
||||
:desc "Org export to clipboard" "y" #'+org/export-to-clipboard
|
||||
:desc "Org export to clipboard as RTF" "Y" #'+org/export-to-clipboard-as-rich-text
|
||||
(:when (featurep! :lang org +journal)
|
||||
(:prefix ("j" . "journal")
|
||||
:desc "New Entry" "j" #'org-journal-new-entry
|
||||
:desc "Search Forever" "s" #'org-journal-search-forever))
|
||||
(:when (featurep! :lang org +roam)
|
||||
(:prefix ("r" . "roam")
|
||||
:desc "Switch to buffer" "b" #'org-roam-switch-to-buffer
|
||||
:desc "Org Roam Capture" "c" #'org-roam-capture
|
||||
:desc "Find file" "f" #'org-roam-find-file
|
||||
:desc "Show graph" "g" #'org-roam-graph
|
||||
:desc "Insert" "i" #'org-roam-insert
|
||||
:desc "Org Roam" "r" #'org-roam
|
||||
(:prefix ("d" . "by date")
|
||||
:desc "Arbitrary date" "d" #'org-roam-dailies-date
|
||||
:desc "Today" "t" #'org-roam-dailies-today
|
||||
:desc "Tomorrow" "m" #'org-roam-dailies-tomorrow
|
||||
:desc "Yesterday" "y" #'org-roam-dailies-yesterday))))
|
||||
|
||||
;;; <leader> o --- open
|
||||
"o" nil ; we need to unbind it first as Org claims this prefix
|
||||
(:prefix-map ("o" . "open")
|
||||
:desc "Browser" "b" #'browse-url-of-file
|
||||
:desc "Debugger" "d" #'+debugger/start
|
||||
:desc "New frame" "f" #'make-frame
|
||||
:desc "REPL" "r" #'+eval/open-repl-other-window
|
||||
:desc "REPL (same window)" "R" #'+eval/open-repl-same-window
|
||||
:desc "Dired" "-" #'dired-jump
|
||||
(:when (featurep! :ui neotree)
|
||||
:desc "Project sidebar" "p" #'+neotree/open
|
||||
:desc "Find file in project sidebar" "P" #'+neotree/find-this-file)
|
||||
(:when (featurep! :ui treemacs)
|
||||
:desc "Project sidebar" "p" #'+treemacs/toggle
|
||||
:desc "Find file in project rsidebar" "P" #'treemacs-find-file)
|
||||
(:when (featurep! :term shell)
|
||||
:desc "Toggle shell popup" "t" #'+shell/toggle
|
||||
:desc "Open shell here" "T" #'+shell/here)
|
||||
(:when (featurep! :term term)
|
||||
:desc "Toggle terminal popup" "t" #'+term/toggle
|
||||
:desc "Open terminal here" "T" #'+term/here)
|
||||
(:when (featurep! :term vterm)
|
||||
:desc "Toggle vterm popup" "t" #'+vterm/toggle
|
||||
:desc "Open vterm here" "T" #'+vterm/here)
|
||||
(:when (featurep! :term eshell)
|
||||
:desc "Toggle eshell popup" "e" #'+eshell/toggle
|
||||
:desc "Open eshell here" "E" #'+eshell/here)
|
||||
(:when (featurep! :tools macos)
|
||||
:desc "Reveal in Finder" "o" #'+macos/reveal-in-finder
|
||||
:desc "Reveal project in Finder" "O" #'+macos/reveal-project-in-finder
|
||||
:desc "Send to Transmit" "u" #'+macos/send-to-transmit
|
||||
:desc "Send project to Transmit" "U" #'+macos/send-project-to-transmit
|
||||
:desc "Send to Launchbar" "l" #'+macos/send-to-launchbar
|
||||
:desc "Send project to Launchbar" "L" #'+macos/send-project-to-launchbar
|
||||
:desc "Open in iTerm" "i" #'+macos/open-in-iterm)
|
||||
(:when (featurep! :tools docker)
|
||||
:desc "Docker" "D" #'docker)
|
||||
(:when (featurep! :email mu4e)
|
||||
:desc "mu4e" "m" #'=mu4e)
|
||||
(:when (featurep! :email notmuch)
|
||||
:desc "notmuch" "m" #'=notmuch)
|
||||
(:when (featurep! :email wanderlust)
|
||||
:desc "wanderlust" "m" #'=wanderlust))
|
||||
|
||||
;;; <leader> o --- org
|
||||
"o" nil ; we need to unbind it first as Org claims this
|
||||
(:prefix-map ("o". "org")
|
||||
:desc "Do what I mean" "o" #'+org/dwim-at-point
|
||||
:desc "Display inline images" "i" #'org-display-inline-images
|
||||
:desc "Search notes for symbol" "." #'+default/search-notes-for-symbol-at-point
|
||||
(:prefix ("a" . "org agenda")
|
||||
:desc "Agenda" "a" #'org-agenda
|
||||
:desc "Todo list" "t" #'org-todo-list
|
||||
:desc "Tags view" "m" #'org-tags-view
|
||||
:desc "View search" "v" #'org-search-view)
|
||||
:desc "Browse notes" "f" #'+default/browse-notes
|
||||
:desc "Search org-directory" "s" #'+default/org-notes-search
|
||||
:desc "Switch org buffers" "b" #'org-switchb
|
||||
:desc "Capture" "c" #'org-capture
|
||||
:desc "Goto capture" "C" #'org-capture-goto-target
|
||||
:desc "Link store" "l" #'org-store-link
|
||||
:desc "Sync org caldav" "S" #'org-caldav-sync)
|
||||
|
||||
;;; <leader> p --- project
|
||||
(:prefix ("p" . "project")
|
||||
:desc "Find file in other project" "F" #'doom/find-file-in-other-project
|
||||
:desc "Search project" "s" #'+default/search-project
|
||||
:desc "List project tasks" "t" #'magit-todos-list
|
||||
:desc "Open project scratch buffer" "x" #'doom/open-project-scratch-buffer
|
||||
:desc "Switch to project scratch buffer" "X" #'doom/switch-to-project-scratch-buffer
|
||||
;; later expanded by projectile
|
||||
(:prefix ("4" . "in other window"))
|
||||
(:prefix ("5" . "in other frame")))
|
||||
:desc "Search project for symbol" "." #'+default/search-project-for-symbol-at-point
|
||||
:desc "Find file in other project" "F" #'doom/find-file-in-other-project
|
||||
:desc "Search project" "s" #'+default/search-project
|
||||
:desc "List project todos" "t" #'magit-todos-list
|
||||
:desc "Open project scratch buffer" "x" #'doom/open-project-scratch-buffer
|
||||
:desc "Switch to project scratch buffer" "X" #'doom/switch-to-project-scratch-buffer
|
||||
(:when (and (featurep! :tools taskrunner)
|
||||
(or (featurep! :completion ivy)
|
||||
(featurep! :completion helm)))
|
||||
:desc "List project tasks" "z" #'+taskrunner/project-tasks)
|
||||
;; later expanded by projectile
|
||||
(:prefix ("4" . "in other window"))
|
||||
(:prefix ("5" . "in other frame")))
|
||||
|
||||
;;; <leader> q --- quit/restart
|
||||
(:prefix-map ("q" . "quit/restart")
|
||||
:desc "Quit Emacs" "q" #'kill-emacs
|
||||
:desc "Save and quit Emacs" "Q" #'save-buffers-kill-terminal
|
||||
(:when (featurep! :ui workspaces)
|
||||
:desc "Quit Emacs & forget session" "X" #'+workspace/kill-session-and-quit)
|
||||
:desc "Restart & restore Emacs" "r" #'doom/restart-and-restore
|
||||
:desc "Restart Emacs" "R" #'doom/restart)
|
||||
:desc "Restart emacs server" "d" #'+default/restart-server
|
||||
:desc "Delete frame" "f" #'delete-frame
|
||||
:desc "Clear current frame" "F" #'doom/kill-all-buffers
|
||||
:desc "Kill Emacs (and daemon)" "K" #'save-buffers-kill-emacs
|
||||
:desc "Quit Emacs" "q" #'kill-emacs
|
||||
:desc "Save and quit Emacs" "Q" #'save-buffers-kill-terminal
|
||||
:desc "Quick save current session" "s" #'doom/quicksave-session
|
||||
:desc "Restore last session" "l" #'doom/quickload-session
|
||||
:desc "Save session to file" "S" #'doom/save-session
|
||||
:desc "Restore session from file" "L" #'doom/load-session
|
||||
:desc "Restart & restore Emacs" "r" #'doom/restart-and-restore
|
||||
:desc "Restart Emacs" "R" #'doom/restart)
|
||||
|
||||
;;; <leader> & --- snippets
|
||||
(:prefix-map ("&" . "snippets")
|
||||
:desc "New snippet" "n" #'yas-new-snippet
|
||||
:desc "Insert snippet" "i" #'yas-insert-snippet
|
||||
:desc "Find global snippet" "/" #'yas-visit-snippet-file
|
||||
:desc "Reload snippets" "r" #'yas-reload-all
|
||||
:desc "Create Temp Template" "c" #'aya-create
|
||||
:desc "Use Temp Template" "e" #'aya-expand)
|
||||
:desc "New snippet" "n" #'yas-new-snippet
|
||||
:desc "Insert snippet" "i" #'yas-insert-snippet
|
||||
:desc "Find global snippet" "/" #'yas-visit-snippet-file
|
||||
:desc "Reload snippets" "r" #'yas-reload-all
|
||||
:desc "Create Temp Template" "c" #'aya-create
|
||||
:desc "Use Temp Template" "e" #'aya-expand)
|
||||
|
||||
(:prefix-map ("t" . "terminal")
|
||||
(:when (featurep! :term term)
|
||||
:desc "Toggle term popup" "t" #'+term/toggle
|
||||
:desc "Open term here" "T" #'+term/here)
|
||||
(:when (featurep! :term vterm)
|
||||
:desc "Toggle vterm popup" "t" #'+vterm/toggle
|
||||
:desc "Open vterm here" "T" #'+vterm/here)
|
||||
(:when (featurep! :term eshell)
|
||||
:desc "Toggle eshell popup" "t" #'+eshell/toggle
|
||||
:desc "Open eshell here" "T" #'+eshell/here))
|
||||
;;; <leader> t --- toggle
|
||||
(:prefix-map ("t" . "toggle")
|
||||
:desc "Big mode" "b" #'doom-big-font-mode
|
||||
:desc "Flymake" "f" #'flymake-mode
|
||||
:desc "Frame fullscreen" "F" #'toggle-frame-fullscreen
|
||||
:desc "Indent style" "I" #'doom/toggle-indent-style
|
||||
:desc "Line numbers" "l" #'doom/toggle-line-numbers
|
||||
:desc "Word-wrap mode" "w" #'+word-wrap-mode
|
||||
(:when (featurep! :checkers syntax)
|
||||
:desc "Flycheck" "f" #'flycheck-mode)
|
||||
(:when (featurep! :ui indent-guides)
|
||||
:desc "Indent guides" "i" #'highlight-indent-guides-mode)
|
||||
(:when (featurep! :ui minimap)
|
||||
:desc "Minimap mode" "m" #'minimap-mode)
|
||||
(:when (featurep! :lang org +present)
|
||||
:desc "org-tree-slide mode" "p" #'+org-present/start)
|
||||
:desc "Read-only mode" "r" #'read-only-mode
|
||||
(:when (featurep! :checkers spell)
|
||||
:desc "Flyspell" "s" #'flyspell-mode)
|
||||
(:when (featurep! :lang org +pomodoro)
|
||||
:desc "Pomodoro timer" "t" #'org-pomodoro)
|
||||
(:when (featurep! :ui zen)
|
||||
:desc "Zen mode" "z" #'writeroom-mode))
|
||||
|
||||
;;; <leader> v --- versioning
|
||||
(:prefix-map ("v" . "versioning")
|
||||
:desc "Git revert file" "R" #'vc-revert
|
||||
:desc "Kill link to remote" "y" #'+vc/browse-at-remote-kill-file-or-region
|
||||
:desc "Kill link to homepage" "Y" #'+vc/browse-at-remote-kill-homepage
|
||||
(:when (featurep! :ui vc-gutter)
|
||||
:desc "Git revert hunk" "r" #'git-gutter:revert-hunk
|
||||
:desc "Git stage hunk" "s" #'git-gutter:stage-hunk
|
||||
:desc "Git time machine" "t" #'git-timemachine-toggle
|
||||
:desc "Jump to next hunk" "n" #'git-gutter:next-hunk
|
||||
:desc "Jump to previous hunk" "p" #'git-gutter:previous-hunk)
|
||||
(:when (featurep! :tools magit)
|
||||
:desc "Magit dispatch" "/" #'magit-dispatch
|
||||
:desc "Forge dispatch" "'" #'forge-dispatch
|
||||
:desc "Magit status" "g" #'magit-status
|
||||
:desc "Magit file delete" "x" #'magit-file-delete
|
||||
:desc "Magit blame" "B" #'magit-blame-addition
|
||||
:desc "Magit clone" "C" #'magit-clone
|
||||
:desc "Magit fetch" "F" #'magit-fetch
|
||||
:desc "Magit buffer log" "L" #'magit-log
|
||||
:desc "Git stage file" "S" #'magit-stage-file
|
||||
:desc "Git unstage file" "U" #'magit-unstage-file
|
||||
(:prefix ("f" . "find")
|
||||
:desc "Find file" "f" #'magit-find-file
|
||||
:desc "Find gitconfig file" "g" #'magit-find-git-config-file
|
||||
:desc "Find commit" "c" #'magit-show-commit
|
||||
:desc "Find issue" "i" #'forge-visit-issue
|
||||
:desc "Find pull request" "p" #'forge-visit-pullreq)
|
||||
(:prefix ("o" . "open in browser")
|
||||
:desc "Browse file or region" "." #'+vc/browse-at-remote-file-or-region
|
||||
:desc "Browse homepage" "h" #'+vc/browse-at-remote-homepage
|
||||
:desc "Browse remote" "r" #'forge-browse-remote
|
||||
:desc "Browse commit" "c" #'forge-browse-commit
|
||||
:desc "Browse an issue" "i" #'forge-browse-issue
|
||||
:desc "Browse a pull request" "p" #'forge-browse-pullreq
|
||||
:desc "Browse issues" "I" #'forge-browse-issues
|
||||
:desc "Browse pull requests" "P" #'forge-browse-pullreqs)
|
||||
(:prefix ("l" . "list")
|
||||
(:when (featurep! :tools gist)
|
||||
:desc "List gists" "g" #'+gist:list)
|
||||
:desc "List repositories" "r" #'magit-list-repositories
|
||||
:desc "List submodules" "s" #'magit-list-submodules
|
||||
:desc "List issues" "i" #'forge-list-issues
|
||||
:desc "List pull requests" "p" #'forge-list-pullreqs
|
||||
:desc "List notifications" "n" #'forge-list-notifications)
|
||||
(:prefix ("c" . "create")
|
||||
:desc "Initialize repo" "r" #'magit-init
|
||||
:desc "Clone repo" "R" #'magit-clone
|
||||
:desc "Commit" "c" #'magit-commit-create
|
||||
:desc "Fixup" "f" #'magit-commit-fixup
|
||||
:desc "Issue" "i" #'forge-create-issue
|
||||
:desc "Pull request" "p" #'forge-create-pullreq)))
|
||||
:desc "Git revert file" "R" #'vc-revert
|
||||
:desc "Kill link to remote" "y" #'browse-at-remote-kill
|
||||
:desc "Kill link to homepage" "Y" #'+vc/browse-at-remote-kill-homepage
|
||||
(:when (featurep! :ui vc-gutter)
|
||||
:desc "Git revert hunk" "r" #'git-gutter:revert-hunk
|
||||
:desc "Git stage hunk" "s" #'git-gutter:stage-hunk
|
||||
:desc "Git time machine" "t" #'git-timemachine-toggle
|
||||
:desc "Jump to next hunk" "n" #'git-gutter:next-hunk
|
||||
:desc "Jump to previous hunk" "p" #'git-gutter:previous-hunk)
|
||||
(:when (featurep! :tools magit)
|
||||
:desc "Magit dispatch" "/" #'magit-dispatch
|
||||
:desc "Forge dispatch" "'" #'forge-dispatch
|
||||
:desc "Magit status" "g" #'magit-status
|
||||
:desc "Magit status here" "G" #'magit-status-here
|
||||
:desc "Magit file delete" "x" #'magit-file-delete
|
||||
:desc "Magit blame" "B" #'magit-blame-addition
|
||||
:desc "Magit clone" "C" #'magit-clone
|
||||
:desc "Magit fetch" "F" #'magit-fetch
|
||||
:desc "Magit buffer log" "L" #'magit-log
|
||||
:desc "Git stage file" "S" #'magit-stage-file
|
||||
:desc "Git unstage file" "U" #'magit-unstage-file
|
||||
(:prefix ("f" . "find")
|
||||
:desc "Find file" "f" #'magit-find-file
|
||||
:desc "Find gitconfig file" "g" #'magit-find-git-config-file
|
||||
:desc "Find commit" "c" #'magit-show-commit
|
||||
:desc "Find issue" "i" #'forge-visit-issue
|
||||
:desc "Find pull request" "p" #'forge-visit-pullreq)
|
||||
(:prefix ("o" . "open in browser")
|
||||
:desc "Browse file or region" "." #'browse-at-remote
|
||||
:desc "Browse homepage" "h" #'+vc/browse-at-remote-homepage
|
||||
:desc "Browse remote" "r" #'forge-browse-remote
|
||||
:desc "Browse commit" "c" #'forge-browse-commit
|
||||
:desc "Browse an issue" "i" #'forge-browse-issue
|
||||
:desc "Browse a pull request" "p" #'forge-browse-pullreq
|
||||
:desc "Browse issues" "I" #'forge-browse-issues
|
||||
:desc "Browse pull requests" "P" #'forge-browse-pullreqs)
|
||||
(:prefix ("l" . "list")
|
||||
(:when (featurep! :tools gist)
|
||||
:desc "List gists" "g" #'gist-list)
|
||||
:desc "List repositories" "r" #'magit-list-repositories
|
||||
:desc "List submodules" "s" #'magit-list-submodules
|
||||
:desc "List issues" "i" #'forge-list-issues
|
||||
:desc "List pull requests" "p" #'forge-list-pullreqs
|
||||
:desc "List notifications" "n" #'forge-list-notifications)
|
||||
(:prefix ("c" . "create")
|
||||
:desc "Initialize repo" "r" #'magit-init
|
||||
:desc "Clone repo" "R" #'magit-clone
|
||||
:desc "Commit" "c" #'magit-commit-create
|
||||
:desc "Fixup" "f" #'magit-commit-fixup
|
||||
:desc "Issue" "i" #'forge-create-issue
|
||||
:desc "Pull request" "p" #'forge-create-pullreq)))
|
||||
|
||||
;;; <leader> w --- workspaces/windows
|
||||
(:prefix-map ("w" . "workspaces/windows")
|
||||
:desc "Autosave session" "a" #'doom/quicksave-session
|
||||
:desc "Display workspaces" "d" #'+workspace/display
|
||||
:desc "Rename workspace" "r" #'+workspace/rename
|
||||
:desc "Create workspace" "c" #'+workspace/new
|
||||
:desc "Delete workspace" "k" #'+workspace/delete
|
||||
:desc "Save session" "s" #'doom/save-session
|
||||
:desc "Save workspace" "S" #'+workspace/save
|
||||
:desc "Load session" "l" #'doom/load-session
|
||||
:desc "Load last autosaved session" "L" #'doom/quickload-session
|
||||
:desc "Switch to other workspace" "o" #'+workspace/other
|
||||
:desc "Undo window config" "u" #'winner-undo
|
||||
:desc "Redo window config" "U" #'winner-redo
|
||||
:desc "Switch to left workspace" "p" #'+workspace/switch-left
|
||||
:desc "Switch to right workspace" "n" #'+workspace/switch-right
|
||||
:desc "Switch to" "w" #'+workspace/switch-to
|
||||
:desc "Switch to workspace 1" "1" #'+workspace/switch-to-0
|
||||
:desc "Switch to workspace 2" "2" #'+workspace/switch-to-1
|
||||
:desc "Switch to workspace 3" "3" #'+workspace/switch-to-2
|
||||
:desc "Switch to workspace 4" "4" #'+workspace/switch-to-3
|
||||
:desc "Switch to workspace 5" "5" #'+workspace/switch-to-4
|
||||
:desc "Switch to workspace 6" "6" #'+workspace/switch-to-5
|
||||
:desc "Switch to workspace 7" "7" #'+workspace/switch-to-6
|
||||
:desc "Switch to workspace 8" "8" #'+workspace/switch-to-7
|
||||
:desc "Switch to workspace 9" "9" #'+workspace/switch-to-8
|
||||
:desc "Switch to last workspace" "0" #'+workspace/switch-to-final)
|
||||
:desc "Autosave session" "a" #'doom/quicksave-session
|
||||
:desc "Display workspaces" "d" #'+workspace/display
|
||||
:desc "Rename workspace" "r" #'+workspace/rename
|
||||
:desc "Create workspace" "c" #'+workspace/new
|
||||
:desc "Delete workspace" "k" #'+workspace/delete
|
||||
:desc "Save session" "s" #'doom/save-session
|
||||
:desc "Save workspace" "S" #'+workspace/save
|
||||
:desc "Load session" "l" #'doom/load-session
|
||||
:desc "Load last autosaved session" "L" #'doom/quickload-session
|
||||
:desc "Switch to other workspace" "o" #'+workspace/other
|
||||
:desc "Undo window config" "u" #'winner-undo
|
||||
:desc "Redo window config" "U" #'winner-redo
|
||||
:desc "Switch to left workspace" "p" #'+workspace/switch-left
|
||||
:desc "Switch to right workspace" "n" #'+workspace/switch-right
|
||||
:desc "Switch to" "w" #'+workspace/switch-to
|
||||
:desc "Switch to workspace 1" "1" #'+workspace/switch-to-0
|
||||
:desc "Switch to workspace 2" "2" #'+workspace/switch-to-1
|
||||
:desc "Switch to workspace 3" "3" #'+workspace/switch-to-2
|
||||
:desc "Switch to workspace 4" "4" #'+workspace/switch-to-3
|
||||
:desc "Switch to workspace 5" "5" #'+workspace/switch-to-4
|
||||
:desc "Switch to workspace 6" "6" #'+workspace/switch-to-5
|
||||
:desc "Switch to workspace 7" "7" #'+workspace/switch-to-6
|
||||
:desc "Switch to workspace 8" "8" #'+workspace/switch-to-7
|
||||
:desc "Switch to workspace 9" "9" #'+workspace/switch-to-8
|
||||
:desc "Switch to last workspace" "0" #'+workspace/switch-to-final)
|
||||
|
||||
;;; <leader> m --- multiple cursors
|
||||
(:when (featurep! :editor multiple-cursors)
|
||||
(:prefix-map ("m" . "multiple cursors")
|
||||
:desc "Edit lines" "l" #'mc/edit-lines
|
||||
:desc "Mark next" "n" #'mc/mark-next-like-this
|
||||
:desc "Unmark next" "N" #'mc/unmark-next-like-this
|
||||
:desc "Mark previous" "p" #'mc/mark-previous-like-this
|
||||
:desc "Unmark previous" "P" #'mc/unmark-previous-like-this
|
||||
:desc "Mark all" "t" #'mc/mark-all-like-this
|
||||
:desc "Mark all DWIM" "m" #'mc/mark-all-like-this-dwim
|
||||
:desc "Edit line endings" "e" #'mc/edit-ends-of-lines
|
||||
:desc "Edit line starts" "a" #'mc/edit-beginnings-of-lines
|
||||
:desc "Mark tag" "s" #'mc/mark-sgml-tag-pair
|
||||
:desc "Mark in defun" "d" #'mc/mark-all-like-this-in-defun
|
||||
:desc "Add cursor w/mouse" "<mouse-1>" #'mc/add-cursor-on-click))
|
||||
(:prefix-map ("m" . "multiple-cursors")
|
||||
:desc "Edit lines" "l" #'mc/edit-lines
|
||||
:desc "Mark next" "n" #'mc/mark-next-like-this
|
||||
:desc "Unmark next" "N" #'mc/unmark-next-like-this
|
||||
:desc "Mark previous" "p" #'mc/mark-previous-like-this
|
||||
:desc "Unmark previous" "P" #'mc/unmark-previous-like-this
|
||||
:desc "Mark all" "t" #'mc/mark-all-like-this
|
||||
:desc "Mark all DWIM" "m" #'mc/mark-all-like-this-dwim
|
||||
:desc "Edit line endings" "e" #'mc/edit-ends-of-lines
|
||||
:desc "Edit line starts" "a" #'mc/edit-beginnings-of-lines
|
||||
:desc "Mark tag" "s" #'mc/mark-sgml-tag-pair
|
||||
:desc "Mark in defun" "d" #'mc/mark-all-like-this-in-defun
|
||||
:desc "Add cursor w/mouse" "<mouse-1>" #'mc/add-cursor-on-click))
|
||||
|
||||
;; APPs
|
||||
;;; <leader> M --- mu4e
|
||||
(:when (featurep! :email mu4e)
|
||||
(:prefix-map ("M" . "mu4e")
|
||||
:desc "Open email app" "M" #'=mu4e
|
||||
:desc "Compose email" "c" #'+mu4e/compose))
|
||||
(:prefix-map ("M" . "mu4e")
|
||||
:desc "Open email app" "M" #'=mu4e
|
||||
:desc "Compose email" "c" #'+mu4e/compose))
|
||||
|
||||
;;; <leader> I --- IRC
|
||||
(:when (featurep! :app irc)
|
||||
(:prefix-map ("I" . "irc")
|
||||
:desc "Open irc app" "I" #'=irc
|
||||
:desc "Next unread buffer" "a" #'tracking-next-buffer
|
||||
:desc "Quit irc" "q" #'+irc/quit
|
||||
:desc "Reconnect all" "r" #'circe-reconnect-all
|
||||
:desc "Send message" "s" #'+irc/send-message
|
||||
(:when (featurep! :completion ivy)
|
||||
:desc "Jump to channel" "j" #'irc/ivy-jump-to-channel)))
|
||||
(:prefix-map ("I" . "irc")
|
||||
:desc "Open irc app" "I" #'=irc
|
||||
:desc "Next unread buffer" "a" #'tracking-next-buffer
|
||||
:desc "Quit irc" "q" #'+irc/quit
|
||||
:desc "Reconnect all" "r" #'circe-reconnect-all
|
||||
:desc "Send message" "s" #'+irc/send-message
|
||||
(:when (featurep! :completion ivy)
|
||||
:desc "Jump to channel" "j" #'+irc/ivy-jump-to-channel)))
|
||||
|
||||
;;; <leader> T --- twitter
|
||||
(:when (featurep! :app twitter)
|
||||
(:prefix-map ("T" . "twitter")
|
||||
:desc "Open twitter app" "T" #'=twitter
|
||||
:desc "Quit twitter" "q" #'+twitter/quit
|
||||
:desc "Rerender twits" "r" #'+twitter/rerender-all
|
||||
:desc "Ace link" "l" #'+twitter/ace-link)))
|
||||
(:prefix-map ("T" . "twitter")
|
||||
:desc "Open twitter app" "T" #'=twitter
|
||||
:desc "Quit twitter" "q" #'+twitter/quit
|
||||
:desc "Rerender twits" "r" #'+twitter/rerender-all
|
||||
:desc "Ace link" "l" #'+twitter/ace-link)))
|
||||
|
||||
|
||||
;;
|
||||
@@ -250,7 +419,7 @@
|
||||
;;; Text scaling
|
||||
[C-mouse-4] #'text-scale-increase
|
||||
[C-mouse-5] #'text-scale-decrease
|
||||
[C-down-mouse-2] (λ! (text-scale-set 0))
|
||||
[C-down-mouse-2] (cmd! (text-scale-set 0))
|
||||
"M-+" #'doom/reset-font-size
|
||||
"M-=" #'doom/increase-font-size
|
||||
"M--" #'doom/decrease-font-size
|
||||
@@ -272,12 +441,15 @@
|
||||
"M-SPC" #'objed-activate)
|
||||
|
||||
;;; buffer management
|
||||
"C-x b" #'persp-switch-to-buffer
|
||||
(:when (featurep! :completion ivy)
|
||||
"C-x 4 b" #'+ivy/switch-workspace-buffer-other-window)
|
||||
"C-x C-b" #'ibuffer-list-buffers
|
||||
"C-x B" #'switch-to-buffer
|
||||
"C-x 4 B" #'switch-to-buffer-other-window
|
||||
"C-x b" #'switch-to-buffer
|
||||
"C-x 4 b" #'switch-to-buffer-other-window
|
||||
(:when (featurep! :ui workspaces)
|
||||
"C-x b" #'persp-switch-to-buffer
|
||||
"C-x B" #'switch-to-buffer
|
||||
"C-x 4 B" #'switch-to-buffer-other-window
|
||||
(:when (featurep! :completion ivy)
|
||||
"C-x 4 b" #'+ivy/switch-workspace-buffer-other-window))
|
||||
"C-x C-b" #'ibuffer
|
||||
"C-x K" #'doom/kill-this-buffer-in-all-windows
|
||||
|
||||
;;; company-mode
|
||||
@@ -291,14 +463,14 @@
|
||||
"C-S-h" #'company-show-doc-buffer
|
||||
"C-s" #'company-search-candidates
|
||||
"M-s" #'company-filter-candidates
|
||||
"<C-tab>" #'company-complete-common-or-cycle
|
||||
[C-tab] #'company-complete-common-or-cycle
|
||||
[tab] #'company-complete-common-or-cycle
|
||||
[backtab] #'company-select-previous
|
||||
"C-RET" #'counsel-company
|
||||
:map company-search-map
|
||||
"C-n" #'company-search-repeat-forward
|
||||
"C-p" #'company-search-repeat-backward
|
||||
"C-s" (λ! (company-search-abort) (company-filter-candidates)))
|
||||
"C-s" (cmd! (company-search-abort) (company-filter-candidates)))
|
||||
|
||||
;;; ein notebooks
|
||||
(:after ein:notebook-multilang
|
||||
@@ -319,22 +491,22 @@
|
||||
;;; help and info
|
||||
(:after help-mode
|
||||
:map help-mode-map
|
||||
"o" #'ace-link-help
|
||||
"o" #'link-hint-open-link
|
||||
">" #'help-go-forward
|
||||
"<" #'help-go-back
|
||||
"n" #'forward-button
|
||||
"p" #'backward-button)
|
||||
(:after helpful
|
||||
:map helpful-mode-map
|
||||
"o" #'ace-link-help)
|
||||
"o" #'link-hint-open-link)
|
||||
(:after apropos
|
||||
:map apropos-mode-map
|
||||
"o" #'ace-link-help
|
||||
"o" #'link-hint-open-link
|
||||
"n" #'forward-button
|
||||
"p" #'backward-button)
|
||||
(:after info
|
||||
:map Info-mode-map
|
||||
"o" #'ace-link-info)
|
||||
"o" #'link-hint-open-link)
|
||||
|
||||
;;; ivy & counsel
|
||||
(:when (featurep! :completion ivy)
|
||||
@@ -377,10 +549,6 @@
|
||||
"C-`" #'+popup/toggle
|
||||
"C-~" #'+popup/raise)
|
||||
|
||||
;;; repl
|
||||
"C-c C-z" #'+eval/open-repl-other-window
|
||||
"C-c C-S-z" #'+eval/open-repl-same-window
|
||||
|
||||
;;; smartparens
|
||||
(:after smartparens
|
||||
:map smartparens-mode-map
|
||||
@@ -399,14 +567,4 @@
|
||||
;;; treemacs
|
||||
(:when (featurep! :ui treemacs)
|
||||
"<f9>" #'+treemacs/toggle
|
||||
"<C-f9>" #'+treemacs/find-file)
|
||||
|
||||
;;; yasnippet
|
||||
(:after yasnippet
|
||||
:map yas-keymap ; keymap while editing an inserted snippet
|
||||
"C-e" #'+snippets/goto-end-of-field
|
||||
"C-a" #'+snippets/goto-start-of-field
|
||||
"<S-tab>" #'yas-prev-field
|
||||
"<M-backspace>" #'+snippets/delete-to-start-of-field
|
||||
[backspace] #'+snippets/delete-backward-char
|
||||
[delete] #'+snippets/delete-forward-char-or-field))
|
||||
"<C-f9>" #'treemacs-find-file))
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,39 +1,5 @@
|
||||
;; config/default/autoload/default.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;;###autoload
|
||||
(defun +default/yank-buffer-filename ()
|
||||
"Copy the current buffer's path to the kill ring."
|
||||
(interactive)
|
||||
(if-let* ((filename (or buffer-file-name (bound-and-true-p list-buffers-directory))))
|
||||
(message (kill-new (abbreviate-file-name filename)))
|
||||
(error "Couldn't find filename in current buffer")))
|
||||
|
||||
;;;###autoload
|
||||
(defun +default/browse-project ()
|
||||
(interactive) (doom-project-browse (doom-project-root)))
|
||||
;; NOTE No need for find-in-project, use `projectile-find-file'
|
||||
|
||||
;;;###autoload
|
||||
(defun +default/browse-templates ()
|
||||
(interactive) (doom-project-browse +file-templates-dir))
|
||||
;;;###autoload
|
||||
(defun +default/find-in-templates ()
|
||||
(interactive) (doom-project-find-file +file-templates-dir))
|
||||
|
||||
;;;###autoload
|
||||
(defun +default/browse-emacsd ()
|
||||
(interactive) (doom-project-browse doom-emacs-dir))
|
||||
;;;###autoload
|
||||
(defun +default/find-in-emacsd ()
|
||||
(interactive) (doom-project-find-file doom-emacs-dir))
|
||||
|
||||
;;;###autoload
|
||||
(defun +default/browse-notes ()
|
||||
(interactive) (doom-project-browse org-directory))
|
||||
;;;###autoload
|
||||
(defun +default/find-in-notes ()
|
||||
(interactive) (doom-project-find-file org-directory))
|
||||
|
||||
;;;###autoload
|
||||
(defun +default/compile (arg)
|
||||
"Runs `compile' from the root of the current project.
|
||||
@@ -59,9 +25,6 @@ If ARG (universal argument), runs `compile' from the current directory."
|
||||
#'man
|
||||
#'woman)))
|
||||
|
||||
;;;###autoload
|
||||
(defalias '+default/newline #'newline)
|
||||
|
||||
;;;###autoload
|
||||
(defun +default/new-buffer ()
|
||||
"TODO"
|
||||
@@ -73,275 +36,11 @@ If ARG (universal argument), runs `compile' from the current directory."
|
||||
(with-current-buffer buffer
|
||||
(funcall (default-value 'major-mode))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +default/newline-above ()
|
||||
"Insert an indented new line before the current one."
|
||||
(interactive)
|
||||
(if (featurep 'evil)
|
||||
(call-interactively 'evil-open-above)
|
||||
(beginning-of-line)
|
||||
(save-excursion (newline))
|
||||
(indent-according-to-mode)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +default/newline-below ()
|
||||
"Insert an indented new line after the current one."
|
||||
(interactive)
|
||||
(if (featurep 'evil)
|
||||
(call-interactively 'evil-open-below)
|
||||
(end-of-line)
|
||||
(newline-and-indent)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +default/yank-pop ()
|
||||
"Interactively select what text to insert from the kill ring."
|
||||
(interactive)
|
||||
(call-interactively
|
||||
(cond ((fboundp 'counsel-yank-pop) #'counsel-yank-pop)
|
||||
((fboundp 'helm-show-kill-ring) #'helm-show-kill-ring)
|
||||
((error "No kill-ring search backend available. Enable ivy or helm!")))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +default--newline-indent-and-continue-comments-a ()
|
||||
"A replacement for `newline-and-indent'.
|
||||
|
||||
Continues comments if executed from a commented line, with special support for
|
||||
languages with weak native comment continuation support (like C-family
|
||||
languages)."
|
||||
(interactive)
|
||||
(if (and (sp-point-in-comment)
|
||||
comment-line-break-function)
|
||||
(funcall comment-line-break-function nil)
|
||||
(delete-horizontal-space t)
|
||||
(newline nil t)
|
||||
(indent-according-to-mode)))
|
||||
|
||||
(defun doom--backward-delete-whitespace-to-column ()
|
||||
"Delete back to the previous column of whitespace, or as much whitespace as
|
||||
possible, or just one char if that's not possible."
|
||||
(interactive)
|
||||
(let* ((context (ignore-errors (sp-get-thing)))
|
||||
(op (plist-get context :op))
|
||||
(cl (plist-get context :cl))
|
||||
open-len close-len)
|
||||
(cond ;; When in strings (sp acts weird with quotes; this is the fix)
|
||||
;; Also, skip closing delimiters
|
||||
((and op cl
|
||||
(string= op cl)
|
||||
(and (string= (char-to-string (or (char-before) 0)) op)
|
||||
(setq open-len (length op)))
|
||||
(and (string= (char-to-string (or (char-after) 0)) cl)
|
||||
(setq close-len (length cl))))
|
||||
(delete-char (- open-len))
|
||||
(delete-char close-len))
|
||||
|
||||
;; Delete up to the nearest tab column IF only whitespace between
|
||||
;; point and bol.
|
||||
((and (not indent-tabs-mode)
|
||||
(not (bolp))
|
||||
(not (sp-point-in-string))
|
||||
(save-excursion (>= (- (skip-chars-backward " \t")) tab-width)))
|
||||
(let ((movement (% (current-column) tab-width)))
|
||||
(when (= movement 0)
|
||||
(setq movement tab-width))
|
||||
(delete-char (- movement)))
|
||||
(unless (memq (char-before) (list ?\n ?\ ))
|
||||
(insert " ")))
|
||||
|
||||
;; Otherwise do a regular delete
|
||||
((delete-char -1)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +default--delete-backward-char-a (n &optional killflag)
|
||||
"Same as `delete-backward-char', but preforms these additional checks:
|
||||
|
||||
+ If point is surrounded by (balanced) whitespace and a brace delimiter ({} []
|
||||
()), delete a space on either side of the cursor.
|
||||
+ If point is at BOL and surrounded by braces on adjacent lines, collapse
|
||||
newlines:
|
||||
{
|
||||
|
|
||||
} => {|}
|
||||
+ Otherwise, resort to `doom--backward-delete-whitespace-to-column'.
|
||||
+ Resorts to `delete-char' if n > 1"
|
||||
(interactive "p\nP")
|
||||
(or (integerp n)
|
||||
(signal 'wrong-type-argument (list 'integerp n)))
|
||||
(cond ((and (use-region-p)
|
||||
delete-active-region
|
||||
(= n 1))
|
||||
;; If a region is active, kill or delete it.
|
||||
(if (eq delete-active-region 'kill)
|
||||
(kill-region (region-beginning) (region-end) 'region)
|
||||
(funcall region-extract-function 'delete-only)))
|
||||
;; In Overwrite mode, maybe untabify while deleting
|
||||
((null (or (null overwrite-mode)
|
||||
(<= n 0)
|
||||
(memq (char-before) '(?\t ?\n))
|
||||
(eobp)
|
||||
(eq (char-after) ?\n)))
|
||||
(let ((ocol (current-column)))
|
||||
(delete-char (- n) killflag)
|
||||
(save-excursion
|
||||
(insert-char ?\s (- ocol (current-column)) nil))))
|
||||
;;
|
||||
((and (= n 1) (bound-and-true-p smartparens-mode))
|
||||
(cond ((and (memq (char-before) (list ?\ ?\t))
|
||||
(save-excursion
|
||||
(and (/= (skip-chars-backward " \t" (line-beginning-position)) 0)
|
||||
(bolp))))
|
||||
(doom--backward-delete-whitespace-to-column))
|
||||
((let* ((pair (ignore-errors (sp-get-thing)))
|
||||
(op (plist-get pair :op))
|
||||
(cl (plist-get pair :cl))
|
||||
(beg (plist-get pair :beg))
|
||||
(end (plist-get pair :end)))
|
||||
(cond ((and end beg (= end (+ beg (length op) (length cl))))
|
||||
(sp-backward-delete-char 1))
|
||||
((doom-surrounded-p pair 'inline 'balanced)
|
||||
(delete-char -1 killflag)
|
||||
(delete-char 1)
|
||||
(when (= (point) (+ (length cl) beg))
|
||||
(sp-backward-delete-char 1)
|
||||
(sp-insert-pair op)))
|
||||
((and (bolp) (doom-surrounded-p pair nil 'balanced))
|
||||
(delete-region beg end)
|
||||
(sp-insert-pair op)
|
||||
t)
|
||||
((run-hook-with-args-until-success 'doom-delete-backward-functions))
|
||||
((doom--backward-delete-whitespace-to-column)))))))
|
||||
;; Otherwise, do simple deletion.
|
||||
((delete-char (- n) killflag))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +default/search-cwd (&optional arg)
|
||||
"Conduct a text search in files under the current folder.
|
||||
If prefix ARG is set, prompt for a directory to search from."
|
||||
(interactive "P")
|
||||
(let ((default-directory
|
||||
(if arg
|
||||
(read-directory-name "Search directory: ")
|
||||
default-directory)))
|
||||
(call-interactively
|
||||
(cond ((featurep! :completion ivy) #'+ivy/project-search-from-cwd)
|
||||
((featurep! :completion helm) #'+helm/project-search-from-cwd)
|
||||
(#'rgrep)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +default/search-other-cwd ()
|
||||
"Conduct a text search in another directory."
|
||||
(interactive)
|
||||
(+default/search-cwd 'other))
|
||||
|
||||
;;;###autoload
|
||||
(defun +default/search-project (&optional arg)
|
||||
"Conduct a text search in the current project root.
|
||||
If prefix ARG is set, prompt for a known project to search from."
|
||||
(interactive "P")
|
||||
(let ((default-directory
|
||||
(if arg
|
||||
(if-let (projects (projectile-relevant-known-projects))
|
||||
(completing-read "Search project: " projects
|
||||
nil t nil nil (doom-project-root))
|
||||
(user-error "There are no known projects"))
|
||||
default-directory)))
|
||||
(call-interactively
|
||||
(cond ((featurep! :completion ivy) #'+ivy/project-search)
|
||||
((featurep! :completion helm) #'+helm/project-search)
|
||||
(#'projectile-grep)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +default/search-other-project ()
|
||||
"Conduct a text search in a known project."
|
||||
(interactive)
|
||||
(+default/search-project 'other))
|
||||
|
||||
;;;###autoload
|
||||
(defun +default/search-project-for-symbol-at-point (&optional arg symbol)
|
||||
"Conduct a text search in the current project for symbol at point.
|
||||
If prefix ARG is set, prompt for a known project to search from."
|
||||
(interactive
|
||||
(list current-prefix-arg
|
||||
(or (and (use-region-p)
|
||||
(rxt-quote-pcre
|
||||
(buffer-substring-no-properties (region-beginning)
|
||||
(region-end))))
|
||||
(rxt-quote-pcre (thing-at-point 'symbol t))
|
||||
"")))
|
||||
(let ((default-directory
|
||||
(if arg
|
||||
(if-let (projects (projectile-relevant-known-projects))
|
||||
(completing-read "Switch to project: " projects
|
||||
nil t nil nil (doom-project-root))
|
||||
(user-error "There are no known projects"))
|
||||
default-directory)))
|
||||
(cond ((featurep! :completion ivy)
|
||||
(+ivy/project-search nil symbol))
|
||||
((featurep! :completion helm)
|
||||
(+helm/project-search nil symbol))
|
||||
((rgrep (regexp-quote symbol))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +default/search-notes-for-symbol-at-point (&optional symbol)
|
||||
"Conduct a text search in the current project for symbol at point. If prefix
|
||||
ARG is set, prompt for a known project to search from."
|
||||
(interactive
|
||||
(list (rxt-quote-pcre (or (thing-at-point 'symbol t) ""))))
|
||||
(require 'org)
|
||||
(let ((default-directory org-directory))
|
||||
(+default/search-project-for-symbol-at-point
|
||||
nil symbol)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +default/org-notes-search ()
|
||||
"Perform a text search on `org-directory'."
|
||||
(interactive)
|
||||
(require 'org)
|
||||
(let ((default-directory org-directory))
|
||||
(+default/search-project-for-symbol-at-point nil "")))
|
||||
|
||||
;;;###autoload
|
||||
(defun +default/org-notes-headlines ()
|
||||
"Jump to an Org headline in `org-agenda-files'."
|
||||
(interactive)
|
||||
(doom-completing-read-org-headings
|
||||
"Jump to org headline: " org-agenda-files 3 t))
|
||||
|
||||
;;;###autoload
|
||||
(defun +default/lsp-format-region-or-buffer ()
|
||||
"Format the buffer (or selection) with LSP."
|
||||
(interactive)
|
||||
(unless (bound-and-true-p lsp-mode)
|
||||
(user-error "Not in an LSP buffer"))
|
||||
(call-interactively
|
||||
(if (use-region-p)
|
||||
#'lsp-format-region
|
||||
#'lsp-format-buffer)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +default/restart-server ()
|
||||
"Restart the Emacs server."
|
||||
(interactive)
|
||||
(server-force-delete)
|
||||
(while (server-running-p)
|
||||
(sit-for 1))
|
||||
(sleep-for 1))
|
||||
(server-start))
|
||||
|
||||
;;;###autoload
|
||||
(defun +default/find-file-under-here ()
|
||||
"Perform a recursive file search from the current directory."
|
||||
(interactive)
|
||||
(if (featurep! :completion ivy)
|
||||
(call-interactively #'counsel-file-jump)
|
||||
(λ! (doom-project-find-file default-directory))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +default/insert-file-path (arg)
|
||||
"Insert the file name (absolute path if prefix ARG).
|
||||
If `buffer-file-name' isn't set, uses `default-directory'."
|
||||
(interactive "P")
|
||||
(let ((path (or buffer-file-name default-directory)))
|
||||
(insert
|
||||
(if arg
|
||||
(abbreviate-file-name path)
|
||||
(file-name-nondirectory path)))))
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
;;; config/default/config.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defvar +default-want-RET-continue-comments t
|
||||
"If non-nil, RET will continue commented lines.")
|
||||
|
||||
(defvar +default-minibuffer-maps
|
||||
`(minibuffer-local-map
|
||||
minibuffer-local-ns-map
|
||||
minibuffer-local-completion-map
|
||||
minibuffer-local-must-match-map
|
||||
minibuffer-local-isearch-map
|
||||
read-expression-map
|
||||
,@(cond ((featurep! :completion ivy)
|
||||
'(ivy-minibuffer-map
|
||||
ivy-switch-buffer-map))
|
||||
((featurep! :completion helm)
|
||||
'(helm-map
|
||||
helm-ag-map
|
||||
helm-read-file-map))))
|
||||
(append '(minibuffer-local-map
|
||||
minibuffer-local-ns-map
|
||||
minibuffer-local-completion-map
|
||||
minibuffer-local-must-match-map
|
||||
minibuffer-local-isearch-map
|
||||
read-expression-map)
|
||||
(cond ((featurep! :completion ivy)
|
||||
'(ivy-minibuffer-map
|
||||
ivy-switch-buffer-map))
|
||||
((featurep! :completion helm)
|
||||
'(helm-map
|
||||
helm-ag-map
|
||||
helm-read-file-map))))
|
||||
"A list of all the keymaps used for the minibuffer.")
|
||||
|
||||
|
||||
@@ -23,20 +26,32 @@
|
||||
;;;###package avy
|
||||
(setq avy-all-windows nil
|
||||
avy-all-windows-alt t
|
||||
avy-background t)
|
||||
avy-background t
|
||||
;; the unpredictability of this (when enabled) makes it a poor default
|
||||
avy-single-candidate-jump nil)
|
||||
|
||||
|
||||
(after! epa
|
||||
(setq epa-file-encrypt-to
|
||||
(or epa-file-encrypt-to
|
||||
;; Collect all public key IDs with your username
|
||||
(unless (string-empty-p user-full-name)
|
||||
(cl-loop for key in (ignore-errors (epg-list-keys (epg-make-context) user-full-name))
|
||||
collect (epg-sub-key-id (car (epg-key-sub-key-list key)))))
|
||||
user-mail-address)
|
||||
;; With GPG 2.1, this forces gpg-agent to use the Emacs minibuffer to
|
||||
;; prompt for the key passphrase.
|
||||
epa-pinentry-mode 'loopback))
|
||||
;; With GPG 2.1+, this forces gpg-agent to use the Emacs minibuffer to prompt
|
||||
;; for the key passphrase.
|
||||
(set (if EMACS27+
|
||||
'epg-pinentry-mode
|
||||
'epa-pinentry-mode) ; DEPRECATED `epa-pinentry-mode'
|
||||
'loopback)
|
||||
;; Default to the first secret key available in your keyring.
|
||||
(setq-default
|
||||
epa-file-encrypt-to
|
||||
(or (default-value 'epa-file-encrypt-to)
|
||||
(unless (string-empty-p user-full-name)
|
||||
(cl-loop for key in (ignore-errors (epg-list-keys (epg-make-context) user-full-name))
|
||||
collect (epg-sub-key-id (car (epg-key-sub-key-list key)))))
|
||||
user-mail-address))
|
||||
;; And suppress prompts if epa-file-encrypt-to has a default value (without
|
||||
;; overwriting file-local values).
|
||||
(defadvice! +default--dont-prompt-for-keys-a (&rest _)
|
||||
:before #'epa-file-write-region
|
||||
(unless (local-variable-p 'epa-file-encrypt-to)
|
||||
(setq-local epa-file-encrypt-to (default-value 'epa-file-encrypt-to)))))
|
||||
|
||||
|
||||
(use-package! drag-stuff
|
||||
@@ -62,11 +77,6 @@
|
||||
;; or specific :post-handlers with:
|
||||
;; (sp-pair "{" nil :post-handlers '(:rem ("| " "SPC")))
|
||||
(after! smartparens
|
||||
;; Smartparens is broken in `cc-mode' as of Emacs 27. See
|
||||
;; <https://github.com/Fuco1/smartparens/issues/963>.
|
||||
(unless EMACS27+
|
||||
(pushnew! sp--special-self-insert-commands 'c-electric-paren 'c-electric-brace))
|
||||
|
||||
;; Smartparens' navigation feature is neat, but does not justify how
|
||||
;; expensive it is. It's also less useful for evil users. This may need to
|
||||
;; be reactivated for non-evil users though. Needs more testing!
|
||||
@@ -76,7 +86,7 @@
|
||||
sp-navigate-consider-sgml-tags nil)))
|
||||
|
||||
;; Autopair quotes more conservatively; if I'm next to a word/before another
|
||||
;; quote, I likely don't want to open a new pair.
|
||||
;; quote, I don't want to open a new pair or it would unbalance them.
|
||||
(let ((unless-list '(sp-point-before-word-p
|
||||
sp-point-after-word-p
|
||||
sp-point-before-same-p)))
|
||||
@@ -97,10 +107,13 @@
|
||||
(sp-local-pair sp-lisp-modes "(" ")" :unless '(:rem sp-point-before-same-p))
|
||||
|
||||
;; Major-mode specific fixes
|
||||
(sp-local-pair '(ruby-mode enh-ruby-mode) "{" "}"
|
||||
(sp-local-pair 'ruby-mode "{" "}"
|
||||
:pre-handlers '(:rem sp-ruby-pre-handler)
|
||||
:post-handlers '(:rem sp-ruby-post-handler))
|
||||
|
||||
;; Don't eagerly escape Swift style string interpolation
|
||||
(sp-local-pair 'swift-mode "\\(" ")" :when '(sp-in-string-p))
|
||||
|
||||
;; Don't do square-bracket space-expansion where it doesn't make sense to
|
||||
(sp-local-pair '(emacs-lisp-mode org-mode markdown-mode gfm-mode)
|
||||
"[" nil :post-handlers '(:rem ("| " "SPC")))
|
||||
@@ -114,9 +127,7 @@
|
||||
;; Disable electric keys in C modes because it interferes with smartparens
|
||||
;; and custom bindings. We'll do it ourselves (mostly).
|
||||
(after! cc-mode
|
||||
(c-toggle-electric-state -1)
|
||||
(c-toggle-auto-newline -1)
|
||||
(setq c-electric-flag nil)
|
||||
(setq-default c-electric-flag nil)
|
||||
(dolist (key '("#" "{" "}" "/" "*" ";" "," ":" "(" ")" "\177"))
|
||||
(define-key c-mode-base-map key nil))
|
||||
|
||||
@@ -176,7 +187,7 @@
|
||||
(sp-local-pair "(*" "*)" :actions nil)
|
||||
(sp-local-pair "(*" "*"
|
||||
:actions '(insert)
|
||||
:post-handlers '(("| " "SPC") ("|\n[i]*)[d-2]" "RET")))))
|
||||
:post-handlers '(("| " "SPC") ("|[i]*)[d-2]" "RET")))))
|
||||
|
||||
(after! smartparens-markdown
|
||||
(sp-with-modes '(markdown-mode gfm-mode)
|
||||
@@ -196,32 +207,52 @@
|
||||
|
||||
;; This keybind allows * to skip over **.
|
||||
(map! :map markdown-mode-map
|
||||
:ig "*" (λ! (if (looking-at-p "\\*\\* *$")
|
||||
(forward-char 2)
|
||||
(call-interactively 'self-insert-command)))))
|
||||
|
||||
;; Highjacks backspace to:
|
||||
;; a) balance spaces inside brackets/parentheses ( | ) -> (|)
|
||||
;; b) delete up to nearest column multiple of `tab-width' at a time
|
||||
;; c) close empty multiline brace blocks in one step:
|
||||
;; {
|
||||
;; |
|
||||
;; }
|
||||
;; becomes {|}
|
||||
;; d) refresh smartparens' :post-handlers, so SPC and RET expansions work
|
||||
;; even after a backspace.
|
||||
;; e) properly delete smartparen pairs when they are encountered, without
|
||||
;; the need for strict mode.
|
||||
;; f) do none of this when inside a string
|
||||
(advice-add #'delete-backward-char :override #'+default--delete-backward-char-a))
|
||||
|
||||
;; Makes `newline-and-indent' continue comments (and more reliably)
|
||||
(advice-add #'newline-and-indent :override #'+default--newline-indent-and-continue-comments-a))
|
||||
:ig "*" (general-predicate-dispatch nil
|
||||
(looking-at-p "\\*\\* *")
|
||||
(cmd! (forward-char 2)))))))
|
||||
|
||||
|
||||
;;
|
||||
;;; Keybinding fixes
|
||||
|
||||
;; Highjacks backspace to delete up to nearest column multiple of `tab-width' at
|
||||
;; a time. If you have smartparens enabled, it will also:
|
||||
;; a) balance spaces inside brackets/parentheses ( | ) -> (|)
|
||||
;; b) close empty multiline brace blocks in one step:
|
||||
;; {
|
||||
;; |
|
||||
;; }
|
||||
;; becomes {|}
|
||||
;; c) refresh smartparens' :post-handlers, so SPC and RET expansions work even
|
||||
;; after a backspace.
|
||||
;; d) properly delete smartparen pairs when they are encountered, without the
|
||||
;; need for strict mode.
|
||||
;; e) do none of this when inside a string
|
||||
(advice-add #'delete-backward-char :override #'+default--delete-backward-char-a)
|
||||
|
||||
;; HACK Makes `newline-and-indent' continue comments (and more reliably).
|
||||
;; Consults `doom-point-in-comment-functions' to detect a commented region
|
||||
;; and uses that mode's `comment-line-break-function' to continue comments.
|
||||
;; If neither exists, it will fall back to the normal behavior of
|
||||
;; `newline-and-indent'.
|
||||
;;
|
||||
;; We use an advice here instead of a remapping because many modes define
|
||||
;; and remap to their own newline-and-indent commands, and tackling all
|
||||
;; those cases was judged to be more work than dealing with the edge cases
|
||||
;; on a case by case basis.
|
||||
(defadvice! +default--newline-indent-and-continue-comments-a (&rest _)
|
||||
"A replacement for `newline-and-indent'.
|
||||
|
||||
Continues comments if executed from a commented line. Consults
|
||||
`doom-point-in-comment-functions' to determine if in a comment."
|
||||
:before-until #'newline-and-indent
|
||||
(interactive "*")
|
||||
(when (and +default-want-RET-continue-comments
|
||||
(doom-point-in-comment-p)
|
||||
(fboundp comment-line-break-function))
|
||||
(funcall comment-line-break-function nil)
|
||||
t))
|
||||
|
||||
;; This section is dedicated to "fixing" certain keys so that they behave
|
||||
;; sensibly (and consistently with similar contexts).
|
||||
|
||||
@@ -252,6 +283,7 @@
|
||||
"s-c" (if (featurep 'evil) #'evil-yank #'copy-region-as-kill)
|
||||
"s-v" #'yank
|
||||
"s-s" #'save-buffer
|
||||
"s-x" #'execute-extended-command
|
||||
:v "s-x" #'kill-region
|
||||
;; Buffer-local font scaling
|
||||
"s-+" #'doom/reset-font-size
|
||||
@@ -259,7 +291,7 @@
|
||||
"s--" #'doom/decrease-font-size
|
||||
;; Conventional text-editing keys & motions
|
||||
"s-a" #'mark-whole-buffer
|
||||
"s-/" (λ! (save-excursion (comment-line 1)))
|
||||
"s-/" (cmd! (save-excursion (comment-line 1)))
|
||||
:n "s-/" #'evilnc-comment-or-uncomment-lines
|
||||
:v "s-/" #'evilnc-comment-operator
|
||||
:gi [s-backspace] #'doom/backward-kill-to-bol-and-indent
|
||||
@@ -278,6 +310,7 @@
|
||||
(define-key! help-map
|
||||
;; new keybinds
|
||||
"'" #'describe-char
|
||||
"u" #'doom/help-autodefs
|
||||
"E" #'doom/sandbox
|
||||
"M" #'doom/describe-active-minor-mode
|
||||
"O" #'+lookup/online
|
||||
@@ -313,25 +346,27 @@
|
||||
|
||||
;; replaces `apropos-documentation' b/c `apropos' covers this
|
||||
"d" nil
|
||||
"da" #'doom/help-autodefs
|
||||
"db" #'doom/report-bug
|
||||
"dd" #'doom/toggle-debug-mode
|
||||
"dc" #'doom/goto-private-config-file
|
||||
"dC" #'doom/goto-private-init-file
|
||||
"dd" #'doom-debug-mode
|
||||
"df" #'doom/help-faq
|
||||
"dh" #'doom/help
|
||||
"dk" #'doom/goto-packages-file
|
||||
"dl" #'doom/help-search-load-path
|
||||
"dL" #'doom/help-search-loaded-files
|
||||
"dm" #'doom/help-modules
|
||||
"dn" #'doom/help-news
|
||||
"dN" #'doom/help-news-search
|
||||
"di" #'doom/goto-doomblock
|
||||
"dp" #'doom/help-packages
|
||||
"dP" #'doom/help-package-homepage
|
||||
"dc" #'doom/goto-config-file
|
||||
"dC" #'doom/help-package-config
|
||||
"ds" #'doom/help-search
|
||||
"dx" #'doom/sandbox
|
||||
"dN" #'doom/help-search-news
|
||||
"dpc" #'doom/help-package-config
|
||||
"dpd" #'doom/goto-private-packages-file
|
||||
"dph" #'doom/help-package-homepage
|
||||
"dpp" #'doom/help-packages
|
||||
"ds" #'doom/help-search-headings
|
||||
"dS" #'doom/help-search
|
||||
"dt" #'doom/toggle-profiler
|
||||
"du" #'doom/help-autodefs
|
||||
"dv" #'doom/version
|
||||
"dx" #'doom/sandbox
|
||||
|
||||
;; replaces `apropos-command'
|
||||
"a" #'apropos
|
||||
@@ -348,7 +383,7 @@
|
||||
"t" #'load-theme
|
||||
;; replaces `finder-by-keyword' b/c not useful
|
||||
"p" #'doom/help-packages
|
||||
;; replaces `describe-package' b/c redundant w/ `doom/describe-package'
|
||||
;; replaces `describe-package' b/c redundant w/ `doom/help-packages'
|
||||
"P" #'find-library)
|
||||
|
||||
(after! which-key
|
||||
@@ -372,10 +407,15 @@
|
||||
|
||||
;; A Doom convention where C-s on popups and interactive searches will invoke
|
||||
;; ivy/helm for their superior filtering.
|
||||
(define-key! :keymaps +default-minibuffer-maps
|
||||
"C-s" (if (featurep! :completion ivy)
|
||||
#'counsel-minibuffer-history
|
||||
#'helm-minibuffer-history))
|
||||
(when-let (command (cond ((featurep! :completion ivy)
|
||||
#'counsel-minibuffer-history)
|
||||
((featurep! :completion helm)
|
||||
#'helm-minibuffer-history)))
|
||||
(define-key!
|
||||
:keymaps (append +default-minibuffer-maps
|
||||
(when (featurep! :editor evil +everywhere)
|
||||
'(evil-ex-completion-map)))
|
||||
"C-s" command))
|
||||
|
||||
;; Smarter C-a/C-e for both Emacs and Evil. C-a will jump to indentation.
|
||||
;; Pressing it again will send you to the true bol. Same goes for C-e, except
|
||||
@@ -387,14 +427,11 @@
|
||||
;; which ctrl+RET will add a new "item" below the current one and
|
||||
;; cmd+RET (Mac) / meta+RET (elsewhere) will add a new, blank line below
|
||||
;; the current one.
|
||||
:gni [C-return] #'+default/newline-below
|
||||
:gni [C-S-return] #'+default/newline-above
|
||||
:gn [C-return] #'+default/newline-below
|
||||
:gn [C-S-return] #'+default/newline-above
|
||||
(:when IS-MAC
|
||||
:gni [s-return] #'+default/newline-below
|
||||
:gni [S-s-return] #'+default/newline-above)
|
||||
(:unless IS-MAC
|
||||
:gni [M-return] #'+default/newline-below
|
||||
:gni [M-S-return] #'+default/newline-above)))
|
||||
:gn [s-return] #'+default/newline-below
|
||||
:gn [S-s-return] #'+default/newline-above)))
|
||||
|
||||
|
||||
;;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user