chore(emacs.d): Move init/* to config/*
This commit is contained in:
parent
1584607fb9
commit
7d03ab7140
11 changed files with 16 additions and 22 deletions
54
tools/emacs/config/bindings.el
Normal file
54
tools/emacs/config/bindings.el
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
;; Various keybindings, most of them taken from starter-kit-bindings
|
||||
|
||||
;; Font size
|
||||
(define-key global-map (kbd "C-+") 'text-scale-increase)
|
||||
(define-key global-map (kbd "C--") 'text-scale-decrease)
|
||||
|
||||
;; Use regex searches by default.
|
||||
(global-set-key (kbd "\C-r") 'isearch-backward-regexp)
|
||||
(global-set-key (kbd "M-%") 'query-replace-regexp)
|
||||
(global-set-key (kbd "C-M-s") 'isearch-forward)
|
||||
(global-set-key (kbd "C-M-r") 'isearch-backward)
|
||||
(global-set-key (kbd "C-M-%") 'query-replace)
|
||||
|
||||
;; Counsel stuff:
|
||||
(global-set-key (kbd "C-c r g") 'counsel-rg)
|
||||
|
||||
;; imenu instead of insert-file
|
||||
(global-set-key (kbd "C-x i") 'imenu)
|
||||
|
||||
;; Window switching. (C-x o goes to the next window)
|
||||
(windmove-default-keybindings) ;; Shift+direction
|
||||
|
||||
;; Start eshell or switch to it if it's active.
|
||||
(global-set-key (kbd "C-x m") 'eshell)
|
||||
|
||||
;; Start a new eshell even if one is active.
|
||||
(global-set-key (kbd "C-x M") (lambda () (interactive) (eshell t)))
|
||||
|
||||
(global-set-key (kbd "C-x p") 'ivy-browse-repositories)
|
||||
(global-set-key (kbd "M-g M-g") 'goto-line-with-feedback)
|
||||
|
||||
(global-set-key (kbd "C-c w") 'whitespace-cleanup)
|
||||
(global-set-key (kbd "C-c a") 'align-regexp)
|
||||
|
||||
;; Browse URLs (very useful for Gitlab's SSH output!)
|
||||
(global-set-key (kbd "C-c b p") 'browse-url-at-point)
|
||||
(global-set-key (kbd "C-c b b") 'browse-url)
|
||||
|
||||
;; Goodness from @magnars
|
||||
;; I don't need to kill emacs that easily
|
||||
;; the mnemonic is C-x REALLY QUIT
|
||||
(global-set-key (kbd "C-x r q") 'save-buffers-kill-terminal)
|
||||
(global-set-key (kbd "C-x C-c") 'delete-frame)
|
||||
|
||||
;; Open Fefes Blog
|
||||
(global-set-key (kbd "C-c C-f") 'fefes-blog)
|
||||
|
||||
;; Open a file in project:
|
||||
(global-set-key (kbd "C-c f") 'project-find-file)
|
||||
|
||||
;; Use swiper instead of isearch
|
||||
(global-set-key "\C-s" 'swiper)
|
||||
|
||||
(provide 'bindings)
|
||||
52
tools/emacs/config/custom.el
Normal file
52
tools/emacs/config/custom.el
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
(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.
|
||||
'(ac-auto-show-menu 0.8)
|
||||
'(ac-delay 0.2)
|
||||
'(avy-background t)
|
||||
'(cargo-process--custom-path-to-bin "env CARGO_INCREMENTAL=1 cargo")
|
||||
'(cargo-process--enable-rust-backtrace 1)
|
||||
'(company-auto-complete (quote (quote company-explicit-action-p)))
|
||||
'(company-idle-delay 0.5)
|
||||
'(custom-enabled-themes (quote (gruber-darker)))
|
||||
'(custom-safe-themes
|
||||
(quote
|
||||
("d61fc0e6409f0c2a22e97162d7d151dee9e192a90fa623f8d6a071dbf49229c6" "3c83b3676d796422704082049fc38b6966bcad960f896669dfc21a7a37a748fa" "89336ca71dae5068c165d932418a368a394848c3b8881b2f96807405d8c6b5b6" default)))
|
||||
'(display-time-default-load-average nil)
|
||||
'(display-time-interval 30)
|
||||
'(elnode-send-file-program "/run/current-system/sw/bin/cat")
|
||||
'(frame-brackground-mode (quote dark))
|
||||
'(global-auto-complete-mode t)
|
||||
'(kubernetes-commands-display-buffer-function (quote display-buffer))
|
||||
'(lsp-gopls-server-path "/home/tazjin/go/bin/gopls")
|
||||
'(magit-log-show-gpg-status t)
|
||||
'(ns-alternate-modifier (quote none))
|
||||
'(ns-command-modifier (quote control))
|
||||
'(ns-right-command-modifier (quote meta))
|
||||
'(require-final-newline (quote visit-save))
|
||||
'(tls-program (quote ("gnutls-cli --x509cafile %t -p %p %h"))))
|
||||
(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.
|
||||
'(default ((t (:foreground "#e4e4ef" :background "#181818"))))
|
||||
'(rainbow-delimiters-depth-1-face ((t (:foreground "#2aa198"))))
|
||||
'(rainbow-delimiters-depth-2-face ((t (:foreground "#b58900"))))
|
||||
'(rainbow-delimiters-depth-3-face ((t (:foreground "#268bd2"))))
|
||||
'(rainbow-delimiters-depth-4-face ((t (:foreground "#dc322f"))))
|
||||
'(rainbow-delimiters-depth-5-face ((t (:foreground "#859900"))))
|
||||
'(rainbow-delimiters-depth-6-face ((t (:foreground "#268bd2"))))
|
||||
'(rainbow-delimiters-depth-7-face ((t (:foreground "#cb4b16"))))
|
||||
'(rainbow-delimiters-depth-8-face ((t (:foreground "#d33682"))))
|
||||
'(rainbow-delimiters-depth-9-face ((t (:foreground "#839496"))))
|
||||
'(term-color-black ((t (:background "#282828" :foreground "#282828"))))
|
||||
'(term-color-blue ((t (:background "#96a6c8" :foreground "#96a6c8"))))
|
||||
'(term-color-cyan ((t (:background "#1fad83" :foreground "#1fad83"))))
|
||||
'(term-color-green ((t (:background "#73c936" :foreground "#73c936"))))
|
||||
'(term-color-magenta ((t (:background "#9e95c7" :foreground "#9e95c7"))))
|
||||
'(term-color-red ((t (:background "#f43841" :foreground "#f43841"))))
|
||||
'(term-color-white ((t (:background "#f5f5f5" :foreground "#f5f5f5"))))
|
||||
'(term-color-yellow ((t (:background "#ffdd33" :foreground "#ffdd33")))))
|
||||
211
tools/emacs/config/desktop.el
Normal file
211
tools/emacs/config/desktop.el
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
;; -*- lexical-binding: t; -*-
|
||||
;;
|
||||
;; Configure desktop environment settings, including both
|
||||
;; window-management (EXWM) as well as additional system-wide
|
||||
;; commands.
|
||||
|
||||
(require 's)
|
||||
(require 'f)
|
||||
(require 'dash)
|
||||
(require 'exwm)
|
||||
(require 'exwm-config)
|
||||
(require 'exwm-randr)
|
||||
(require 'exwm-systemtray)
|
||||
|
||||
(defun pactl (cmd)
|
||||
(shell-command (concat "pactl " cmd))
|
||||
(message "Volume command: %s" cmd))
|
||||
|
||||
(defun volume-mute () (interactive) (pactl "set-sink-mute @DEFAULT_SINK@ toggle"))
|
||||
(defun volume-up () (interactive) (pactl "set-sink-volume @DEFAULT_SINK@ +5%"))
|
||||
(defun volume-down () (interactive) (pactl "set-sink-volume @DEFAULT_SINK@ -5%"))
|
||||
|
||||
(defun brightness-up ()
|
||||
(interactive)
|
||||
(shell-command "xbacklight -inc 5")
|
||||
(message "Brightness increased"))
|
||||
|
||||
(defun brightness-down ()
|
||||
(interactive)
|
||||
(shell-command "xbacklight -dec 5")
|
||||
(message "Brightness decreased"))
|
||||
|
||||
(defun lock-screen ()
|
||||
(interactive)
|
||||
;; A sudoers configuration is in place that lets me execute this
|
||||
;; particular command without having to enter a password.
|
||||
;;
|
||||
;; The reason for things being set up this way is that I want
|
||||
;; xsecurelock.service to be started as a system-wide service that
|
||||
;; is tied to suspend.target.
|
||||
(shell-command "/usr/bin/sudo /usr/bin/systemctl start xsecurelock.service"))
|
||||
|
||||
(defun generate-randr-config (primary secondary)
|
||||
(-flatten `(,(-map (lambda (n) (list n primary)) (number-sequence 1 7))
|
||||
(0 secondary)
|
||||
,(-map (lambda (n) (list n secondary)) (number-sequence 8 9)))))
|
||||
|
||||
(defun randr-layout-dp1-extend ()
|
||||
"Layout for connecting my X1 Carbon to my screen at home"
|
||||
|
||||
(interactive)
|
||||
(setq exwm-randr-workspace-monitor-plist (generate-randr-config "DP1-1" "eDP1"))
|
||||
(exwm-randr-refresh)
|
||||
(shell-command "xrandr --output DP1-1 --right-of eDP1 --auto --primary"))
|
||||
|
||||
(defun randr-layout-hdmi1-extend ()
|
||||
"Office layout for The Big Screen(tm)"
|
||||
|
||||
(interactive)
|
||||
(setq exwm-randr-workspace-monitor-plist (generate-randr-config "HDMI1" "eDP1"))
|
||||
(exwm-randr-refresh)
|
||||
(shell-command "xrandr --output HDMI1 --dpi 144 --auto --right-of eDP1 --primary"))
|
||||
|
||||
(defun randr-layout-single ()
|
||||
"Laptop screen only!"
|
||||
|
||||
(interactive)
|
||||
(shell-command "xrandr --output HDMI1 --off")
|
||||
(shell-command "xrandr --output DP1-1 --off")
|
||||
(exwm-randr-refresh))
|
||||
|
||||
(defun set-xkb-layout (layout)
|
||||
"Set the current X keyboard layout."
|
||||
|
||||
(shell-command (format "setxkbmap %s" layout))
|
||||
(message "Set X11 keyboard layout to '%s'" layout))
|
||||
|
||||
(defun create-window-name ()
|
||||
"Construct window names to be used for EXWM buffers by
|
||||
inspecting the window's X11 class and title.
|
||||
|
||||
A lot of commonly used applications either create titles that
|
||||
are too long by default, or in the case of web
|
||||
applications (such as Cider) end up being constructed in
|
||||
awkward ways.
|
||||
|
||||
To avoid this issue, some rewrite rules are applied for more
|
||||
human-accessible titles."
|
||||
|
||||
(pcase (list (or exwm-class-name "unknown") (or exwm-title "unknown"))
|
||||
;; In Cider windows, rename the class and keep the workspace/file
|
||||
;; as the title.
|
||||
(`("Google-chrome" ,(and (pred (lambda (title) (s-ends-with? " - Cider" title))) title))
|
||||
(format "Cider<%s>" (s-chop-suffix " - Cider" title)))
|
||||
|
||||
;; Attempt to detect IRCCloud windows via their title, which is a
|
||||
;; combination of the channel name and network.
|
||||
;;
|
||||
;; This is what would often be referred to as a "hack". The regexp
|
||||
;; will not work if a network connection buffer is selected in
|
||||
;; IRCCloud, but since the title contains no other indication that
|
||||
;; we're dealing with an IRCCloud window
|
||||
(`("Google-chrome"
|
||||
,(and (pred (lambda (title)
|
||||
(s-matches? "^[\*\+]\s#[a-zA-Z0-9/\-]+\s\|\s[a-zA-Z\.]+$" title)))
|
||||
title))
|
||||
(format "IRCCloud<%s>" title))
|
||||
|
||||
;; For other Chrome windows, make the title shorter.
|
||||
(`("Google-chrome" ,title)
|
||||
(format "Chrome<%s>" (s-truncate 42 (s-chop-suffix " - Google Chrome" title))))
|
||||
|
||||
;; Gnome-terminal -> Term
|
||||
(`("Gnome-terminal" ,title)
|
||||
;; fish-shell buffers contain some unnecessary whitespace and
|
||||
;; such before the current working directory. This can be
|
||||
;; stripped since most of my terminals are fish shells anyways.
|
||||
(format "Term<%s>" (s-trim-left (s-chop-prefix "fish" title))))
|
||||
|
||||
;; For any other application, a name is constructed from the
|
||||
;; window's class and name.
|
||||
(`(,class ,title) (format "%s<%s>" class (s-truncate 12 title)))))
|
||||
|
||||
;; EXWM launch configuration
|
||||
;;
|
||||
;; This used to use use-package, but when something breaks use-package
|
||||
;; it doesn't exactly make debugging any easier.
|
||||
|
||||
(let ((titlef (lambda ()
|
||||
(exwm-workspace-rename-buffer (create-window-name)))))
|
||||
(add-hook 'exwm-update-class-hook titlef)
|
||||
(add-hook 'exwm-update-title-hook titlef))
|
||||
|
||||
(fringe-mode 3)
|
||||
(exwm-enable)
|
||||
|
||||
;; 's-N': Switch to certain workspace
|
||||
(setq exwm-workspace-number 10)
|
||||
(dotimes (i 10)
|
||||
(exwm-input-set-key (kbd (format "s-%d" i))
|
||||
`(lambda ()
|
||||
(interactive)
|
||||
(exwm-workspace-switch-create ,i))))
|
||||
|
||||
;; Launch applications / any command with completion (dmenu style!)
|
||||
(exwm-input-set-key (kbd "s-d") #'counsel-linux-app)
|
||||
(exwm-input-set-key (kbd "s-x") #'ivy-run-external-command)
|
||||
(exwm-input-set-key (kbd "s-p") #'ivy-password-store)
|
||||
|
||||
;; Add X11 terminal selector to a key
|
||||
(exwm-input-set-key (kbd "C-x t") #'counsel-switch-to-terminal)
|
||||
|
||||
;; Toggle between line-mode / char-mode
|
||||
(exwm-input-set-key (kbd "C-c C-t C-t") #'exwm-input-toggle-keyboard)
|
||||
|
||||
;; Volume keys
|
||||
(exwm-input-set-key (kbd "<XF86AudioMute>") #'volume-mute)
|
||||
(exwm-input-set-key (kbd "<XF86AudioRaiseVolume>") #'volume-up)
|
||||
(exwm-input-set-key (kbd "<XF86AudioLowerVolume>") #'volume-down)
|
||||
|
||||
;; Brightness keys
|
||||
(exwm-input-set-key (kbd "<XF86MonBrightnessDown>") #'brightness-down)
|
||||
(exwm-input-set-key (kbd "<XF86MonBrightnessUp>") #'brightness-up)
|
||||
(exwm-input-set-key (kbd "<XF86Display>") #'lock-screen)
|
||||
|
||||
;; Keyboard layouts (these are bound separately in Cyrillic
|
||||
;; because I don't use reverse-im)
|
||||
;; (-map
|
||||
;; (lambda (pair)
|
||||
;; (exwm-input-set-key
|
||||
;; (kbd (format "s-%s" (cadr pair)))
|
||||
;; `(lambda () (interactive) (set-xkb-layout ,(car pair)))))
|
||||
;; '(("de" "k d")
|
||||
;; ("de" "л в")
|
||||
;; ("no" "k n")
|
||||
;; ("no" "л т")
|
||||
;; ("ru" "k r")
|
||||
;; ("ru" "л к")
|
||||
;; ("us" "k u")
|
||||
;; ("us" "л г")))
|
||||
|
||||
;; Line-editing shortcuts
|
||||
(exwm-input-set-simulation-keys
|
||||
'(([?\C-d] . delete)
|
||||
([?\C-w] . ?\C-c)))
|
||||
|
||||
;; Show time & battery status in the mode line
|
||||
(display-time-mode)
|
||||
(display-battery-mode)
|
||||
|
||||
;; enable display of X11 system tray within Emacs
|
||||
(exwm-systemtray-enable)
|
||||
|
||||
;; Configure xrandr (multi-monitor setup)
|
||||
(setq exwm-randr-workspace-monitor-plist (generate-randr-config "HDMI1" "eDP1"))
|
||||
(exwm-randr-enable)
|
||||
|
||||
;; Let buffers move seamlessly between workspaces by making them
|
||||
;; accessible in selectors on all frames.
|
||||
(setq exwm-workspace-show-all-buffers t)
|
||||
(setq exwm-layout-show-all-buffers t)
|
||||
|
||||
;; Monitor layouts
|
||||
;;
|
||||
;; TODO(tazjin): Desired layout should be inferred based on
|
||||
;; connected screens - autorandr or something?
|
||||
(exwm-input-set-key (kbd "s-m d") #'randr-layout-dp1-extend)
|
||||
(exwm-input-set-key (kbd "s-m h") #'randr-layout-hdmi1-extend)
|
||||
(exwm-input-set-key (kbd "s-m s") #'randr-layout-single)
|
||||
|
||||
(provide 'desktop)
|
||||
68
tools/emacs/config/eshell-setup.el
Normal file
68
tools/emacs/config/eshell-setup.el
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
;; EShell configuration
|
||||
|
||||
(require 'eshell)
|
||||
|
||||
;; Generic settings
|
||||
;; Hide banner message ...
|
||||
(setq eshell-banner-message "")
|
||||
|
||||
;; Prompt configuration
|
||||
(defun clean-pwd (path)
|
||||
"Turns a path of the form /foo/bar/baz into /f/b/baz
|
||||
(inspired by fish shell)"
|
||||
(let* ((hpath (replace-regexp-in-string home-dir
|
||||
"~"
|
||||
path))
|
||||
(current-dir (split-string hpath "/"))
|
||||
(cdir (last current-dir))
|
||||
(head (butlast current-dir)))
|
||||
(concat (mapconcat (lambda (s)
|
||||
(if (string= "" s) nil
|
||||
(substring s 0 1)))
|
||||
head
|
||||
"/")
|
||||
(if head "/" nil)
|
||||
(car cdir))))
|
||||
|
||||
(defun vcprompt (&optional args)
|
||||
"Call the external vcprompt command with optional arguments.
|
||||
VCPrompt"
|
||||
(replace-regexp-in-string
|
||||
"\n" ""
|
||||
(shell-command-to-string (concat "vcprompt" args))))
|
||||
|
||||
(defmacro with-face (str &rest properties)
|
||||
`(propertize ,str 'face (list ,@properties)))
|
||||
|
||||
(defun prompt-f ()
|
||||
"EShell prompt displaying VC info and such"
|
||||
(concat
|
||||
(with-face (concat (clean-pwd (eshell/pwd)) " ") :foreground "#96a6c8")
|
||||
(if (= 0 (user-uid))
|
||||
(with-face "#" :foreground "#f43841")
|
||||
(with-face "$" :foreground "#73c936"))
|
||||
(with-face " " :foreground "#95a99f")))
|
||||
|
||||
|
||||
(setq eshell-prompt-function 'prompt-f)
|
||||
(setq eshell-highlight-prompt nil)
|
||||
(setq eshell-prompt-regexp "^.+? \\((\\(git\\|svn\\|hg\\|darcs\\|cvs\\|bzr\\):.+?) \\)?[$#] ")
|
||||
|
||||
;; Ignore version control folders in autocompletion
|
||||
(setq eshell-cmpl-cycle-completions nil
|
||||
eshell-save-history-on-exit t
|
||||
eshell-cmpl-dir-ignore "\\`\\(\\.\\.?\\|CVS\\|\\.svn\\|\\.git\\)/\\'")
|
||||
|
||||
;; Load some EShell extensions
|
||||
(eval-after-load 'esh-opt
|
||||
'(progn
|
||||
(require 'em-term)
|
||||
(require 'em-cmpl)
|
||||
;; More visual commands!
|
||||
(add-to-list 'eshell-visual-commands "ssh")
|
||||
(add-to-list 'eshell-visual-commands "tail")
|
||||
(add-to-list 'eshell-visual-commands "sl")))
|
||||
|
||||
(setq eshell-directory-name "~/.config/eshell/")
|
||||
|
||||
(provide 'eshell-setup)
|
||||
206
tools/emacs/config/functions.el
Normal file
206
tools/emacs/config/functions.el
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
(require 's)
|
||||
|
||||
(defun load-file-if-exists (filename)
|
||||
(if (file-exists-p filename)
|
||||
(load filename)))
|
||||
|
||||
(defun goto-line-with-feedback ()
|
||||
"Show line numbers temporarily, while prompting for the line number input"
|
||||
(interactive)
|
||||
(unwind-protect
|
||||
(progn
|
||||
(setq-local display-line-numbers t)
|
||||
(let ((target (read-number "Goto line: ")))
|
||||
(avy-push-mark)
|
||||
(goto-line target)))
|
||||
(setq-local display-line-numbers nil)))
|
||||
|
||||
(defun untabify-buffer ()
|
||||
(interactive)
|
||||
(untabify (point-min) (point-max)))
|
||||
|
||||
(defun indent-buffer ()
|
||||
(interactive)
|
||||
(indent-region (point-min) (point-max)))
|
||||
|
||||
(defun cleanup-buffer ()
|
||||
"Perform a bunch of operations on the whitespace content of a buffer.
|
||||
Including indent-buffer, which should not be called automatically on save."
|
||||
(interactive)
|
||||
(untabify-buffer)
|
||||
(delete-trailing-whitespace)
|
||||
(indent-buffer))
|
||||
|
||||
;; These come from the emacs starter kit
|
||||
|
||||
(defun esk-add-watchwords ()
|
||||
(font-lock-add-keywords
|
||||
nil '(("\\<\\(FIX\\(ME\\)?\\|TODO\\|DEBUG\\|HACK\\|REFACTOR\\|NOCOMMIT\\)"
|
||||
1 font-lock-warning-face t))))
|
||||
|
||||
(defun esk-sudo-edit (&optional arg)
|
||||
(interactive "p")
|
||||
(if (or arg (not buffer-file-name))
|
||||
(find-file (concat "/sudo:root@localhost:" (read-file-name "File: ")))
|
||||
(find-alternate-file (concat "/sudo:root@localhost:" buffer-file-name))))
|
||||
|
||||
;; Open Fefes blog
|
||||
(defun fefes-blog ()
|
||||
(interactive)
|
||||
(eww "https://blog.fefe.de/"))
|
||||
|
||||
;; Open the NixOS man page
|
||||
(defun nixos-man ()
|
||||
(interactive)
|
||||
(man "configuration.nix"))
|
||||
|
||||
;; Open local emacs configuration
|
||||
(defun emacs-config ()
|
||||
(interactive)
|
||||
(dired "~/.emacs.d/"))
|
||||
|
||||
;; Get the nix store path for a given derivation.
|
||||
;; If the derivation has not been built before, this will trigger a build.
|
||||
(defun nix-store-path (derivation)
|
||||
(let ((expr (concat "with import <nixos> {}; " derivation)))
|
||||
(s-chomp (shell-command-to-string (concat "nix-build -E '" expr "'")))))
|
||||
|
||||
(defun insert-nix-store-path ()
|
||||
(interactive)
|
||||
(let ((derivation (read-string "Derivation name (in <nixos>): ")))
|
||||
(insert (nix-store-path derivation))))
|
||||
|
||||
(defun toggle-force-newline ()
|
||||
"Buffer-local toggle for enforcing final newline on save."
|
||||
(interactive)
|
||||
(setq-local require-final-newline (not require-final-newline))
|
||||
(message "require-final-newline in buffer %s is now %s"
|
||||
(buffer-name)
|
||||
require-final-newline))
|
||||
|
||||
;; Helm includes a command to run external applications, which does
|
||||
;; not seem to exist in ivy. This implementation uses some of the
|
||||
;; logic from Helm to provide similar functionality using ivy.
|
||||
(defun list-external-commands ()
|
||||
"Creates a list of all external commands available on $PATH
|
||||
while filtering NixOS wrappers."
|
||||
(cl-loop
|
||||
for dir in (split-string (getenv "PATH") path-separator)
|
||||
when (and (file-exists-p dir) (file-accessible-directory-p dir))
|
||||
for lsdir = (cl-loop for i in (directory-files dir t)
|
||||
for bn = (file-name-nondirectory i)
|
||||
when (and (not (s-contains? "-wrapped" i))
|
||||
(not (member bn completions))
|
||||
(not (file-directory-p i))
|
||||
(file-executable-p i))
|
||||
collect bn)
|
||||
append lsdir into completions
|
||||
finally return (sort completions 'string-lessp)))
|
||||
|
||||
(defvar external-command-flag-overrides
|
||||
'(("google-chrome" . "--force-device-scale-factor=1.4"))
|
||||
|
||||
"This setting lets me add additional flags to specific commands
|
||||
that are run interactively via `ivy-run-external-command'.")
|
||||
|
||||
(defun run-external-command (cmd)
|
||||
"Execute the specified command and notify the user when it
|
||||
finishes."
|
||||
(let* ((extra-flags (cdr (assoc cmd external-command-flag-overrides)))
|
||||
(cmd (if extra-flags (s-join " " (list cmd extra-flags)) cmd)))
|
||||
(message "Starting %s..." cmd)
|
||||
(set-process-sentinel
|
||||
(start-process-shell-command cmd nil cmd)
|
||||
(lambda (process event)
|
||||
(when (string= event "finished\n")
|
||||
(message "%s process finished." process))))))
|
||||
|
||||
(defun ivy-run-external-command ()
|
||||
"Prompts the user with a list of all installed applications and
|
||||
lets them select one to launch."
|
||||
|
||||
(interactive)
|
||||
(let ((external-commands-list (list-external-commands)))
|
||||
(ivy-read "Command:" external-commands-list
|
||||
:require-match t
|
||||
:history 'external-commands-history
|
||||
:action #'run-external-command)))
|
||||
|
||||
(defun ivy-password-store (&optional password-store-dir)
|
||||
"Custom version of password-store integration with ivy that
|
||||
actually uses the GPG agent correctly."
|
||||
|
||||
(interactive)
|
||||
(ivy-read "Copy password of entry: "
|
||||
(password-store-list (or password-store-dir (password-store-dir)))
|
||||
:require-match t
|
||||
:keymap ivy-pass-map
|
||||
:action (lambda (entry)
|
||||
(let ((password (auth-source-pass-get 'secret entry)))
|
||||
(password-store-clear)
|
||||
(kill-new password)
|
||||
(setq password-store-kill-ring-pointer kill-ring-yank-pointer)
|
||||
(message "Copied %s to the kill ring. Will clear in %s seconds."
|
||||
entry (password-store-timeout))
|
||||
(setq password-store-timeout-timer
|
||||
(run-at-time (password-store-timeout)
|
||||
nil 'password-store-clear))))))
|
||||
|
||||
(defun ivy-browse-repositories ()
|
||||
"Select a git repository and open its associated magit buffer."
|
||||
|
||||
(interactive)
|
||||
(ivy-read "Repository: "
|
||||
(magit-list-repos)
|
||||
:require-match t
|
||||
:sort t
|
||||
:action #'magit-status))
|
||||
|
||||
(defun warmup-gpg-agent (arg &optional exit)
|
||||
"Function used to warm up the GPG agent before use. This is
|
||||
useful in cases where there is no easy way to make pinentry run
|
||||
in the correct context (such as when sending email)."
|
||||
(interactive)
|
||||
(message "Warming up GPG agent")
|
||||
(epg-sign-string (epg-make-context) "dummy")
|
||||
nil)
|
||||
|
||||
(defun bottom-right-window-p ()
|
||||
"Determines whether the last (i.e. bottom-right) window of the
|
||||
active frame is showing the buffer in which this function is
|
||||
executed."
|
||||
(let* ((frame (selected-frame))
|
||||
(right-windows (window-at-side-list frame 'right))
|
||||
(bottom-windows (window-at-side-list frame 'bottom))
|
||||
(last-window (car (seq-intersection right-windows bottom-windows))))
|
||||
(eq (current-buffer) (window-buffer last-window))))
|
||||
|
||||
(defun inferior-erlang-nix-shell ()
|
||||
"Start an inferior Erlang process from the root of the current
|
||||
project."
|
||||
(interactive)
|
||||
(inferior-erlang
|
||||
(format "nix-shell --command erl %s" (cdr (project-current)))))
|
||||
|
||||
(defun memespace-region ()
|
||||
"Make a meme out of it."
|
||||
|
||||
(interactive)
|
||||
(let* ((start (region-beginning))
|
||||
(end (region-end))
|
||||
(memed
|
||||
(message
|
||||
(s-trim-right
|
||||
(apply #'string
|
||||
(-flatten
|
||||
(nreverse
|
||||
(-reduce-from (lambda (acc x)
|
||||
(cons (cons x (-repeat (+ 1 (length acc)) 32)) acc))
|
||||
'()
|
||||
(string-to-list (buffer-substring-no-properties start end))))))))))
|
||||
|
||||
(save-excursion (delete-region start end)
|
||||
(goto-char start)
|
||||
(insert memed))))
|
||||
|
||||
(provide 'functions)
|
||||
160
tools/emacs/config/init.el
Normal file
160
tools/emacs/config/init.el
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
;;; init.el --- Package bootstrapping. -*- lexical-binding: t; -*-
|
||||
|
||||
;; Packages are installed via Nix configuration, this file only
|
||||
;; initialises the newly loaded packages.
|
||||
|
||||
(require 'use-package)
|
||||
(require 'seq)
|
||||
|
||||
(package-initialize)
|
||||
|
||||
;; Initialise all packages installed via Nix.
|
||||
;;
|
||||
;; TODO: Generate this section in Nix for all packages that do not
|
||||
;; require special configuration.
|
||||
|
||||
;;
|
||||
;; Packages providing generic functionality.
|
||||
;;
|
||||
|
||||
(use-package ace-window
|
||||
:bind (("C-x o" . ace-window))
|
||||
:init
|
||||
(setq aw-keys '(?f ?j ?d ?k ?s ?l ?a)
|
||||
aw-scope 'frame))
|
||||
|
||||
(use-package auth-source-pass :init (auth-source-pass-enable))
|
||||
|
||||
(use-package avy
|
||||
:bind (("M-j" . avy-goto-char)
|
||||
("M-p" . avy-pop-mark)
|
||||
("M-g g" . avy-goto-line)))
|
||||
|
||||
(use-package browse-kill-ring)
|
||||
|
||||
(use-package company
|
||||
:hook ((prog-mode . company-mode))
|
||||
:bind (:map rust-mode-map ("<tab>" . company-indent-or-complete-common)
|
||||
:map lisp-mode-map ("<tab>" . company-indent-or-complete-common))
|
||||
:init (setq company-tooltip-align-annotations t))
|
||||
|
||||
(use-package dash)
|
||||
(use-package dash-functional)
|
||||
(use-package gruber-darker-theme)
|
||||
(use-package ht)
|
||||
(use-package hydra)
|
||||
(use-package idle-highlight-mode :hook ((prog-mode . idle-highlight-mode)))
|
||||
(use-package paredit :hook ((lisp-mode . paredit-mode)
|
||||
(emacs-lisp-mode . paredit-mode)))
|
||||
(use-package multiple-cursors)
|
||||
(use-package pinentry
|
||||
:init
|
||||
(setq epa-pinentry-mode 'loopback)
|
||||
(pinentry-start))
|
||||
|
||||
(use-package rainbow-delimiters :hook (prog-mode . rainbow-delimiters-mode))
|
||||
(use-package rainbow-mode)
|
||||
(use-package s)
|
||||
(use-package smartparens :init (smartparens-global-mode))
|
||||
(use-package string-edit)
|
||||
(use-package telephone-line) ;; configuration happens outside of use-package
|
||||
(use-package undo-tree :init (global-undo-tree-mode))
|
||||
(use-package uuidgen)
|
||||
(use-package which-key :init (which-key-mode t))
|
||||
|
||||
;;
|
||||
;; Applications in emacs
|
||||
;;
|
||||
|
||||
(use-package magit
|
||||
:bind ("C-c g" . magit-status)
|
||||
:init (setq magit-repository-directories '(("/home/vincent/projects" . 2))))
|
||||
|
||||
(use-package password-store)
|
||||
(use-package pg)
|
||||
(use-package restclient)
|
||||
|
||||
;;
|
||||
;; Packages providing language-specific functionality
|
||||
;;
|
||||
|
||||
(use-package cargo
|
||||
:hook ((rust-mode . cargo-minor-mode)
|
||||
(cargo-process-mode . visual-line-mode))
|
||||
:bind (:map cargo-minor-mode-map ("C-c C-c C-l" . ignore)))
|
||||
|
||||
(use-package dockerfile-mode)
|
||||
|
||||
(use-package erlang
|
||||
:hook ((erlang-mode . (lambda ()
|
||||
;; Don't indent after '>' while I'm writing
|
||||
(local-set-key ">" 'self-insert-command)))))
|
||||
|
||||
(use-package f)
|
||||
|
||||
(use-package go-mode
|
||||
:bind (:map go-mode-map ("C-c C-r" . recompile)
|
||||
:map go-mode-map ("<tab>" . company-indent-or-complete-common))
|
||||
:hook ((go-mode . (lambda ()
|
||||
(setq tab-width 2)
|
||||
(setq-local compile-command
|
||||
(concat "go build " buffer-file-name))))))
|
||||
|
||||
(use-package haskell-mode)
|
||||
|
||||
(use-package jq-mode
|
||||
:init (add-to-list 'auto-mode-alist '("\\.jq\\'" . jq-mode)))
|
||||
|
||||
(use-package kotlin-mode
|
||||
:bind (:map kotlin-mode-map ("<tab>" . indent-relative)))
|
||||
|
||||
(use-package lsp-mode)
|
||||
|
||||
(use-package markdown-mode
|
||||
:init
|
||||
(add-to-list 'auto-mode-alist '("\\.txt\\'" . markdown-mode))
|
||||
(add-to-list 'auto-mode-alist '("\\.markdown\\'" . markdown-mode))
|
||||
(add-to-list 'auto-mode-alist '("\\.md\\'" . markdown-mode)))
|
||||
|
||||
(use-package markdown-toc)
|
||||
|
||||
(use-package nix-mode
|
||||
:bind (:map nix-mode-map ("<tab>" . nix-indent-line)))
|
||||
|
||||
(use-package nginx-mode)
|
||||
(use-package rust-mode)
|
||||
(use-package terraform-mode)
|
||||
(use-package toml-mode)
|
||||
(use-package web-mode)
|
||||
(use-package yaml-mode)
|
||||
|
||||
;; Configure a few basics before moving on to package-specific initialisation.
|
||||
(setq custom-file (concat user-emacs-directory "init/custom.el"))
|
||||
(load custom-file)
|
||||
|
||||
(defvar home-dir (expand-file-name "~"))
|
||||
|
||||
;; Seed RNG
|
||||
(random t)
|
||||
|
||||
;; Load all other Emacs configuration. These configurations are
|
||||
;; added to `load-path' by Nix.
|
||||
(mapc 'require '(desktop
|
||||
mail-setup
|
||||
look-and-feel
|
||||
functions
|
||||
settings
|
||||
modes
|
||||
bindings
|
||||
term-setup
|
||||
eshell-setup))
|
||||
(telephone-line-setup)
|
||||
(ace-window-display-mode)
|
||||
|
||||
;; If a local configuration file exists, it should be loaded. No
|
||||
;; other configuration comes from `user-emacs-directory'.
|
||||
(let ((local-file (expand-file-name (f-join user-emacs-directory "local.el"))))
|
||||
(when (f-exists? local-file)
|
||||
(load local-file)))
|
||||
|
||||
(provide 'init)
|
||||
132
tools/emacs/config/look-and-feel.el
Normal file
132
tools/emacs/config/look-and-feel.el
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
;;; -*- lexical-binding: t; -*-
|
||||
|
||||
;; Hide those ugly tool bars:
|
||||
(tool-bar-mode 0)
|
||||
(scroll-bar-mode 0)
|
||||
(menu-bar-mode 0)
|
||||
(add-hook 'after-make-frame-functions
|
||||
(lambda (frame) (scroll-bar-mode 0)))
|
||||
|
||||
;; Don't do any annoying things:
|
||||
(setq ring-bell-function 'ignore)
|
||||
(setq initial-scratch-message "")
|
||||
|
||||
;; Remember layout changes
|
||||
(winner-mode 1)
|
||||
|
||||
;; Usually emacs will run as a proper GUI application, in which case a few
|
||||
;; extra settings are nice-to-have:
|
||||
(when window-system
|
||||
(setq frame-title-format '(buffer-file-name "%f" ("%b")))
|
||||
(mouse-wheel-mode t)
|
||||
(blink-cursor-mode -1))
|
||||
|
||||
;; Configure editor fonts
|
||||
(let ((font (format "Input Mono-%d" 12)))
|
||||
(setq default-frame-alist `((font-backend . "xft")
|
||||
(font . ,font)))
|
||||
(set-frame-font font t t))
|
||||
|
||||
;; Display modeline time in dottime (see https://dotti.me)
|
||||
;;
|
||||
;; This is done in a way that initially seems more complicated than
|
||||
;; one would like, but this is unfortunately required due to the way
|
||||
;; `format-time-string' handles timezones.
|
||||
(defun format-dottime-advice (orig _ &optional _ _)
|
||||
(let* ((offset-sec (car (current-time-zone)))
|
||||
(offset-hours (/ offset-sec 60 60))
|
||||
(dottime (if (/= offset-hours 0)
|
||||
(concat "%M-%Dt%H·%M" (format "%0+3d" offset-hours))
|
||||
"%m-%dT%H·%M")))
|
||||
(apply orig '("%m-%dT%H·%M" nil t))))
|
||||
|
||||
(advice-add 'format-time-string :around #'format-dottime-advice)
|
||||
|
||||
;; Configure telephone-line
|
||||
(defun telephone-misc-if-last-window ()
|
||||
"Renders the mode-line-misc-info string for display in the
|
||||
mode-line if the currently active window is the last one in the
|
||||
frame.
|
||||
|
||||
The idea is to not display information like the current time,
|
||||
load, battery levels on all buffers."
|
||||
|
||||
(when (bottom-right-window-p)
|
||||
(telephone-line-raw mode-line-misc-info t)))
|
||||
|
||||
(defun telephone-line-setup ()
|
||||
(telephone-line-defsegment telephone-line-last-window-segment ()
|
||||
(telephone-misc-if-last-window))
|
||||
|
||||
;; Display the current EXWM workspace index in the mode-line
|
||||
(telephone-line-defsegment telephone-line-exwm-workspace-index ()
|
||||
(when (bottom-right-window-p)
|
||||
(format "[%s]" exwm-workspace-current-index)))
|
||||
|
||||
;; Define a highlight font for ~ important ~ information in the last
|
||||
;; window.
|
||||
(defface special-highlight '((t (:foreground "white" :background "#5f627f"))) "")
|
||||
(add-to-list 'telephone-line-faces
|
||||
'(highlight . (special-highlight . special-highlight)))
|
||||
|
||||
(setq telephone-line-lhs
|
||||
'((nil . (telephone-line-position-segment))
|
||||
(accent . (telephone-line-buffer-segment))))
|
||||
|
||||
(setq telephone-line-rhs
|
||||
'((accent . (telephone-line-major-mode-segment))
|
||||
(nil . (telephone-line-last-window-segment
|
||||
telephone-line-exwm-workspace-index))
|
||||
|
||||
;; TODO(tazjin): lets not do this particular thing while I
|
||||
;; don't actually run notmuch, there are too many things
|
||||
;; that have a dependency on the modeline drawing correctly
|
||||
;; (including randr operations!)
|
||||
;;
|
||||
;; (highlight . (telephone-line-notmuch-counts))
|
||||
))
|
||||
|
||||
(setq telephone-line-primary-left-separator 'telephone-line-tan-left
|
||||
telephone-line-primary-right-separator 'telephone-line-tan-right
|
||||
telephone-line-secondary-left-separator 'telephone-line-tan-hollow-left
|
||||
telephone-line-secondary-right-separator 'telephone-line-tan-hollow-right)
|
||||
|
||||
(telephone-line-mode 1))
|
||||
|
||||
;; Auto refresh buffers
|
||||
(global-auto-revert-mode 1)
|
||||
|
||||
;; Use clipboard properly
|
||||
(setq select-enable-clipboard t)
|
||||
|
||||
;; Show in-progress chords in minibuffer
|
||||
(setq echo-keystrokes 0.1)
|
||||
|
||||
;; Show column numbers in all buffers
|
||||
(column-number-mode t)
|
||||
|
||||
;; Highlight currently active line
|
||||
(global-hl-line-mode t)
|
||||
|
||||
(defalias 'yes-or-no-p 'y-or-n-p)
|
||||
(defalias 'auto-tail-revert-mode 'tail-mode)
|
||||
|
||||
;; Style line numbers (shown with M-g g)
|
||||
(setq linum-format
|
||||
(lambda (line)
|
||||
(propertize
|
||||
(format (concat " %"
|
||||
(number-to-string
|
||||
(length (number-to-string
|
||||
(line-number-at-pos (point-max)))))
|
||||
"d ")
|
||||
line)
|
||||
'face 'linum)))
|
||||
|
||||
;; Display tabs as 2 spaces
|
||||
(setq tab-width 2)
|
||||
|
||||
;; Don't wrap around when moving between buffers
|
||||
(setq windmove-wrap-around nil)
|
||||
|
||||
(provide 'look-and-feel)
|
||||
90
tools/emacs/config/mail-setup.el
Normal file
90
tools/emacs/config/mail-setup.el
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
(require 'notmuch)
|
||||
(require 'counsel-notmuch)
|
||||
|
||||
(global-set-key (kbd "C-c m") 'notmuch-hello)
|
||||
(global-set-key (kbd "C-c C-m") 'counsel-notmuch)
|
||||
(global-set-key (kbd "C-c C-e n") 'notmuch-mua-new-mail)
|
||||
|
||||
(setq notmuch-cache-dir (format "%s/.cache/notmuch" (getenv "HOME")))
|
||||
(make-directory notmuch-cache-dir t)
|
||||
|
||||
;; Cache addresses for completion:
|
||||
(setq notmuch-address-save-filename (concat notmuch-cache-dir "/addresses"))
|
||||
|
||||
;; Don't spam my home folder with drafts:
|
||||
(setq notmuch-draft-folder "drafts") ;; relative to notmuch database
|
||||
|
||||
;; Mark things as read when archiving them:
|
||||
(setq notmuch-archive-tags '("-inbox" "-unread" "+archive"))
|
||||
|
||||
;; Show me saved searches that I care about:
|
||||
(setq notmuch-saved-searches
|
||||
'((:name "inbox" :query "tag:inbox" :count-query "tag:inbox AND tag:unread" :key "i")
|
||||
(:name "sent" :query "tag:sent" :key "t")
|
||||
(:name "drafts" :query "tag:draft")))
|
||||
(setq notmuch-show-empty-saved-searches t)
|
||||
|
||||
;; Mail sending configuration
|
||||
(setq send-mail-function 'sendmail-send-it) ;; sendmail provided by MSMTP
|
||||
(setq notmuch-always-prompt-for-sender t)
|
||||
(setq notmuch-mua-user-agent-function
|
||||
(lambda () (format "Emacs %s; notmuch.el %s" emacs-version notmuch-emacs-version)))
|
||||
(setq mail-host-address (system-name))
|
||||
(setq notmuch-mua-cite-function #'message-cite-original-without-signature)
|
||||
|
||||
;; Close mail buffers after sending mail
|
||||
(setq message-kill-buffer-on-exit t)
|
||||
|
||||
;; Ensure sender is correctly passed to msmtp
|
||||
(setq mail-specify-envelope-from t
|
||||
message-sendmail-envelope-from 'header
|
||||
mail-envelope-from 'header)
|
||||
|
||||
;; Store sent mail in the correct folder per account
|
||||
(setq notmuch-maildir-use-notmuch-insert nil)
|
||||
(setq notmuch-fcc-dirs '(("mail@tazj.in" . "tazjin/Sent")))
|
||||
|
||||
;; I don't use drafts but I instinctively hit C-x C-s constantly, lets
|
||||
;; handle that gracefully.
|
||||
(define-key notmuch-message-mode-map (kbd "C-x C-s") #'ignore)
|
||||
|
||||
;; MSMTP decrypts passwords using pass, but pinentry doesn't work
|
||||
;; correctly in that setup. This forces a warmup of the GPG agent
|
||||
;; before sending the message.
|
||||
;;
|
||||
;; Note that the sending function is advised because the provided hook
|
||||
;; for this seems to run at the wrong time.
|
||||
(advice-add 'notmuch-mua-send-common :before 'warmup-gpg-agent)
|
||||
|
||||
;; Define a telephone-line segment for displaying the count of unread,
|
||||
;; important mails in the last window's mode-line:
|
||||
(defvar *last-notmuch-count-redraw* 0)
|
||||
(defvar *current-notmuch-count* nil)
|
||||
|
||||
(defun update-display-notmuch-counts ()
|
||||
"Update and render the current state of the notmuch unread
|
||||
count for display in the mode-line.
|
||||
|
||||
The offlineimap-timer runs every 2 minutes, so it does not make
|
||||
sense to refresh this much more often than that."
|
||||
|
||||
(when (> (- (float-time) *last-notmuch-count-redraw*) 30)
|
||||
(setq *last-notmuch-count-redraw* (float-time))
|
||||
(let* ((inbox-unread (notmuch-saved-search-count "tag:inbox and tag:unread"))
|
||||
(notmuch-count (format "I: %s; D: %s" inbox-unread)))
|
||||
(setq *current-notmuch-count* notmuch-count)))
|
||||
|
||||
(when (and (bottom-right-window-p)
|
||||
;; Only render if the initial update is done and there
|
||||
;; are unread mails:
|
||||
*current-notmuch-count*
|
||||
(not (equal *current-notmuch-count* "I: 0; D: 0")))
|
||||
*current-notmuch-count*))
|
||||
|
||||
(telephone-line-defsegment telephone-line-notmuch-counts ()
|
||||
"This segment displays the count of unread notmuch messages in
|
||||
the last window's mode-line (if unread messages are present)."
|
||||
|
||||
(update-display-notmuch-counts))
|
||||
|
||||
(provide 'mail-setup)
|
||||
36
tools/emacs/config/modes.el
Normal file
36
tools/emacs/config/modes.el
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
;; Initializes modes I use.
|
||||
|
||||
(add-hook 'prog-mode-hook 'esk-add-watchwords)
|
||||
|
||||
;; Use auto-complete as completion at point
|
||||
(defun set-auto-complete-as-completion-at-point-function ()
|
||||
(setq completion-at-point-functions '(auto-complete)))
|
||||
|
||||
(add-hook 'auto-complete-mode-hook
|
||||
'set-auto-complete-as-completion-at-point-function)
|
||||
|
||||
;; Enable rainbow-delimiters for all things programming
|
||||
(add-hook 'prog-mode-hook 'rainbow-delimiters-mode)
|
||||
|
||||
;; Enable Paredit & Company in Emacs Lisp mode
|
||||
(add-hook 'emacs-lisp-mode-hook 'company-mode)
|
||||
|
||||
;; Always highlight matching brackets
|
||||
(show-paren-mode 1)
|
||||
|
||||
;; Always auto-close parantheses and other pairs
|
||||
;; (replaced by smartparens)
|
||||
;; (electric-pair-mode)
|
||||
|
||||
;; Keep track of recent files
|
||||
(recentf-mode)
|
||||
|
||||
;; Easily navigate sillycased words
|
||||
(global-subword-mode 1)
|
||||
|
||||
;; Transparently open compressed files
|
||||
(auto-compression-mode t)
|
||||
|
||||
;; Show available key chord completions
|
||||
|
||||
(provide 'modes)
|
||||
64
tools/emacs/config/settings.el
Normal file
64
tools/emacs/config/settings.el
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
(require 'prescient)
|
||||
(require 'ivy-prescient)
|
||||
(require 'uniquify)
|
||||
(require 'ivy-pass)
|
||||
|
||||
;; Make ivy go!
|
||||
(ivy-mode 1)
|
||||
(counsel-mode 1)
|
||||
|
||||
(setq ivy-use-virtual-buffers t)
|
||||
(setq enable-recursive-minibuffers t)
|
||||
|
||||
;; Enable support for prescient in ivy & configure it
|
||||
(ivy-prescient-mode)
|
||||
(prescient-persist-mode)
|
||||
|
||||
;; Move files to trash when deleting
|
||||
(setq delete-by-moving-to-trash t)
|
||||
|
||||
;; We don't live in the 80s, but we're also not a shitty web app.
|
||||
(setq gc-cons-threshold 20000000)
|
||||
|
||||
(setq uniquify-buffer-name-style 'forward)
|
||||
|
||||
; Fix some defaults
|
||||
(setq visible-bell nil
|
||||
inhibit-startup-message t
|
||||
color-theme-is-global t
|
||||
sentence-end-double-space nil
|
||||
shift-select-mode nil
|
||||
uniquify-buffer-name-style 'forward
|
||||
whitespace-style '(face trailing lines-tail tabs)
|
||||
whitespace-line-column 80
|
||||
default-directory "~"
|
||||
fill-column 80
|
||||
ediff-split-window-function 'split-window-horizontally)
|
||||
|
||||
(add-to-list 'safe-local-variable-values '(lexical-binding . t))
|
||||
(add-to-list 'safe-local-variable-values '(whitespace-line-column . 80))
|
||||
|
||||
(set-default 'indent-tabs-mode nil)
|
||||
|
||||
;; UTF-8 please
|
||||
(setq locale-coding-system 'utf-8) ; pretty
|
||||
(set-terminal-coding-system 'utf-8) ; pretty
|
||||
(set-keyboard-coding-system 'utf-8) ; pretty
|
||||
(set-selection-coding-system 'utf-8) ; please
|
||||
(prefer-coding-system 'utf-8) ; with sugar on top
|
||||
|
||||
;; Make emacs behave sanely (overwrite selected text)
|
||||
(delete-selection-mode 1)
|
||||
|
||||
;; Keep your temporary files in tmp, emacs!
|
||||
(setq auto-save-file-name-transforms
|
||||
`((".*" ,temporary-file-directory t)))
|
||||
(setq backup-directory-alist
|
||||
`((".*" . ,temporary-file-directory)))
|
||||
|
||||
(remove-hook 'kill-buffer-query-functions 'server-kill-buffer-query-function)
|
||||
|
||||
;; Show time in 24h format
|
||||
(setq display-time-24hr-format t)
|
||||
|
||||
(provide 'settings)
|
||||
36
tools/emacs/config/term-setup.el
Normal file
36
tools/emacs/config/term-setup.el
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
;; Utilities for X11 terminal buffers.
|
||||
|
||||
(defvar x11-terminal-program "gnome-terminal"
|
||||
"Which X11 terminal application to use.")
|
||||
|
||||
(defvar x11-terminal-buffer-prefix "Term"
|
||||
"String prefix for X11 terminal buffer names.")
|
||||
|
||||
(defun open-or-create-terminal-buffer (buffer-name)
|
||||
"Switch to the buffer with BUFFER-NAME or create a new buffer
|
||||
running the configured X11 terminal."
|
||||
(let ((buffer (get-buffer buffer-name)))
|
||||
(if (not buffer)
|
||||
(run-external-command x11-terminal-program)
|
||||
(switch-to-buffer buffer))))
|
||||
|
||||
(defun is-terminal-buffer (buffer)
|
||||
"Determine whether BUFFER runs an X11 terminal."
|
||||
(and (equal 'exwm-mode (buffer-local-value 'major-mode buffer))
|
||||
(s-starts-with? x11-terminal-buffer-prefix (buffer-name buffer))))
|
||||
|
||||
(defun counsel-switch-to-terminal ()
|
||||
"Switch to an X11 terminal buffer, or create a new one."
|
||||
(interactive)
|
||||
(let ((terms (-map #'buffer-name
|
||||
(-filter #'is-terminal-buffer (buffer-list)))))
|
||||
(if terms
|
||||
(ivy-read "Switch to terminal buffer: "
|
||||
(cons "New terminal" terms)
|
||||
:caller 'counsel-switch-to-terminal
|
||||
:preselect (s-concat "^" x11-terminal-buffer-prefix)
|
||||
:require-match t
|
||||
:action #'open-or-create-terminal-buffer)
|
||||
(run-external-command x11-terminal-program))))
|
||||
|
||||
(provide 'term-setup)
|
||||
Loading…
Add table
Add a link
Reference in a new issue