emacs/lisp/acdw.el

179 lines
5.9 KiB
EmacsLisp

;;; acdw.el -*- lexical-binding: t; coding: utf-8-unix -*-
;; Author: Case Duckworth <acdw@acdw.net>
;; Created: Sometime during Covid-19, 2020
;; Keywords: configuration
;; URL: https://tildegit.org/acdw/emacs
;; This file is NOT part of GNU Emacs.
;;; License:
;; Everyone is permitted to do whatever with this software, without
;; limitation. This software comes without any warranty whatsoever,
;; but with two pieces of advice:
;; - Don't hurt yourself.
;; - Make good choices.
;;; Commentary:
;; `acdw.el' contains `acdw/map', its mode, and assorted ease-of-life
;; functions for me, acdw.
;;; Code:
;;; Utilities
;;;; Determine the system I'm on
(defconst acdw/system (pcase system-type
('gnu/linux :home)
((or 'msdos 'windows-nt) :work)
(_ :other))
"Which system is currently being used.")
;;;; Run commands only when unfocused
(defun acdw/when-unfocused (func &rest args)
"Call FUNC, with ARGS, iff all Emacs frames are out of focus.
Ready for use with `after-focus-change-function'."
(when (seq-every-p #'null (mapcar #'frame-focus-state (frame-list)))
(apply func args)))
;;;; Run commands at sunrise and sunset
(defun acdw/sunrise-sunset (sunrise-command sunset-command)
"Run commands at sunrise and sunset."
(let* ((times-regex (rx (* nonl)
(: (any ?s ?S) "unrise") " "
(group (repeat 1 2 digit) ":"
(repeat 1 2 digit)
(: (any ?a ?A ?p ?P) (any ?m ?M)))
(* nonl)
(: (any ?s ?S) "unset") " "
(group (repeat 1 2 digit) ":"
(repeat 1 2 digit)
(: (any ?a ?A ?p ?P) (any ?m ?M)))
(* nonl)))
(ss (sunrise-sunset))
(_m (string-match times-regex ss))
(sunrise-time (match-string 1 ss))
(sunset-time (match-string 2 ss)))
(run-at-time sunrise-time (* 60 60 24) sunrise-command)
(run-at-time sunset-time (* 60 60 24) sunset-command)
(run-at-time "12:00am" (* 60 60 24) sunset-command)))
;;;; Define a function and add it to hooks
(defun defun-with-hooks (hooks function-def)
"Add FUNCTION-DEF to HOOKS.
FUNCTION-DEF should be a `defun' form. This function is just to
put functions that only exist for hooks closer to the hooks
they bind to."
(let ((func function-def))
(dolist (hook hooks)
(add-hook hook func))))
;;; Garbage collection hacks
(defconst acdw/gc-cons-threshold-basis (* 800 1024)
"Basis value for `gc-cons-threshold' to return to after jumping.
800 KB is Emacs's default.")
(defconst acdw/gc-cons-percentage-basis 0.1
"Basis value for `gc-cons-percentage' to return to after jumping.
0.1 is Emacs's default.")
(defun acdw/gc-disable ()
"Disable garbage collection by setting relevant variables to their maxima."
(setq gc-cons-threshold most-positive-fixnum
gc-cons-percentage 0.8))
(defun acdw/gc-enable ()
"Re-enable garbage collection by setting relevant variables back to bases."
(setq gc-cons-threshold acdw/gc-cons-threshold-basis
gc-cons-percentage acdw/gc-cons-percentage-basis))
;;; Directories (think `no-littering')
(defvar acdw/dir (expand-file-name
(convert-standard-filename "var/")
user-emacs-directory)
"A directory to hold extra configuration and emacs data.")
(defun acdw/in-dir (file &optional make-directory)
"Expand FILE relative to `acdw/dir', optionally creating its
directory."
(let ((f (expand-file-name (convert-standard-filename file)
acdw/dir)))
(when make-directory
(make-directory (file-name-directory f) 'parents))
f))
;;; Reading mode
(define-minor-mode acdw/reading-mode
"A mode for reading."
:init-value t
:lighter " Read"
(if acdw/reading-mode
(progn ;; turn on
;; settings
(setq-local mode-line-format
'(:eval
(let* ((fmt " Reading %b (%m) ")
(len (length (format-mode-line fmt))))
(concat
(propertize " "
'display `((space :align-to (- right
,len)))
'face '(:inherit italic))
fmt))))
;; modes to disable
(dolist (mode '(display-fill-column-indicator-mode
simple-modeline-mode))
(when (fboundp mode)
(funcall mode -1)))
;; modes to enable
(dolist (mode '(iscroll-mode
olivetti-mode))
(when (fboundp mode)
(funcall mode +1))))
;; turn off
;; settings
(kill-local-variable 'mode-line-format)
;; modes to re-enable
(dolist (mode '(display-fill-column-indicator-mode
simple-modeline-mode))
(when (fboundp mode)
(funcall mode +1)))
;; modes to re-disable
(dolist (mode '(olivetti-mode
iscroll-mode))
(when (fboundp mode)
(funcall mode -1)))
(force-mode-line-update)))
;;; Keymap & Mode
(defvar acdw/map (make-sparse-keymap)
"A keymap for my custom bindings.")
(define-minor-mode acdw/mode
"A mode for `acdw/map'."
:init-value t
:lighter " acdw"
:keymap acdw/map)
(define-globalized-minor-mode acdw/global-mode acdw/mode acdw/mode)
;; Disable `acdw/mode' in the minibuffer
(defun acdw/mode--disable ()
"Disable `acdw/mode'."
(acdw/mode -1))
(add-hook 'minibuffer-setup-hook #'acdw/mode--disable)
;; Set up a leader key for `acdw/mode'
(defvar acdw/leader
(let ((map (make-sparse-keymap))
(c-z (global-key-binding "\C-z")))
(define-key acdw/map "\C-z" map)
(define-key map "\C-z" c-z)
map))
(provide 'acdw)
;;; acdw.el ends here