merge(emacs): Merge (unrelated) emacs.d history into tools/emacs
This commit is contained in:
commit
b938d716ff
13 changed files with 1079 additions and 0 deletions
11
tools/emacs/.gitignore
vendored
Normal file
11
tools/emacs/.gitignore
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
.smex-items
|
||||
*token*
|
||||
auto-save-list/
|
||||
clones/
|
||||
elpa/
|
||||
irc.el
|
||||
local.el
|
||||
other/
|
||||
scripts/
|
||||
themes/
|
||||
*.elc
|
6
tools/emacs/README.md
Normal file
6
tools/emacs/README.md
Normal file
|
@ -0,0 +1,6 @@
|
|||
emacs.d
|
||||
========
|
||||
|
||||
This contains my emacs.d folder.
|
||||
|
||||
I use emacs for many things.
|
168
tools/emacs/init.el
Normal file
168
tools/emacs/init.el
Normal file
|
@ -0,0 +1,168 @@
|
|||
;;; 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)
|
||||
|
||||
;; Add 'init' folder that contains other settings to load.
|
||||
(add-to-list 'load-path (concat user-emacs-directory "init"))
|
||||
|
||||
;; 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 edit-server :init (edit-server-start))
|
||||
(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 eglot
|
||||
:init (defvar rust-eglot-initialized nil)
|
||||
:hook ((rust-mode . (lambda ()
|
||||
(unless rust-eglot-initialized
|
||||
(call-interactively #'eglot)
|
||||
(setq rust-eglot-initialized t))))))
|
||||
|
||||
(use-package erlang
|
||||
:hook ((erlang-mode . (lambda ()
|
||||
;; Don't indent after '>' while I'm writing
|
||||
(local-set-key ">" 'self-insert-command)))))
|
||||
|
||||
(use-package go-mode)
|
||||
(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 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)
|
||||
|
||||
;;
|
||||
;; EXWM / NixOS related packages
|
||||
;;
|
||||
|
||||
;; 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)
|
||||
|
||||
(defun load-other-settings ()
|
||||
(mapc 'require '(nixos
|
||||
mail-setup
|
||||
look-and-feel
|
||||
functions
|
||||
settings
|
||||
modes
|
||||
bindings
|
||||
term-setup
|
||||
eshell-setup))
|
||||
(telephone-line-setup)
|
||||
(ace-window-display-mode)
|
||||
|
||||
(use-package sly
|
||||
:init (setq inferior-lisp-program (concat (nix-store-path "sbcl") "/bin/sbcl"))
|
||||
;;(add-to-list 'company-backends 'sly-company)
|
||||
))
|
||||
|
||||
|
||||
;; Some packages can only be initialised after the rest of the
|
||||
;; settings has been applied:
|
||||
|
||||
(add-hook 'after-init-hook 'load-other-settings)
|
||||
(put 'narrow-to-region 'disabled nil)
|
||||
(put 'upcase-region 'disabled nil)
|
54
tools/emacs/init/bindings.el
Normal file
54
tools/emacs/init/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/init/custom.el
Normal file
52
tools/emacs/init/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)
|
||||
'(aprila-nixops-path "/home/vincent/projects/langler/nixops")
|
||||
'(aprila-release-author "Vincent Ambo <vincent@aprila.no>")
|
||||
'(aprila-releases-path "/home/vincent/projects/langler/docs/releases")
|
||||
'(avy-background t)
|
||||
'(cargo-process--custom-path-to-bin "env CARGO_INCREMENTAL=1 cargo")
|
||||
'(cargo-process--enable-rust-backtrace 1)
|
||||
'(custom-enabled-themes (quote (gruber-darker)))
|
||||
'(custom-safe-themes
|
||||
(quote
|
||||
("d61fc0e6409f0c2a22e97162d7d151dee9e192a90fa623f8d6a071dbf49229c6" "3c83b3676d796422704082049fc38b6966bcad960f896669dfc21a7a37a748fa" "89336ca71dae5068c165d932418a368a394848c3b8881b2f96807405d8c6b5b6" default)))
|
||||
'(elnode-send-file-program "/run/current-system/sw/bin/cat")
|
||||
'(frame-brackground-mode (quote dark))
|
||||
'(global-auto-complete-mode t)
|
||||
'(intero-debug nil)
|
||||
'(intero-global-mode t nil (intero))
|
||||
'(intero-package-version "0.1.31")
|
||||
'(kubernetes-commands-display-buffer-function (quote display-buffer))
|
||||
'(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)))
|
||||
(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")))))
|
68
tools/emacs/init/eshell-setup.el
Normal file
68
tools/emacs/init/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)
|
266
tools/emacs/init/functions.el
Normal file
266
tools/emacs/init/functions.el
Normal file
|
@ -0,0 +1,266 @@
|
|||
(require 's)
|
||||
;; A few handy functions I use in init.el (or not, but they're nice to
|
||||
;; have)
|
||||
|
||||
(defun custom-download-theme (url filename)
|
||||
"Downloads a theme through HTTP and places it in ~/.emacs.d/themes"
|
||||
|
||||
;; Ensure the directory exists
|
||||
(unless (file-exists-p "~/.emacs.d/themes")
|
||||
(make-directory "~/.emacs.d/themes"))
|
||||
|
||||
;; Adds the themes folder to the theme load path (if not already
|
||||
;; there)
|
||||
(unless (member "~/.emacs.d/themes" custom-theme-load-path)
|
||||
(add-to-list 'custom-theme-load-path "~/.emacs.d/themes"))
|
||||
|
||||
;; Download file if it doesn't exist.
|
||||
|
||||
(let ((file
|
||||
(concat "~/.emacs.d/themes/" filename)))
|
||||
(unless (file-exists-p file)
|
||||
(url-copy-file url file))))
|
||||
|
||||
(defun custom-download-script (url filename)
|
||||
"Downloads an Elisp script, places it in ~/.emacs/other and then loads it"
|
||||
|
||||
;; Ensure the directory exists
|
||||
(unless (file-exists-p "~/.emacs.d/other")
|
||||
(make-directory "~/.emacs.d/other"))
|
||||
|
||||
;; Download file if it doesn't exist.
|
||||
(let ((file
|
||||
(concat "~/.emacs.d/other/" filename)))
|
||||
(unless (file-exists-p file)
|
||||
(url-copy-file url file))
|
||||
|
||||
(load file)))
|
||||
|
||||
(defun keychain-password (account &optional keychain)
|
||||
"Returns the password for the account, by default it's looked up in the Login.keychain but a
|
||||
different keychain can be specified."
|
||||
(let ((k (if keychain keychain "Login.keychain")))
|
||||
(replace-regexp-in-string
|
||||
"\n" ""
|
||||
(shell-command-to-string (concat "security find-generic-password -w -a "
|
||||
account
|
||||
" "
|
||||
k)))))
|
||||
|
||||
;; This clones a git repository to 'foldername in .emacs.d
|
||||
;; if there isn't already a folder with that name
|
||||
(defun custom-clone-git (url foldername)
|
||||
"Clones a git repository to .emacs.d/foldername"
|
||||
(let ((fullpath (concat "~/.emacs.d/" foldername)))
|
||||
(unless (file-exists-p fullpath)
|
||||
(async-shell-command (concat "git clone " url " " fullpath)))))
|
||||
|
||||
(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 this machines NixOS config
|
||||
(defun nix-config ()
|
||||
(interactive)
|
||||
(find-file "/etc/nixos/configuration.nix"))
|
||||
|
||||
;; 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)))
|
||||
|
||||
(defun run-external-command (cmd)
|
||||
"Execute the specified command and notify the user when it
|
||||
finishes."
|
||||
(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 intero-fix-ghci-panic ()
|
||||
"Disable deferring of out of scope variable errors, which
|
||||
triggers a bug in the interactive Emacs REPL printing a panic
|
||||
under certain conditions."
|
||||
|
||||
(interactive)
|
||||
(let* ((root (intero-project-root))
|
||||
(package-name (intero-package-name))
|
||||
(backend-buffer (intero-buffer 'backend))
|
||||
(name (format "*intero:%s:%s:repl*"
|
||||
(file-name-nondirectory root)
|
||||
package-name))
|
||||
(setting ":set -fno-defer-out-of-scope-variables\n"))
|
||||
(when (get-buffer name)
|
||||
(with-current-buffer (get-buffer name)
|
||||
(goto-char (point-max))
|
||||
(let ((process (get-buffer-process (current-buffer))))
|
||||
(when process (process-send-string process setting)))))))
|
||||
|
||||
;; Brute-force fix: Ensure the setting is injected every time the REPL
|
||||
;; is selected.
|
||||
;;
|
||||
;; Upstream issue: https://github.com/commercialhaskell/intero/issues/569
|
||||
(advice-add 'intero-repl :after (lambda (&rest r) (intero-fix-ghci-panic))
|
||||
'((name . intero-panic-fix)))
|
||||
(advice-add 'intero-repl-load :after (lambda (&rest r) (intero-fix-ghci-panic))
|
||||
'((name . intero-panic-fix)))
|
||||
|
||||
(provide 'functions)
|
115
tools/emacs/init/look-and-feel.el
Normal file
115
tools/emacs/init/look-and-feel.el
Normal file
|
@ -0,0 +1,115 @@
|
|||
;;; -*- 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 battery in mode-line's misc section on adho:
|
||||
(when (equal "adho" (system-name))
|
||||
(setq battery-mode-line-format " %b%p%%")
|
||||
(display-battery-mode))
|
||||
|
||||
;; 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 in 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))
|
||||
(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)
|
98
tools/emacs/init/mail-setup.el
Normal file
98
tools/emacs/init/mail-setup.el
Normal file
|
@ -0,0 +1,98 @@
|
|||
(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 "aprila-dev" :query "tag:aprila-dev" :count-query "tag:aprila-dev AND tag:unread" :key "d")
|
||||
(:name "gitlab" :query "tag:gitlab" :key "g")
|
||||
(: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")
|
||||
;; Not a mistake, Office365 apparently
|
||||
;; renames IMAP folders (!) to your local
|
||||
;; language instead of providing translations
|
||||
;; in the UI m(
|
||||
("vincent@aprila.no" . "aprila/Sende element")))
|
||||
|
||||
;; 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"))
|
||||
(devel-unread (notmuch-saved-search-count "tag:aprila-dev and tag:unread"))
|
||||
(notmuch-count (format "I: %s; D: %s" inbox-unread devel-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/init/modes.el
Normal file
36
tools/emacs/init/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)
|
103
tools/emacs/init/nixos.el
Normal file
103
tools/emacs/init/nixos.el
Normal file
|
@ -0,0 +1,103 @@
|
|||
;; Configure additional settings if this is one of my NixOS machines
|
||||
;; (i.e. if ExWM is required)
|
||||
;; -*- lexical-binding: t; -*-
|
||||
|
||||
(require 's)
|
||||
(require 'f)
|
||||
(require 'dash)
|
||||
|
||||
(defun pulseaudio-ctl (cmd)
|
||||
(shell-command (concat "pulseaudio-ctl " cmd))
|
||||
(message "Volume command: %s" cmd))
|
||||
|
||||
(defun volume-mute () (interactive) (pulseaudio-ctl "mute"))
|
||||
(defun volume-up () (interactive) (pulseaudio-ctl "up"))
|
||||
(defun volume-down () (interactive) (pulseaudio-ctl "down"))
|
||||
|
||||
(defun brightness-up ()
|
||||
(interactive)
|
||||
(shell-command "exec light -A 10")
|
||||
(message "Brightness increased"))
|
||||
|
||||
(defun brightness-down ()
|
||||
(interactive)
|
||||
(shell-command "exec light -U 10")
|
||||
(message "Brightness decreased"))
|
||||
|
||||
(defun lock-screen ()
|
||||
(interactive)
|
||||
(shell-command "screen-lock"))
|
||||
|
||||
(defun generate-randr-config ()
|
||||
(-flatten `(,(-map (lambda (n) (list n "DP2")) (number-sequence 1 7))
|
||||
(0 "eDP1")
|
||||
,(-map (lambda (n) (list n "eDP1")) (number-sequence 8 9)))))
|
||||
|
||||
(use-package exwm
|
||||
:hook ((exwm-update-class . (lambda ()
|
||||
;; Make class name the buffer name
|
||||
(exwm-workspace-rename-buffer exwm-class-name))))
|
||||
:init
|
||||
(progn
|
||||
(require 'exwm-config)
|
||||
|
||||
(fringe-mode 3)
|
||||
|
||||
(setq exwm-workspace-number 10)
|
||||
|
||||
;; 's-r': Reset
|
||||
(exwm-input-set-key (kbd "s-r") #'exwm-reset)
|
||||
;; 's-w': Switch workspace
|
||||
(exwm-input-set-key (kbd "s-w") #'exwm-workspace-switch)
|
||||
;; 's-N': Switch to certain workspace
|
||||
(dotimes (i 10)
|
||||
(exwm-input-set-key (kbd (format "s-%d" i))
|
||||
`(lambda ()
|
||||
(interactive)
|
||||
(exwm-workspace-switch-create ,i))))
|
||||
|
||||
;; Launch applications with completion (dmenu style!)
|
||||
(exwm-input-set-key (kbd "s-d") #'ivy-run-external-command)
|
||||
(exwm-input-set-key (kbd "s-p") #'ivy-password-store)
|
||||
(exwm-input-set-key (kbd "C-s-p") '(lambda ()
|
||||
(interactive)
|
||||
(ivy-password-store "~/.aprila-secrets")))
|
||||
|
||||
;; Add Alacritty selector to a key
|
||||
(exwm-input-set-key (kbd "C-x t") #'counsel-switch-to-alacritty)
|
||||
|
||||
;; 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)
|
||||
|
||||
;; Line-editing shortcuts
|
||||
(exwm-input-set-simulation-keys
|
||||
'(([?\C-d] . delete)
|
||||
([?\C-w] . ?\C-c)))
|
||||
|
||||
;; Enable EXWM
|
||||
(exwm-enable)
|
||||
|
||||
;; Show time in the mode line
|
||||
(display-time-mode)
|
||||
|
||||
;; Configure xrandr when running on laptop
|
||||
(when (equal (shell-command-to-string "hostname") "adho\n")
|
||||
(require 'exwm-randr)
|
||||
(setq exwm-randr-workspace-output-plist (generate-randr-config))
|
||||
(exwm-randr-enable))
|
||||
|
||||
;; Let buffers move seamlessly between workspaces
|
||||
(setq exwm-workspace-show-all-buffers t)
|
||||
(setq exwm-layout-show-all-buffers t)))
|
||||
|
||||
(provide 'nixos)
|
65
tools/emacs/init/settings.el
Normal file
65
tools/emacs/init/settings.el
Normal file
|
@ -0,0 +1,65 @@
|
|||
(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)
|
||||
(add-to-list 'ivy-prescient-excluded-commands 'counsel-rg)
|
||||
|
||||
;; 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)
|
37
tools/emacs/init/term-setup.el
Normal file
37
tools/emacs/init/term-setup.el
Normal file
|
@ -0,0 +1,37 @@
|
|||
;; Utilities for Alacritty buffers.
|
||||
|
||||
(defun open-or-create-alacritty-buffer (buffer-name)
|
||||
"Switch to the buffer with BUFFER-NAME or create a
|
||||
new buffer running Alacritty."
|
||||
(let ((buffer (get-buffer buffer-name)))
|
||||
(if (not buffer)
|
||||
(run-external-command "alacritty")
|
||||
(switch-to-buffer buffer))))
|
||||
|
||||
(defun is-alacritty-buffer (buffer)
|
||||
"Determine whether BUFFER runs Alacritty."
|
||||
(and (equal 'exwm-mode (buffer-local-value 'major-mode buffer))
|
||||
(s-starts-with? "Alacritty" (buffer-name buffer))))
|
||||
|
||||
(defun counsel-switch-to-alacritty ()
|
||||
"Switch to a (multi-)term buffer or create one."
|
||||
(interactive)
|
||||
(let ((terms (-map #'buffer-name
|
||||
(-filter #'is-alacritty-buffer (buffer-list)))))
|
||||
(if terms
|
||||
(ivy-read "Switch to Alacritty buffer: "
|
||||
(cons "New terminal" terms)
|
||||
:caller 'counsel-switch-to-alacritty
|
||||
:require-match t
|
||||
:action #'open-or-create-alacritty-buffer)
|
||||
(run-external-command "alacritty"))))
|
||||
|
||||
(defun alacritty-rename ()
|
||||
"Rename the current terminal buffer."
|
||||
(interactive)
|
||||
(let* ((buffer (get-buffer (buffer-name))))
|
||||
(if (is-alacritty-buffer buffer)
|
||||
(rename-buffer (format "Alacritty<%s>" (read-string "New terminal name: ")))
|
||||
(error "This function is only intended to rename Alacritty buffers."))))
|
||||
|
||||
(provide 'term-setup)
|
Loading…
Reference in a new issue