First, let’s set the package archives and do some basic tweaks.
(require 'package)
(setq package-enable-at-startup nil) ;; Speed tip taken from Doom Emacs
(setq package-archives '(("ELPA" . "https://tromey.com/elpa/")
("gnu" . "https://elpa.gnu.org/packages/")
("melpa" . "https://melpa.org/packages/")))
;; General convieniences, somewhat questionable
(setq url-http-attempt-keepalives nil)
(setq package-check-signature nil)
We’re going to use straight.el
for package management.
(use-package general) (use-package projectile) (use-package s) (setq org-confirm-babel-evaluate nil)
Are we using native-comp? If so, let’s actually native compile things. Also, the popup compilation warnings are really bothersome, so turn those off, too.
(setq package-native-compile t)
(setq comp-deferred-compilation t)
(setq native-comp-deferred-compilation-deny-list nil)
(setq warning-suppress-log-types '((comp)))
Let’s then use a variety of the tips for speeding up initialization time given by the creator of Doom Emacs.
;; Go back to normal GC behavior after init
(add-hook 'emacs-startup-hook
(lambda ()
(setq gc-cons-threshold 16777216 ; 16mb
gc-cons-percentage 0.1)))
;; Don't do GC when the minibuffer is being used (lag during minibuffer usage is frustrating)
(defun doom-defer-garbage-collection-h ()
"Disable garbage collection."
(setq gc-cons-threshold most-positive-fixnum))
(defun doom-restore-garbage-collection-h ()
"Restore garbage collection."
(run-at-time
1 nil (lambda () (setq gc-cons-threshold 16777216))))
(add-hook 'minibuffer-setup-hook #'doom-defer-garbage-collection-h)
(add-hook 'minibuffer-exit-hook #'doom-restore-garbage-collection-h)
;; GCMH) (literally Garbage Collector Magic Hack) optimizes GC calls?
(use-package gcmh
:init
(setq gcmh-idle-delay 5)
(setq gcmh-high-cons-threshold (* 16 1024 1024))
:config
(gcmh-mode))
Emacs has some default behaviors that are generally annoying. Let’s disable them!
;; Turn off all unnecessary GUI elements.
(tool-bar-mode -1)
(menu-bar-mode -1)
(scroll-bar-mode -1)
;; Unless something is actively exploding, I do not care.
(setq warning-minimum-level :emergency)
;; customize is the worst.
(setq custom-file "/dev/null")
(setq package-selected-packages "/dev/null/")
;; These keybinds suspend Emacs (in order to mimic terminal behavior).
;; This has *only* caused me trouble in GUI Emacs.
(when (display-graphic-p)
(global-unset-key (kbd "C-z"))
(global-unset-key (kbd "C-x C-z")))
;; Stop making backup files everywhere, put them all in one place!
(setq backup-directory-alist `(("." . "~/.saves")))
(setq backup-by-copying t)
;; Stop Emacs from bothering you about disabled commands.
(setq disabled-command-function nil)
;; Prevent any attempts to resize the frame.
(setq frame-inhibit-implied-resize t)
;; Stop Emacs from trying to use dialog boxes.
(setq use-dialog-box nil)
;; Prefer y/n over yes/no.
(fset 'yes-or-no-p 'y-or-n-p)
;; Mouse behavior tweaks? TODO look into me
(setq mouse-wheel-scroll-amount '(1 ((shift) . 1) ((control) . nil)))
(setq mouse-wheel-progressive-speed nil)
;; Visual line mode is just better.
(global-visual-line-mode)
(use-package olivetti
:config
(setq-default olivetti-body-width 180)
:hook ((prog-mode . olivetti-mode)))
(message "got to system")
Let’s now move on to system-level configuration. First, some utility functions for running commands and deducing distro/OS.
(defun process-exit-code-and-output (program &rest args)
"Run PROGRAM with ARGS and return the exit code and output in a list."
(with-temp-buffer
(list (apply 'call-process program nil (current-buffer) nil args)
(buffer-string))))
(defun get-distro-or-os ()
"Return the Linux distribution or OS Emacs is running on."
(if (eq system-type 'darwin)
"Darwin"
(when (eq system-type 'gnu/linux)
(if (file-exists-p "/etc/os-release")
(substring (shell-command-to-string "source /etc/os-release && echo $NAME") 0 -1)
(substring (car (cdr (process-exit-code-and-output "uname" "-o"))) 0 -1)))))
Then, let’s set up system-packages, an awesome package that lets you programmatically install packages from Emacs across operating systems.
(use-package system-packages
:init
(let (os-name (get-distro-or-os))
;; system-packages doesn't support yay by default, so add it.
(when (string= os-name "Arch Linux")
(add-to-list 'system-packages-supported-package-managers
'(yay .
((default-sudo . nil)
(install . "yay -S")
(uninstall . "yay -Rs")
(update . "yay -Syu")
(log . "cat /var/log/pacman.log")
(change-log . "yay -Qc")
(clean-cache . "yay -Sc")
(get-info . "yay -Qi")
(get-info-remote . "yay -Si")
(list-files-provided-by . "yay -Ql")
(owning-file . "yay -Qo")
(verify-all-dependencies . "yay -Dk")
(remove-orphaned . "yay -Rsn $(pacman -Qtdq)")
(list-installed-packages . "yay -Qe")
(list-installed-packages-all . "yay -Q")
(noconfirm . "--noconfirm"))))
(setq system-packages-package-manager 'yay))
(when (string= os-name "Debian GNU/Linux")
(setq system-packages-use-sudo t)
(setq system-packages-package-manager 'apt))
(if (string= os-name "Darwin")
(setq system-packages-package-manager 'brew)))
(setq system-packages-noconfirm t))
This package also has some nice extensions like use-package-ensure-system-package
which lets you express system-level dependencies for Emacs packages, and helm-system-packages
which is the ultimate package manager interface (although it unfortunately means we’ll need to install all of Helm for just this).
(use-package use-package-ensure-system-package)
(use-package helm-system-packages
:commands (helm-system-packages))
(message "got to external")
pywal
will be our savior for theming by allowing for thematic consistency.
;; (use-package exwm
;; :ensure-system-package python-pywal)
kitty
is a terminal emulator that’s featureful and usable.
include ~/.cache/wal/colors-kitty.conf
font_family IBM Plex Mono
cursor_shape block
window_padding_width 10 15
map page_up scroll_page_up
map page_down scroll_page_down
map ctrl+shift+equal change_font_size all +2.0
map ctrl+shift+plus change_font_size all +2.0
map ctrl+shift+kp_add change_font_size all +2.0
initial_window_width 1000
initial_window_height 400
It is clearly of top priority to ensure the Arch logo in neofetch
looks good.
${c1}
▄
▟█▙
▟███▙
▟█████▙
▟███████▙
▂▔▀▜██████▙
▟██▅▂▝▜█████▙
▟█████████████▙
▟███████████████▙
▟█████████████████▙
▟███████████████████▙
▟█████████▛▀▀▜████████▙
▟████████▛ ▜███████▙
▟█████████ ████████▙
▟██████████ █████▆▅▄▃▂
▟██████████▛ ▜█████████▙
▟██████▀▀▀ ▀▀██████▙
▟███▀▘ ▝▀███▙
▟▛▀ ▀▜▙
Firefox could be prettier.
;; (use-package exwm
;; :ensure-system-package (firefox python-pywalfox))
#TabsToolbar {visibility: collapse;}
#statuspanel[type="overLink"] #statuspanel-label {
display:none!important;
}
It’s time to load EXWM, the Emacs X Window Manager.
(message "got to desktop")
(use-package exwm
:init
(setq exwm-workspace-number 2)
(setq exwm-input-global-keys
`(([?\s-r] . exwm-reset)
([?\s-w] . exwm-workspace-switch)
([?\s-&] . (lambda (command)
(interactive (list (read-shell-command "$ "))) ;
(start-process-shell-command command nil command)))))
;; Set default simulation keys
(setq exwm-input-simulation-keys
'(([?\C-a] . [home])
([?\C-e] . [end])
([?\M-v] . [prior])
([?\C-v] . [next])
([?\C-d] . [delete])
([?\C-k] . [S-end delete])))
;; Allow windows to be moved across screens and interacted with normally.
(setq exwm-layout-show-all-buffers t)
(setq exwm-workspace-show-all-buffers t)
:config
(exwm-enable))
Setting up multi-monitor support is a bit of a hack in my configuration since my input devices tend to mysteriously swap around. You’ll notice I’m using use-package
for the same package twice in a row here, but fear not, it merely executes them sequentially and it means I can intersperse long-winded package configuration with text without fear of accidentally breaking something one day.
(use-package exwm
:init
(defvar left-screen "HDMI-1")
(defvar middle-screen "eDP-1")
; (defvar right-screen "DP-1")
:config
(require 'exwm-randr)
(setq exwm-randr-workspace-output-plist `(0 ,middle-screen 1 ,left-screen))
(exwm-randr-enable))
;; (use-package ivy
;; :config
;; (call-process-shell-command (concat "xrandr --output" left-screen " --left-of " middle-screen) 0)
;; (call-process-shell-command (concat "xrandr --output" left-screen " --left-of " middle-screen) 0)
;; (call-process-shell-command (concat "xrandr --output" right-screen " --right-of " middle-screen) 0)
(call-process-shell-command "feh --bg-fill ~/.config/wallpapers/firewatch-galaxy.jpg" nil 0)
;; (start-process-shell-command "polybar-update" nil
;; (concat "sed s/<MONITOR>/"
;; middle-screen
;; "/g -i ~/.config/polybar/config.ini.bak > ~/.config/polybar/config.ini"))
(call-process-shell-command "bash ~/.config/polybar/launch.sh --material" nil 0)
(use-package exwm-outer-gaps
:straight (exmw-outer-gaps :type git :host github :repo "lucasgruss/exwm-outer-gaps")
:config
(defun exwm-outer-gaps-redraw ()
"exwm-outer gaps sometimes has artifacts in the gap area. Quickly toggling the mode on and off works forces a redraw of the gaps and gets rid of them."
(interactive)
(exwm-outer-gaps-mode))
:hook (exwm-init
. (lambda () (exwm-outer-gaps-mode))))
Next, if we’re on Linux, let’s do everything we need to do at startup.
xmodmap
lets you modify the keys, so let’s make things a lot nicer for Emacs.
clear lock
clear control
clear mod1
clear mod2
clear mod3
clear mod4
clear mod5
keycode 37 = Hyper_L
keycode 66 = Control_L
keycode 9 = Escape
keycode 0xffca = Escape
add control = Control_L Control_R
add mod1 = Alt_L Alt_R Meta_L
add mod2 = Num_Lock
add mod3 = Hyper_L
add mod4 = Super_L Super_R
add mod5 = Mode_switch ISO_Level3_Shift
xbindkeys
allows for customizing system-wide keybinds which can be useful when you’re in a pickle. Most of this is legacy config from back before I started using EXWM.
# -*- shell-script -*-
# TODO Phase me out!
# Increase volume
"pamixer -i 5"
XF86AudioRaiseVolume
# Decrease volume
"pamixer -d 5"
XF86AudioLowerVolume
"pamixer -t"
XF86AudioMute
"bash ~/.config/rofi/applets/menu/screenshot.sh"
Print
"bash ~/.config/rofi/applets/menu/powermenu.sh"
Pause
"bash ~/.config/rofi/applets/menu/apps.sh"
Scroll_Lock
"bash ~/.config/rofi/launchers/type-4/launcher.sh"
alt + p
"betterlockscreen -l blur"
alt + shift + l
"bash ~/.config/rofi/launchers/ribbon/launcher.sh"
alt + shift + p
"sh ~/.config/focus.sh"
alt + shift + f
"python ~/.config/modeset.py 'normal'"
m:0x20 + c:37 + F1
"rofi -show calc -modi calc -no-show-match -no-sort"
XF86Calculator
"sp next"
alt + shift + control + l
"sp prev"
alt + shift + control + h
"sp play"
alt + shift + control + p
"bash ~/spotvol.sh lower"
alt + shift + control + j
"bash ~/spotvol.sh"
alt + shift + control + k
xcape
allows for “dual-function” keys that can act as one key when held down, and another when tapped. It’s niche but useful. We’ll remap tapping left-shift and right-shift to left and right parentheses respectively, as well as r=)emap tapping caps-lock to escape.
xcape -e "Control_L=Escape"
xcape -e "Shift_R=parenright"
xcape -e "Shift_L=parenleft"
dunst
is a great notification server.
[global]
monitor = 0
follow = keyboard
geometry = "320x20-36+36"
indicate_hidden = yes
shrink = yes
transparency = 0
notification_height = 0
separator_height = 0
padding = 8
horizontal_padding = 8
frame_width = 2
frame_color = "#000000"
separator_color = frame
sort = yes
idle_threshold = 120
font = IBM Plex Mono 10
line_height = 0
markup = full
format = "<b>%s</b>\n<i>%b</i>"
alignment = left
show_age_threshold = 60
word_wrap = yes
ellipsize = middle
ignore_newline = no
stack_duplicates = true
hide_duplicate_count = false
show_indicators = false
icon_position = left
max_icon_size = 32
icon_path = /usr/share/icons/candy-icons/apps/scalable:/usr/share/icons/candy-icons/devices/scalable/
sticky_history = yes
history_length = 20
dmenu = /usr/bin/dmenu -p dunst:
browser = /usr/bin/firefox -new-tab
always_run_script = true
title = Dunst
class = Dunst
startup_notification = false
verbosity = mesg
corner_radius = 0
force_xinerama = false
mouse_left_click = close_current
mouse_middle_click = do_action
mouse_right_click = close_all
[experimental]
per_monitor_dpi = false
[shortcuts]
close = ctrl+space
close_all = ctrl+shift+space
history = ctrl+grave
context = ctrl+shift+grave
[urgency_low]
foreground = "#ffd5cd"
background = "#121212"
frame_color = "#a2c5de"
timeout = 10
icon = ~/.config/dunst/images/notification.png
[urgency_normal]
background = "#121212"
foreground = "#ffd5cd"
frame_color = "#a2c5de"
timeout = 10
icon = ~/.config/dunst/images/notification.png
[urgency_critical]
background = "#121212"
foreground = "#ffd5cd"
frame_color = "#a2c5de"
timeout = 0
icon = ~/.config/dunst/images/alert.png
Let’s define a quick script to reload it based on pywal, too.
. "${HOME}/.cache/wal/colors.sh"
pkill dunst
dunst \
-frame_width 2 \
-lb "${color0}" \
-nb "${color0}" \
-cb "${color0}" \
-lf "${color7}" \
-bf "${color7}" \
-cf "${color7}" \
-nf "${color7}" \
-frame_color "${color2}" &
picom
is a nice compositor, and will allow us to have effects like rounded corners and transparency if we want them. Dual kawase blur looks very nice, so let’s use it.
backend = "glx";
blur: {
method = "dual_kawase";
strength = 10;
background = false;
background-frame = false;
background-fixed = false;
}
Finally, we actually run the startup.
(message "got to exwm startup")
(use-package exwm
; :ensure-system-package (xbindkeys xcape dunst flameshot unclutter polybar feh picom)
:config
;; Rebind keys
(call-process-shell-command "xmodmap ~/.config/X/Xmodmap" nil 0)
(call-process-shell-command "xbindkeys" nil 0)
(call-process-shell-command "sh ~/.config/X/xcape.sh" nil 0)
;; Notifications w/ dunst
(call-process-shell-command "dunst &" nil 0)
(call-process-shell-command "sh ~/.config/dunst/reload_dunst.sh" nil 0)
;; Make mouse vanish when not used
(call-process-shell-command "unclutter &" nil 0)
;; The best screenshot utility!
(call-process-shell-command "flameshot &" nil 0)
;; Compositor
(call-process-shell-command "picom &" nil 0))
Let’s make moving across monitors and workspaces a little easier.
(defun exwm-workspace-next ()
(interactive)
(if (< exwm-workspace-current-index (- exwm-workspace-number 1))
(exwm-workspace-switch (+ exwm-workspace-current-index 1))))
(defun exwm-workspace-prev ()
(interactive)
(if (> exwm-workspace-current-index 0)
(exwm-workspace-switch (- exwm-workspace-current-index 1))))
(use-package exwm
:after general
:init
(general-define-key
"M-h" 'exwm-workspace-next
"M-l" 'exwm-workspace-prev))
;; Make mouse follow focus
(use-package exwm-mff
:init (exwm-mff-mode))
(use-package exwmsw
:straight (exwmsw :type git :host github :repo "Lemonbreezes/exwmsw"
:fork (:host github :repo "richardfeynmanrocks/exwmsw"))
:init
(setq exwmsw-active-workspace-plist `(,middle-screen 0 ,right-screen 0 ,left-screen 0))
(setq exwmsw-the-right-screen right-screen)
(setq exwmsw-the-center-screen middle-screen)
(setq exwmsw-the-left-screen left-screen)
;; :general
;; (override-global-map
;; "C-M-j" #'exwmsw-cycle-screens
;; "C-M-k" #'exwmsw-cycle-screens-backward)
;; (exwm-mode-map ;; HACK
;; "C-M-j" #'exwmsw-cycle-screens
;; "C-M-k" #'exwmsw-cycle-screens-backward)
)
(message "finished monitor schenanigans")
Then, make it so EXWM buffer names contain part of the the window title based off this great tip from r/emacs.
(use-package exwm
:init
(defun b3n-exwm-set-buffer-name ()
(if (and exwm-title (string-match "\\`http[^ ]+" exwm-title))
(let ((url (match-string 0 exwm-title)))
(setq-local buffer-file-name url)
(setq-local exwm-title (replace-regexp-in-string
(concat (regexp-quote url) " - ")
""
exwm-title))))
(setq-local exwm-title
(concat
exwm-class-name
"<"
(if (<= (length exwm-title) 50)
exwm-title
(concat (substring exwm-title 0 50) "…"))
">"))
(exwm-workspace-rename-buffer exwm-title))
(add-hook 'exwm-update-class-hook 'b3n-exwm-set-buffer-name)
(add-hook 'exwm-update-title-hook 'b3n-exwm-set-buffer-name))
(use-package elcord
:init
(setq elcord-display-buffer-details nil)
(setq elcord-use-major-mode-as-main-icon t)
(setq elcord-icon-base (lambda (icon)
(concat (if (string= icon "c0-mode_icon")
"https://quantumish.github.io/random/"
"https://raw.githubusercontent.com/Mstrodl/elcord/master/icons/") icon ".png")))
:config
(add-to-list 'elcord-mode-text-alist '(c0-mode . "C0"))
(add-to-list 'elcord-mode-icon-alist '(c0-mode . "c0-mode_icon"))
(add-to-list 'elcord-mode-text-alist '(c02-mode . "C0"))
(add-to-list 'elcord-mode-icon-alist '(c02-mode . "c0-mode_icon"))
(elcord-mode))
;; TODO: Set up treemacs.
(set-face-attribute 'default nil :family "ttyp0")
(set-face-attribute 'font-lock-comment-face nil :italic t)
(use-package hide-mode-line)
(use-package doom-themes
:init
;; Global settings (defaults)
(setq doom-themes-enable-bold t ; if nil, bold is universally disabled
doom-themes-enable-italic t) ; if nil, italics is universally disabled
(doom-themes-visual-bell-config)
;(setq doom-themes-treemacs-theme "doom-colors") ; use the colorful treemacs theme
;(doom-themes-treemacs-config)
(doom-themes-org-config))
(use-package ewal)
(use-package ewal-doom-themes
:init
(load-theme 'ewal-doom-one t))
(use-package doom-modeline
:init
(setq doom-modeline-height 40)
(setq doom-modeline-buffer-encoding nil)
(doom-modeline-mode))
;; TODO: Contextual solaire
(use-package solaire-mode
:hook
(prog-mode . solaire-mode))
(fringe-mode 0)
;; (use-package centaur-tabs
;; :init
;; (setq centaur-tabs-height 16)
;; (setq centaur-tabs-style "bar")
;; (setq centaur-tabs-set-icons t)
;; (setq centaur-tabs-icon-scale-factor 0.7)
;; (setq centaur-tabs-set-bar 'left)
;; (setq x-underline-at-descent-line t)
;; (defun contextual-tabs ()
;; (interactive)
;; (if (and (centaur-tabs-mode-on-p) (eq (derived-mode-p 'prog-mode) nil))
;; (centaur-tabs-local-mode)))
;; (defun centaur-tabs-hide-tab (x)
;; (let ((name (format "%s" x)))
;; (or
;; (window-dedicated-p (selected-window))
;; (string-match-p (regexp-quote "<") name)
;; (string-prefix-p "*lsp" name)
;; (string-prefix-p "*Compile-Log*" name)
;; (string-prefix-p "*company" name)
;; (string-prefix-p "*compilation" name)
;; (string-prefix-p "*Help" name)
;; (string-prefix-p "*straight" name)
;; (string-prefix-p "*Flycheck" name)
;; (string-prefix-p "*tramp" name)
;; (string-prefix-p "*help" name)
;; (and (string-prefix-p "magit" name)
;; (not (file-name-extension name)))
;; )))
;; (defun centaur-tabs-hide-tab-cached (x) (centaur-tabs-hide-tab x))
;; (centaur-tabs-mode)
;; :hook
;; (after-change-major-mode . contextual-tabs)
;; :bind
;; ("H-l" . 'centaur-tabs-forward-tab)
;; ("H-h" . 'centaur-tabs-backward-tab))
(use-package treemacs
:after doom-themes
:init
(doom-themes-treemacs-config)
(setq doom-themes-treemacs-theme "doom-colors")
(setq treemacs-width 30)
(treemacs-project-follow-mode)
:bind
("C-c t" . treemacs)
:hook
(treemacs-mode .
(lambda ()
(setq header-line-format " ")
(face-remap-add-relative 'header-line '(:height 20 :background "#0e121a"))
)
))
(use-package treemacs-projectile)
(use-package treemacs-all-the-icons
:after treemacs
:init
(treemacs-load-theme "all-the-icons"))
(use-package olivetti
:config
(setq-default olivetti-body-width 180)
:hook ((prog-mode . olivetti-mode)))
;; (prog-mode .
;; (lambda ()
;; (setq header-line-format " ")
;; (face-remap-add-relative 'header-line '(:height 100 :background "#0b0f16"))
;; ))
Transparency can look nice - sometimes. Polybar clashes with transparency, so disable it while we’re using it.
;; FIXME hacky and broken
(define-minor-mode translucent-mode
"Make the current frame slightly transparent and don't use polybar."
nil
:global t
(if translucent-mode
(set-frame-parameter (selected-frame) 'alpha '(100))
(set-frame-parameter (selected-frame) 'alpha '(90))))
(use-package dashboard
:straight (emacs-dashboard :type git :host github :repo "emacs-dashboard/emacs-dashboard"
:fork (:host github :repo "richardfeynmanrocks/emacs-dashboard"))
:init
(setq dashboard-center-content t)
(setq dashboard-set-heading-icons t)
(setq dashboard-projects-backend 'projectile)
(setq dashboard-footer-messages '("The One True Editor!"
"Protocol 3: Protect the Pilot"
"All systems nominal."
"Democracy... is non negotiable."
"It's my way or... hell, it's my way!"
"Make life rue the day it though it could give Richard Stallman lemons!"
"Vi-Vi-Vi, the editor of the beast."
"Happy hacking!"
"While any text editor can save your files, only Emacs can save your soul."
"There's an Emacs package for that."
"Rip and tear, until it is done!"
"It's time to kick ass and chew bubblegum... and I'm all outta gum."
"Eight Megabytes And Constantly Swapping"
"Escape Meta Alt Control Super"
"M-x butterfly"
"The thermonuclear word processor."
"The best OS!"
""))
(setq dashboard-items '((recents . 3)
(projects . 3)
(agenda . 5)))
(setq dashboard-startup-banner "~/.config/wallpapers/firewatch-galaxy.png")
(setq dashboard-image-banner-max-height 250)
(setq dashboard-image-banner-max-width 500)
(setq dashboard-set-init-info nil)
(setq dashboard-set-navigator t)
;; Format: "(icon title help action face prefix suffix)"
(setq dashboard-page-separator "\n\n")
:config
(setq dashboard-navigator-buttons
`(;; line1
((,(all-the-icons-faicon "github" :height 1 :v-adjust 0.0)
"Github"
"Browse repo"
(lambda (&rest _) (browse-url "https://github.com/quantumish/.emacs.d")))
(,(all-the-icons-faicon "reddit-alien" :height 1 :v-adjust 0.0)
"r/emacs"
"Waste time"
(lambda (&rest _) (browse-url "https://reddit.com/r/emacs"))))))
(dashboard-setup-startup-hook)
:hook
(dashboard-mode . hide-mode-line-mode)
(dashboard-mode . turn-off-solaire-mode))
Next, let’s improve interactions with Emacs: things like finding files, running commands, switching buffers, etc… by using ivy
, a light(ish) minibuffer completion system. Ivy is one of the more popular packages for this, meaning that there’s quite a bit of integration with other packages. Notably, counsel
extends its functionality and swiper
provides a nicer interface to interactive search.
On top of this, prescient
allows for completions to be even more useful by basing them off of history and sorting them better. Finally, we can add some icons and extra text to make it all prettier.
(org-babel-tangle-file "~/.emacs.d/completion.org")
(org-babel-load-file "~/.emacs.d/completion.org")
(use-package prescient
:init (setq prescient-persist-mode t))
(use-package ivy
:init
(use-package counsel :config (counsel-mode 1))
(use-package swiper :defer t)
(ivy-mode 1)
(setq counsel-search-engine 'google)
:bind
(("C-s" . swiper-isearch)
("M-x" . counsel-M-x)
("C-x C-f" . counsel-find-file)
("C-x C-l" . counsel-load-theme)
("C-h C-f" . counsel-faces)
("M-s g" . counsel-search)
("M-g o" . counsel-outline)
("M-g h" . counsel-org-goto-all)
("M-g i" . counsel-imenu)
("M-g a" . counsel-linux-app)))
(use-package counsel-projectile
:bind
(("M-g p" . counsel-projectile-switch-project)))
(use-package ivy-rich
:after ivy
:init (ivy-rich-mode))
(use-package all-the-icons)
(use-package all-the-icons-ivy-rich
:after ivy-rich counsel
:init (all-the-icons-ivy-rich-mode))
(use-package ivy-prescient
:after ivy prescient
:init (ivy-prescient-mode))
(use-package marginalia
:config (marginalia-mode))
In order to make some parts of exploring Emacs slightly nicer, let’s install helpful
which overhauls the Help interface, and which-key
which helps you discover keybinds.
(use-package helpful
:init
;; Advise describe-style functions so that Helpful appears no matter what
(advice-add 'describe-function :override #'helpful-function)
(advice-add 'describe-variable :override #'helpful-variable)
(advice-add 'describe-command :override #'helpful-callable)
(advice-add 'describe-key :override #'helpful-key)
(advice-add 'describe-symbol :override #'helpful-symbol)
:config
;; Baseline keybindings, not very opinionated
(global-set-key (kbd "C-h f") #'counsel-describe-function)
(global-set-key (kbd "C-h v") #'counsel-describe-variable)
(global-set-key (kbd "C-h k") #'helpful-key)
(global-set-key (kbd "C-c C-d") #'helpful-at-point)
(global-set-key (kbd "C-h F") #'helpful-function)
(global-set-key (kbd "C-h C") #'helpful-command)
;; Counsel integration
(setq counsel-describe-function-function #'helpful-callable)
(setq counsel-describe-variable-function #'helpful-variable))
(use-package which-key
:init (which-key-mode))
(use-package zygospore)
(defun opposite-other-window ()
"Cycle buffers in the opposite direction."
(interactive)
(other-window -1))
(defun opposite-other-frame ()
"Cycle frames in the opposite direction."
(interactive)
(other-frame -1))
(use-package exwm
:after 'general
:config
(general-define-key
:keymaps '(exwm-mode-map override-global-map)
"M-k" 'other-window
"M-j" 'opposite-other-window
"C-M-j" 'opposite-other-frame
"C-M-k" 'other-frame
"M-m" 'zygospore-toggle-delete-other-windows))
(use-package drag-stuff
:config
(general-def
"M-<up>" 'drag-stuff-up
"M-<down>" 'drag-stuff-down))
First, let’s set up the basics.
(use-package org
:init
(setq org-todo-keywords '((sequence "TODO(t)" "WAIT(w)" "|" "DONE(d)" "NOPE(n)")))
(setq org-modules (append org-modules '(org-habit org-id))) )
Let’s add aesthetics for normal prose-style Org usage.
(use-package org
:config
(setq org-fontify-quote-and-verse-blocks t)
(setq org-fontify-emphasized-text t)
(setq org-hide-emphasis-markers t)
(setq org-ellipsis " ")
(setq org-hide-leading-stars t)
(set-face-attribute 'org-document-title nil
:height 2.0
:weight 'bold)
:hook (org-mode . org-indent-mode))
There are a variety of useful packages that make Org look nicer:
(setq org-latex-create-formula-image-program 'dvisvgm)
(setq org-highlight-latex-and-related '(native))
;; Smart mixing of variable pitch and monospace
;; This is preferred over `mixed-pitch` because of small details
(use-package org-variable-pitch
:init (org-variable-pitch-setup))
;; Better headline icons
(use-package org-superstar
:config
(setq org-superstar-headline-bullets-list '("◉" "○" "◈" "◎"))
:hook (org-mode . org-superstar-mode))
;; Auto-toggle emphasis
(use-package org-appear
:straight (:host github :repo "awth13/org-appear")
:hook (org-mode . org-appear-mode))
;; Auto-toggle LaTeX rendering
(use-package xenops
:hook (org-mode . xenops-mode)
:config (defun xenops-handle-paste ()))
;; Natural bulleted lists
(use-package org-autolist
:hook (org-mode . org-autolist-mode))
;; Centering w/ Olivetti
(use-package olivetti
:hook (org-mode . (lambda () (interactive) (olivetti-mode) (olivetti-set-width 100))))
(use-package org
:config
(defun magic-icon-fix ()
(let ((fontset (face-attribute 'default :fontset)))
(set-fontset-font fontset '(?\xf000 . ?\xf2ff) "FontAwesome" nil 'append)))
:hook
(org-mode . (lambda () (interactive)
(setq prettify-symbols-alist '(("[#A]" . "")
("[#B]" . "")
("[#C]" . "")
("[ ]" . "")
("[X]" . "")
("[-]" . "")
("#+begin_src" . "")
("#+end_src" . "―")
("#+begin_collapsible" . "")
("#+end_collapsible" . "―")
("#+begin_aside" . "")
("#+end_aside" . "―")
("#+begin_quote" . "")
("#+end_quote" . "―")
("#+begin_defn" . "")
("#+end_defn" . "―")
("#+begin_questionable" . "")
("#+end_questionable" . "―")
("#+begin_problem" . "")
("#+end_problem" . "―")
("#+EXCLUDE_TAGS:" . "")
(":PROPERTIES:" . "\n")
(":END:" . "―")
("#+STARTUP:" . "")
("#+TITLE: " . "")
("#+title: " . "")
("#+RESULTS:" . "")
("#+NAME:" . "")
("#+ROAM_TAGS:" . "")
("#+FILETAGS:" . "")
("#+HTML_HEAD:" . "")
("#+SUBTITLE:" . "")
("#+AUTHOR:" . "")
(":Effort:" . "")
("SCHEDULED:" . "")
("DEADLINE:" . "")
("#+begin_defn" . "")
("#+end_defn" . "―")
("#+TITLE: " . "")
))
(prettify-symbols-mode))))
(use-package org-roam
:init
(setq org-roam-directory (concat (getenv "HOME") "/sync/notes"))
(setq org-roam-v2-ack t)
:bind
("C-c n i" . org-roam-node-insert)
("C-c n f" . org-roam-node-find)
("C-c n s" . org-roam-db-sync))
(use-package org-roam-ui
:straight
(:host github :repo "org-roam/org-roam-ui" :branch "main" :files ("*.el" "out"))
:after org-roam
;; :hook (after-init . org-roam-ui-mode)
:config
(setq org-roam-ui-sync-theme t
org-roam-ui-follow t
org-roam-ui-update-on-save t
org-roam-ui-open-on-start t))
(use-package deft
:init
(setq deft-directory org-roam-directory)
(defun my/deft-parse-title (file contents)
"Parse the given FILE and CONTENTS and determine the title.
If `deft-use-filename-as-title' is nil, the title is taken to
be the first non-empty line of the FILE. Else the base name of the FILE is
used as title."
(let ((begin (string-match "^#\\+[tT][iI][tT][lL][eE]: .*$" contents)))
(if begin
(string-trim (substring contents begin (match-end 0)) "#\\+[tT][iI][tT][lL][eE]: *" "[\n\t ]+")
(deft-base-filename file))))
(advice-add 'deft-parse-title :override #'my/deft-parse-title)
(setq deft-strip-summary-regexp
(concat "\\("
"[\n\t]" ;; blank
"\\|^#\\+[[:alpha:]_]+:.*$" ;; org-mode metadata
"\\|^:PROPERTIES:\n\\(.+\n\\)+:END:\n"
"\\)")))
(use-package org
:init
(defvar org-inbox-file (concat (getenv "HOME") "/sync/org/inbox.org"))
(defvar org-completed-file (concat (getenv "HOME") "/sync/org/completed.org"))
(setq org-archive-location (concat org-completed-file "::"))
(setq org-agenda-files (list (concat (getenv "HOME") "/sync/org/cmu.org")))
;; :general
;; ("C-c o i" #'(lambda () (interactive) (find-file org-inbox-file)))
;; ("C-c o a" #'(lambda () (interactive) (org-agenda 'a)))
)
(use-package org
:init
(setq org-enforce-todo-dependencies t)
(setq org-enforce-todo-checkbox-dependencies t)
(setq org-agenda-dim-blocked-tasks t))
(use-package vterm
:hook (vterm-mode . rename-uniquely))
(defun dw/get-prompt-path ()
(let* ((current-path (eshell/pwd))
(git-output (shell-command-to-string "git rev-parse --show-toplevel"))
(has-path (not (string-match "^fatal" git-output))))
(if (not has-path)
(abbreviate-file-name current-path)
(string-remove-prefix (file-name-directory git-output) current-path))))
;; This prompt function mostly replicates my custom zsh prompt setup
;; that is powered by github.com/denysdovhan/spaceship-prompt.
(defun dw/eshell-prompt ()
(concat
"\n"
(propertize "davfrei" 'face `(:foreground ,(doom-color 'orange)) 'read-only t)
(propertize " " 'face `(:foreground "white") 'read-only t)
(propertize (dw/get-prompt-path) 'face `(:foreground ,(doom-color 'orange)) 'read-only t)
(propertize " · " 'face `(:foreground "white") 'read-only t)
(propertize (format-time-string "%I:%M:%S %p") 'face `(:foreground ,(doom-color 'cyan)) 'read-only t)
(if (= (user-uid) 0)
(propertize "\n#" 'face `(:foreground "red2") 'read-only t)
(propertize "\nλ" 'face `(:foreground ,(doom-color 'blue)) 'read-only t))
(propertize " " 'face `(:foreground ,(doom-color 'fg)))
))
(defun dw/eshell-configure ()
(use-package xterm-color)
(push 'eshell-tramp eshell-modules-list)
(push 'xterm-color-filter eshell-preoutput-filter-functions)
(delq 'eshell-handle-ansi-color eshell-output-filter-functions)
;; Save command history when commands are entered
(add-hook 'eshell-pre-command-hook 'eshell-save-some-history)
(add-hook 'eshell-before-prompt-hook
(lambda ()
(setq xterm-color-preserve-properties t)))
;; Truncate buffer for performance
(add-to-list 'eshell-output-filter-functions 'eshell-truncate-buffer)
;; We want to use xterm-256color when running interactive commands
;; in eshell but not during other times when we might be launching
;; a shell command to gather its output.
(add-hook 'eshell-pre-command-hook
(lambda () (setenv "TERM" "xterm-256color")))
(add-hook 'eshell-post-command-hook
(lambda () (setenv "TERM" "dumb")))
;; Use completion-at-point to provide completions in eshell
(define-key eshell-mode-map (kbd "<tab>") 'completion-at-point)
;; Initialize the shell history
(eshell-hist-initialize)
(setenv "PAGER" "cat")
(setq eshell-prompt-function 'dw/eshell-prompt
eshell-prompt-regexp "^λ "
eshell-history-size 10000
eshell-buffer-maximum-lines 10000
eshell-hist-ignoredups t
eshell-highlight-prompt t
eshell-scroll-to-bottom-on-input t
eshell-prefer-lisp-functions nil))
(use-package eshell
:hook (eshell-first-time-mode . dw/eshell-configure)
:init
(setq eshell-directory-name "~/.dotfiles/.emacs.d/eshell/"
eshell-aliases-file (expand-file-name "~/.dotfiles/.emacs.d/eshell/alias")))
(use-package eshell-z
:hook ((eshell-mode . (lambda () (require 'eshell-z)))
(eshell-z-change-dir . (lambda () (eshell/pushd (eshell/pwd))))))
(use-package exec-path-from-shell
:init
(setq exec-path-from-shell-check-startup-files nil)
:config
(when (memq window-system '(mac ns x))
(exec-path-from-shell-initialize)))
(setq eshell-prompt-function 'dw/eshell-prompt)
(use-package esh-autosuggest
:hook (eshell-mode . esh-autosuggest-mode))
(use-package eshell-toggle
:straight (eshell-toggle :type git :host github :repo "4DA/eshell-toggle")
:init
(setq eshell-toggle-size-fraction 4)
(setq eshell-toggle-use-projectile-root t)
(setq eshell-toggle-run-command nil))
(use-package eshell-up) ;; TODO eshell-up
;; (use-package eshell-info-banner
;; :straight (eshell-info-banner :type git :host github
;; :repo "phundrak/eshell-info-banner.el")
;; :hook (eshell-banner-load . eshell-info-banner-update-banner))
;; (use-package eshell-fringe-status
;; :init
;; (setq eshell-fringe-status-success-bitmap 'my-flycheck-fringe-indicator)
;; (setq eshell-fringe-status-failure-bitmap 'my-flycheck-fringe-indicator)
;; :hook (eshell-mode . eshell-fringe-status-mode))
;; (use-package esh-help
;; :init (setup-esh-help-eldoc))
lsp-mode
enables us to get Intellisense-esque features in Emacs: setting it up requires both config on Emacs’ side and installing actual language servers on your side. We’ll auto-install them with the magic of use-package-ensure-system-package
, although brace yourself for the potential for lots of debugging if the server doesn’t work as expected on your system.
lsp-mode
can do more than just provide good completions: you can jump to definitions and references with lsp-find-definition
and lsp-find-references
respectively, as well as most other things you’d expect from an IDE.
(use-package lsp-mode
; :ensure-system-package ccls
; :ensure-system-package (pyls . "python -m pip install pyls")
; :ensure-system-package rust-analyzer
:init
;; Disable annoying headerline
(setq lsp-headerline-breadcrumb-enable nil)
;; Don't show unneeded function info in completions
(setq lsp-completion-show-detail nil)
;; Disable annoying autoformatting!
(setq-default lsp-enable-indentation nil)
(setq-default lsp-enable-on-type-formatting nil)
:commands lsp
;; Add languages of your choice!
:hook ((c-mode . lsp)
(c++-mode . lsp)
(python-mode . lsp)
(typescript-mode . lsp)
(rust-mode . lsp)
(lsp-mode . (lambda () (lsp-lens-mode 0)))))
(use-package lsp-ui
:after lsp
:init
(setq lsp-ui-doc-delay 5)
(add-hook 'flycheck-mode-hook 'lsp-ui-mode) ;; HACK
(add-hook 'lsp-mode-hook 'lsp-ui-mode)
;; (general-def
;; :keymaps 'lsp-mode-map
;; "C-c l p" 'lsp-ui-peek-find-references)
:config
(eval `(set-face-attribute 'lsp-ui-doc-background nil :background ,(doom-darken 'bg .2))))
company-mode
provides code completions in Emacs, and will work together with lsp-mode
to provide a nice experience. On top of that, let’s use add-ons that allow documentation for completions to pop up and also let prescient
make things better like it did with Ivy.
(use-package company
:init
(setq company-idle-delay 0)
(setq company-tooltip-maximum-width 40)
:hook
(prog-mode . company-mode))
(use-package company-quickhelp
:after company
:init (company-quickhelp-mode))
(use-package company-quickhelp-terminal
:after company-quickhelp)
(use-package company-prescient
:after company prescient
:init
(setq-default history-length 1000)
(setq-default prescient-history-length 1000)
:init (company-prescient-mode))
(use-package kv)
(require 'kv)
(defvar custom-compile-cmds
'((rustic-mode . ((debug . "cargo build")
(release . "cargo build --release")
(test . "cargo test")))
(c++-mode . ((cmake . "cmake .")
(test . "ctest")
(make . "make")
(this . "g++ $this.cpp -std=c++17 -o $this")
(this-debug . "g++ $this.cpp -std=c++17 -g -o $this")
(this-speedy . "g++ $this.cpp -O3 -std=c++17 -o $this")
(this-python . "g++ -shared -std=c++17 -undefined_dynamic_lookup `python3 -m pybind11 --includes` $this.cpp -o $this`python3-config --extension-suffix` -D PYTHON -fPIC")))
(c-mode . ((make . "make")
(this . "gcc $this.c -o $this")
(this-speedy . "gcc $this.c -O3 -o $this")
(this-archive . "gcc $this.c -O -c -g && ar rcs $this.a $this.o")
(this-mpi . "mpicc $this.c -o $this")))
(cuda-mode . ((this . "nvcc $this.cu -o $this")))
(python-mode . ((this-types . "mypy $this.py --ignore-missing-imports --strict")
(this-cython . "cython --embed -o $this.c $this.py -3 && sudo gcc $this.c -o $this -I/usr/include/python3.9 -lpython3.9")))
))
(defun compile-dwim ()
(interactive)
(let ((list (cdr (assoc major-mode custom-compile-cmds)))) ;; Debugging is for suckers
(ivy-read "Compilation preset: " (kvalist->keys list)
:preselect (car (kvalist->keys list))
:action (lambda (name)
(compile
(replace-regexp-in-string
(regexp-quote "$this")
(file-name-sans-extension (buffer-file-name))
(cdr (assoc (intern-soft name) list))))))))
(use-package compile
:config
(setq compilation-scroll-output t)
(setq compilation-ask-about-save nil)
(defun compile-project ()
(interactive)
(let ((default-directory (projectile-project-root)))
(call-interactively 'compile-dwim)))
(require 'ansi-color)
(defun colorize-compilation-buffer ()
(toggle-read-only)
(ansi-color-apply-on-region compilation-filter-start (point))
(toggle-read-only))
(add-hook 'compilation-filter-hook 'colorize-compilation-buffer)
:bind (:map prog-mode-map
("C-;" . compile-project))
:hook
(compilation-mode . hide-mode-line-mode)
; (compilation-mode . (lambda () (set-header-line 200)))
(compilation-start . olivetti-mode)
(compilation-start . determine-olivetti))
(defun minimal-browse-url (url)
"Browse an arbitrary url (as URL) in a new frameless Firefox window."
(split-window-right)
(other-window 1)
(call-process-shell-command (concat "firefox -P default-release --new-window " url) nil 0))
(use-package dash-docs)
(use-package counsel-dash
:config
(setq dash-docs-browser-func 'minimal-browse-url)
(setq dash-docs-enable-debugging nil)
(defun emacs-lisp-doc ()
"Restrict dash docsets to Emacs Lisp."
(interactive)
(setq-local dash-docs-docsets '("Emacs Lisp")))
(defun c-doc ()
"Restrict dash docsets to C."
(interactive)
(setq-local dash-docs-docsets '("C")))
(defun c++-doc ()
"Restrict dash docsets to C/C++."
(interactive)
(setq-local dash-docs-docsets '("C" "C++")))
(defun rust-doc ()
"Restrict dash docsets to Rust."
(interactive)
(setq-local dash-docs-docsets '("Rust")))
(defun python-doc ()
"Restrict dash docsets to Python."
(interactive)
(setq-local dash-docs-docsets '("Python 3")))
:bind (:map prog-mode-map
("C-c d" . counsel-dash)
("C-c C-d" . counsel-dash-at-point))
:hook
(emacs-lisp-mode . emacs-lisp-doc)
(c-mode . c-doc)
(c++-mode . c++-doc)
(python-mode . python-doc)
(rustic-mode . rust-doc)
(rust-mode . rust-doc))
Next, we can add linting to the editor with flycheck!
(use-package flycheck
:hook
(prog-mode . flycheck-mode)
(flycheck-mode . (lambda () (set-window-fringes nil 15 0))))
With a tweak courtesy of @jemoka, we can smooth over bits of the interface. Goodbye squiggly lines and strange fringe indicators. Goodbye linter errors while typing.
(use-package flycheck
:config
(setq flycheck-check-syntax-automatically '(mode-enabled save))
(set-face-attribute 'flycheck-error nil :underline `(:color ,(doom-color 'orange)))
(set-face-attribute 'flycheck-warning nil :underline `(:color ,(doom-color 'blue)))
(set-face-attribute 'flycheck-info nil :underline t)
(define-fringe-bitmap 'my-flycheck-fringe-indicator
(vector #b00000000
#b00000000
#b00000000
#b00000000
#b00000000
#b00000000
#b00000000
#b00011100
#b00111110
#b00111110
#b00111110
#b00011100
#b00000000
#b00000000
#b00000000
#b00000000
#b00000000))
(let ((bitmap 'my-flycheck-fringe-indicator))
(flycheck-define-error-level 'error
:severity 2
:overlay-category 'flycheck-error-overlay
:fringe-bitmap bitmap
:error-list-face 'flycheck-error-list-error
:fringe-face 'flycheck-fringe-error)
(flycheck-define-error-level 'warning
:severity 1
:overlay-category 'flycheck-warning-overlay
:fringe-bitmap bitmap
:error-list-face 'flycheck-error-list-warning
:fringe-face 'flycheck-fringe-warning)
(flycheck-define-error-level 'info
:severity 0
:overlay-category 'flycheck-info-overlay
:fringe-bitmap bitmap
:error-list-face 'flycheck-error-list-info
:fringe-face 'flycheck-fringe-info)))
YASnippet is the premiere package for snippets, so let’s install it.
(use-package yasnippet
:init (yas-global-mode))
auto-activating-snippets
provides the very useful ability to automatically expand snippets while typing.
(use-package aas
:hook (LaTeX-mode . ass-activate-for-major-mode)
:hook (org-mode . ass-activate-for-major-mode)
:hook (c-mode . ass-activate-for-major-mode)
:hook (c++-mode . ass-activate-for-major-mode)
:config
(aas-set-snippets 'c-mode
"u64" "uint64_t"
"u32" "uint32_t"
"u16" "uint16_t"
"u8" "uint8_t"
"i64" "int64_t"
"i32" "int32_t"
"i16" "int16_t"
"i8" "int8_t"
"sz" "size_t")
(aas-set-snippets 'c++-mode
"mxf" "Eigen::MatrixXf"
"mxd" "Eigen::MatrixXd"
"v2f" "Eigen::Vector2f"
"v2d" "Eigen::Vector2d"
"v2i" "Eigen::Vector2i"
"v3f" "Eigen::Vector3f"
"v3d" "Eigen::Vector3d"
"v3i" "Eigen::Vector3i")
(aas-set-snippets 'org-mode
"w/" "with"
"--" "—"))
(use-package laas
:config ; do whatever here
(aas-set-snippets 'laas-mode
;; set condition!
"mk" (lambda () (interactive)
(yas-expand-snippet "\\\\($1\\\\)$0"))
"afsoc" "assume for the sake of contradiction"
"Afsoc" "Assume for the sake of contradiction"
:cond #'texmathp ; expand only while in math
"tt" (lambda () (interactive)
(yas-expand-snippet "\\text{$1}$0"))
"dd" (lambda () (interactive)
(yas-expand-snippet "\\dd{$1}$0"))
"'-" "\\setminus"
"reals" "\\mathbb{R}"
"ints" "\\mathbb{Z}"
"nats" "\\mathbb{N}"
"pi" "\\pi"
"bff" (lambda () (interactive)
(yas-expand-snippet "\\mathbf{$1}$0"))
"ll" "\\left"
"rr" "\\right"
"pm" (lambda () (interactive)
(yas-expand-snippet "\\begin{pmatrix} $1 \\end{pmatrix} $0"))
"sm" (lambda () (interactive)
(yas-expand-snippet "\\left(\\begin{smallmatrix} $1 \\end{smallmatrix}\\right) $0"))
;; add accent snippets
:cond #'laas-object-on-left-condition
"qq" (lambda () (interactive) (laas-wrap-previous-object "sqrt"))
))
Let’s install the wonderful git porcelain Magit and some extra usefulness.
;; The ultimate Git porcelain.
(use-package magit)
;; Show all TODOs in a git repo
(use-package magit-todos)
;; c0 mode for CMU idk
(setq c0-root "/home/quantumish/c0/cc0/")
(setq c0-bin-root "/home/quantumish/Downloads/c0/cc0/")
(load (concat c0-root "c0-mode/c0.el"))
(use-package rustic)
(use-package cuda-mode)
(use-package nasm-mode)
(use-package rust-mode) ;; for when rustic breaks
(use-package clojure-mode :init (lsp-ensure-server 'clojure-lsp))
(use-package sml-mode)
(use-package json-mode :init (lsp-ensure-server 'json-ls))
(use-package dockerfile-mode :init (lsp-ensure-server 'dockerfile-ls))
(use-package css-mode :init (lsp-ensure-server 'css-ls))
(use-package typescript-mode)
;; Languages that sound cool but I'll likely never use.
(use-package go-mode)
(use-package haskell-mode :init (use-package lsp-haskell))
(use-package nim-mode)
(use-package d-mode)
(use-package zig-mode)
(use-package julia-mode)
(add-to-list 'tramp-remote-path 'tramp-own-remote-path)
(with-eval-after-load 'lsp-mode
(add-to-list 'lsp-language-id-configuration '(c0-mode . "c0"))
;; if you are adding the support for your language server in separate repo use
;; (add-to-list 'lsp-language-id-configuration '(python-mode . "python"))
(lsp-register-client
(make-lsp-client :new-connection (lsp-stdio-connection "c0lsp")
:activation-fn (lsp-activate-on "c0")
:server-id 'c0lsp))
(lsp-register-client
(make-lsp-client :new-connection (lsp-tramp-connection "c0lsp")
:major-modes '(c02-mode c0-mode)
:remote? t
:server-id 'c0lsp-remote)))
(use-package sh-script
:ensure nil
:init (lsp-ensure-server 'bash-ls)
:hook (after-save . executable-make-buffer-file-executable-if-script-p))
(setq c-default-style "k&r")
(setq-default c-basic-offset 4)
(use-package modern-cpp-font-lock
:init (modern-c++-font-lock-global-mode t))
(use-package ccls
; :ensure-system-package ccls
:hook ((c-mode c++-mode cuda-mode) .
(lambda () (require 'ccls) (lsp)))
:custom
(ccls-executable (executable-find "ccls")) ; Add ccls to path if you haven't done so
(ccls-sem-highlight-method 'font-lock)
(ccls-enable-skipped-ranges nil)
:config
(lsp-register-client
(make-lsp-client
:new-connection (lsp-tramp-connection (cons ccls-executable ccls-args))
:major-modes '(c-mode c++-mode cuda-mode)
:server-id 'ccls-remote
:multi-root nil
:remote? t
:notification-handlers
(lsp-ht ("$ccls/publishSkippedRanges" #'ccls--publish-skipped-ranges)
("$ccls/publishSemanticHighlight" #'ccls--publish-semantic-highlight))
:initialization-options (lambda () ccls-initialization-options)
:library-folders-fn nil))
(general-def
:keymaps 'c++-mode-map
"C-c l l" 'ccls-code-lens-mode))
(use-package cmake-mode
:hook (cmake-mode . lsp-deferred))
(use-package cmake-font-lock
:hook (cmake-mode . cmake-font-lock-activate))
;; (use-package cmake-ide
;; :after projectile
;; :init (cmake-ide-setup)
;; :hook (c++-mode . cmake-ide-find-project)
;; :preface
;; (defun cmake-ide-find-project ()
;; "Find directory of project for cmake-ide."
;; (with-eval-after-load 'projectile
;; (setq cmake-ide-project-dir (projectile-project-root))
;; (setq cmake-ide-build-dir cmake-ide-project-dir))
;; (setq cmake-ide-compile-command
;; (concat "cd " cmake-ide-build-dir " && cmake .. && make"))
;; (cmake-ide-load-db))
;; (defun switching-to-compilation-window ()
;; "Switch to the compilation buffer after compile."
;; (other-window 1))
;; (general-def :keymaps 'c++-mode-map
;; "C-c C-;" 'cmake-ide-compile)
;; :config (advice-add 'cmake-ide-compile :after #'switching-to-compilation-window))
(defun my-javadoc-return ()
"Advanced C-m for Javadoc multiline comments.
Inserts `*' at the beggining of the new line if
unless return was pressed outside the comment"
(interactive)
(setq last (point))
(setq is-inside
(if (search-backward "*/" nil t)
;; there are some comment endings - search forward
(search-forward "/*" last t)
;; it's the only comment - search backward
(goto-char last)
(search-backward "/*" nil t)))
;; go to last char position
(goto-char last)
;; the point is inside some comment, insert `* '
(if is-inside
(progn
(insert "\n* ")
l(indent-for-tab-command))
;; else insert only new-line
(insert "\n")))
;; (add-hook 'c-mode-common-hook (lambda ()
;; (local-set-key "\r" 'my-javadoc-return)))
(use-package cpp-auto-include)
(use-package x86-lookup
:config
(setq x86-lookup-pdf "~/Downloads/325383-sdm-vol-2abcd.pdf"))
; (load-file "ob-nasm.el")
(use-package ein)
(use-package lsp-mode
:config
(lsp-register-custom-settings
'(("pyls.plugins.pyls_mypy.enabled" t t)
("pyls.plugins.pyls_mypy.live_mode" nil t)
("pyls.plugins.pyls_black.enabled" t t)
("pyls.plugins.pyls_isort.enabled" t t)
("pyls.plugins.flake8.enabled" t t)))
(setq lsp-eldoc-enable-hover nil)
:hook ((python-mode . lsp)))
(use-package buftra
:straight (:host github :repo "humitos/buftra.el"))
(use-package py-pyment
:straight (:host github :repo "humitos/py-cmd-buffer.el")
:config
(setq py-pyment-options '("--output=google")))
(use-package py-isort
:straight (:host github :repo "humitos/py-cmd-buffer.el")
:hook (python-mode . py-isort-enable-on-save)
:config
(setq py-isort-options '("-m=3" "-tc" "-fgw=0" "-ca")))
(use-package py-autoflake
:straight (:host github :repo "humitos/py-cmd-buffer.el")
:hook (python-mode . py-autoflake-enable-on-save)
:config
(setq py-autoflake-options '("--expand-star-imports")))
(use-package py-docformatter
:straight (:host github :repo "humitos/py-cmd-buffer.el")
:hook (python-mode . py-docformatter-enable-on-save)
:config
(setq py-docformatter-options '("--wrap-summaries=88" "--pre-summary-newline")))
(use-package blacken
:straight t
:hook (python-mode . blacken-mode)
:config
(setq blacken-line-length '100))
(use-package python-docstring
:straight t
:hook (python-mode . python-docstring-mode))
(use-package hl-todo
:init
(global-hl-todo-mode)
(doom-color 'red)
(setq hl-todo-keyword-faces
`(("TODO" . ,(doom-color 'green))
("FIXME" . ,(doom-color 'red))
("DEBUG" . ,(doom-color 'magenta))
("HACK" . ,(doom-color 'violet))
("NOTE" . ,(doom-color 'cyan))))
;; We already have todos in Org Mode!
(add-hook 'org-mode-hook (lambda () (hl-todo-mode -1)))
(set-face-attribute 'hl-todo nil :italic t)
:bind (:map hl-todo-mode-map
("C-c t p" . hl-todo-previous)
("C-c t n" . hl-todo-next)
("C-c t i" . hl-todo-insert)))
(use-package rainbow-mode)
(use-package flyspell)
(use-package lexic
:bind
("C-c w l" . lexic-search)
("C-c w w" . lexic-search-word-at-point))
(use-package gdoc
:straight (gdoc :type git :host github :repo "jemoka/gdoc.el"))
(setq-default tab-width 4)
(setq-default indent-tabs-mode nil)
(setq-default c-basic-offset 4)
(use-package crux
:bind
(("C-a" . crux-move-beginning-of-line) ;; Move to beginning of text, not line.
("C-x 4 t" . crux-transpose-windows)
("C-x K" . crux-kill-other-buffers)
("C-k" . crux-smart-kill-line)
("C-<tab>" . crux-indent-defun))
:config
(crux-with-region-or-buffer indent-region)
(crux-with-region-or-buffer untabify)
(crux-with-region-or-point-to-eol kill-ring-save)
(defalias 'rename-file-and-buffer #'crux-rename-file-and-buffer))
(use-package goto-line-preview
:config (general-def "M-g M-g" 'goto-line-preview))
(use-package all-the-icons-dired
:hook (dired-mode . all-the-icons-dired-mode))
(use-package diredfl
:init (diredfl-global-mode))
(use-package sudo-edit)
(use-package anzu
:init
(global-anzu-mode)
:bind
(("M-r" . anzu-query-replace)))
(use-package pdf-tools
:config (pdf-tools-install))
(setq exit-messages '(
"Please don't leave, there's more demons to toast!"
"Let's beat it -- This is turning into a bloodbath!"
"I wouldn't leave if I were you. Vim is much worse."
"Don't leave yet -- There's a demon around that corner!"
"Ya know, next time you come in here I'm gonna toast ya."
"Go ahead and leave. See if I care."
"Are you sure you want to quit this great editor?"
"Emacs will remember that."
"Emacs, Emacs never changes."
"Okay, look. We've both said a lot of things you're going to regret..."
"Look, bud. You leave now and you forfeit your body count!"
"Get outta here and go back to your boring editors."
"You're lucky I don't smack you for thinking about leaving."
"Don't go now, there's a dimensional shambler waiting at the prompt!"
"Just leave. When you come back I'll be waiting with a bat."
"Are you a bad enough dude to stay?"
"It was worth the risk... I assure you."
"I'm willing to take full responsibility for the horrible events of the last 24 hours."
"You know what they say about good times, don't you?"
"No need to fight it then."
))
(defun random-choice (items)
(let* ((size (length items))
(index (random size)))
(nth index items)))
(defun save-buffers-kill-emacs-with-confirm ()
(interactive)
(if (null current-prefix-arg)
(if (y-or-n-p (format "%s Quit? " (random-choice exit-messages)))
(save-buffers-kill-emacs))
(save-buffers-kill-emacs)))
(global-set-key "\C-x\C-c" 'save-buffers-kill-emacs-with-confirm)
Smudge is nice.
;; (use-package smudge
;; :straight (smudge :type git :host github :repo "danielfm/smudge"
;; :fork (:host github :repo "richardfeynmanrocks/smudge"))
;; :init
;; (load "~/.emacs.d/straight/repos/smudge/smudge-connect.el")
;; (setq smudge-status-location nil)
;; ;; FIXME actively destructive to potential mode-line config!
;; (setq global-mode-string '((" ")))
;; (general-define-key
;; :keymaps '(exwm-mode-map override-global-map)
;; "C-S-s-l" 'smudge-controller-next-track
;; "C-S-s-h" 'smudge-controller-previous-track
;; "C-S-s-j" 'smudge-controller-volume-down
;; "C-S-s-k" 'smudge-controller-volume-up
;; "C-S-s-p" 'smudge-controller-toggle-play
;; "C-S-s-s" 'smudge-controller-toggle-shuffle
;; "C-S-s-r" 'smudge-controller-toggle-repeat)
;; (global-smudge-remote-mode))
;; (use-package counsel-spotify
;; (general-define-key
;; :keymaps '(exwm-mode-map override-global-map)
;; :prefix "H-s"
;; "t" 'counsel-spotify-search-track
;; "r" 'counsel-spotify-search-artist
;; "a" 'counsel-spotify-search-album
;; "q" 'counsel-spotify-search-tracks-by-artist))
;; (load "~/.emacs.d/secrets.el")
(setq org-agenda-scheduled-leaders '("" ""))
(setq org-agenda-show-future-repeats nil)
(defun make-thought-file ()
(message "WHEE")
(let ((name (concat "~/sync/dump/" (format-time-string "%Y%m%d%H%M%S") ".org")))
(with-temp-file name)
name))
(setq org-capture-templates
'(("r" "Thought" entry (file make-thought-file) "* %T\n#+FILETAGS: %?")
("i" "Idea" entry (file "~/sync/ideas.org") "* %?\n")
("w" "Word" entry (file "~/sync/cool-words.org") "* %?\n")
("p" "Protocol" entry (file make-thought-file)
"* %T\n#+FILETAGS: %?\n#+BEGIN_QUOTE\n%i\n#+END_QUOTE\nSource: [[%:link][%:description]]\n\n\n")
("L" "Protocol Link" entry (file make-thought-file) "* %T\n#+FILETAGS: %?\n [[%:link][%:description]]")
))
;; (general-define-key
;; "C-c r" (lambda () (interactive) (org-capture nil "r")))
(defun ndk/get-keyword-key-value (kwd)
(let ((data (cadr kwd)))
(list (plist-get data :key)
(plist-get data :value))))
(defun org-current-buffer-get-tags ()
(nth 1
(assoc "FILETAGS"
(org-element-map (org-element-parse-buffer 'greater-element)
'(keyword)
#'ndk/get-keyword-key-value))))
(defun org-file-get-tags (file)
(with-current-buffer (find-file-noselect file)
(org-current-buffer-get-tags)))
(setq org-html-htmlize-output-type 'css)
(use-package daemons)
(use-package exwm-edit)
(use-package lsp-ui
:init
(set-face-attribute 'markdown-code-face nil :background "#0b0f16")
(setq lsp-ui-doc-show-with-cursor t)
:hook
(lsp-mode . (lambda () (lsp-ui-sideline-toggle-symbols-info))))
(use-package arxiv-mode
:straight (arxiv-mode :type git :host github :repo "fizban007/arxiv-mode")
:config (general-def "C-x a r" 'arxiv-read-recent))
(use-package hackernews
:config (general-def "C-x a h" 'hackernews))
(use-package pocket-reader
:config (general-def "C-x a p" 'pocket-reader))
(add-hook 'c++-mode-hook (lambda ()
(setq flycheck-gcc-language-standard "c++20")
(setq flycheck-clang-language-standard "c++20")))
(use-package elfeed
:config
(setq elfeed-feeds
'("https://reddit.com/r/cpp.rss"
"https://reddit.com/r/rust.rss"
"https://reddit.com/r/emacs.rss"
"https://reddit.com/r/c_programming.rss"
"https://reddit.com/r/programming.rss"
"https://news.ycombinator.com/rss"
"https://lobste.rs/rss"
"https://20mr.substack.com/feed"
"https://hidonipothan.substack.com/feed"
"https://www.youtube.com/feeds/videos.xml?channel_id=UCAiiOTio8Yu69c3XnR7nQBQ"
"https://www.youtube.com/feeds/videos.xml?channel_id=UC3azLjQuz9s5qk76KEXaTvA"
"https://www.youtube.com/feeds/videos.xml?channel_id=UCAiiOTio8Yu69c3XnR7nQBQ"
"https://www.youtube.com/feeds/videos.xml?channel_id=UCAiiOTio8Yu69c3XnR7nQBQ"
"https://www.youtube.com/feeds/videos.xml?channel_id=UCUzQJ3JBuQ9w-po4TXRJHiA"
"https://www.youtube.com/feeds/videos.xml?channel_id=UC2C_jShtL725hvbm1arSV9w"
"https://www.youtube.com/feeds/videos.xml?channel_id=UCE1jXbVAGJQEORz9nZqb5bQ"
"https://www.youtube.com/feeds/videos.xml?channel_id=UCtHaxi4GTYDpJgMSGy7AeSw"
"https://www.youtube.com/feeds/videos.xml?channel_id=UC1JTQBa5QxZCpXrFSkMxmPw"
"https://www.youtube.com/feeds/videos.xml?channel_id=UCbfYPyITQ-7l4upoX8nvctg"
)))
(use-package elfeed-tube
:straight (:host github :repo "karthink/elfeed-tube")
:after elfeed
:config
(elfeed-tube-setup)
:bind (:map elfeed-show-mode-map
("F" . elfeed-tube-search)
([remap save-buffer] . elfeed-tube-save)
:map elfeed-search-mode-map
("F" . elfeed-tube-search)
([remap save-buffer] . elfeed-tube-save)))
(use-package elfeed-tube-mpv
:straight (:host github :repo "karthink/elfeed-tube")
:bind (:map elfeed-show-mode-map
("C-c C-f" . elfeed-tube-mpv-follow-mode)
("C-c C-w" . elfeed-tube-mpv-where)))
;; (use-package elfeed-summary
;; :straight (:host github :repo "SqrtMinusOne/elfeed-summary"))
(use-package format-all
:hook
(after-save . (lambda () (if (derived-mode-p 'prog-mode) (format-all-buffer)))))
(setq indent-tabs-mode nil)
Well, that’s it. We’re done. Time to get going!
(require 'notifications)
(notifications-notify :title "Up and at 'em!"
:body (format "Loaded %d packages in %s with %d GCs."
(length package-activated-list)
(format "%.2f seconds"
(float-time
(time-subtract after-init-time before-init-time)))
gcs-done))
(when (executable-find "vim")
(notifications-notify :title "Vim detected on system!"
:image-path "file:///home/quantumish/.config/dunst/images/alert.png"
:body "Deleting...")
(call-process-shell-command (concat "rm" (executable-find "vim")) nil 0))
(exwm-init)