diff options
| author | bdunahu <bdunahu@operationnull.com> | 2026-01-04 13:13:39 -0700 |
|---|---|---|
| committer | bdunahu <bdunahu@operationnull.com> | 2026-01-04 13:13:39 -0700 |
| commit | c2b706ff2f3aa42d58a03febad1d1b8f8d5a1142 (patch) | |
| tree | d6786f531f02717472abdc992cc6c6ef81e660b3 /kolwynia | |
| parent | c4ca05231236c7e9bdf5304275eadde954acf588 (diff) | |
remove unnecessary nested guix dir
Diffstat (limited to 'kolwynia')
72 files changed, 6029 insertions, 0 deletions
diff --git a/kolwynia/home/bdunahu.scm b/kolwynia/home/bdunahu.scm new file mode 100644 index 0000000..4c60772 --- /dev/null +++ b/kolwynia/home/bdunahu.scm @@ -0,0 +1,175 @@ +;;; Copyright © 2025-2026 bdunahu <bdunahu@operationnull.com> +(define-module (kolwynia home bdunahu) + #:use-module (gnu) + #:use-module (gnu home services) + #:use-module (gnu home services desktop) + #:use-module (gnu home services dict) + #:use-module (gnu home services dotfiles) + #:use-module (gnu home services gnupg) + #:use-module (gnu home services mail) + #:use-module (gnu home services mcron) + #:use-module (gnu home services shells) + #:use-module (gnu home services shepherd) + #:use-module (gnu home services ssh) + #:use-module (gnu home services xdg) + #:use-module (gnu packages gnupg) ;pinentry-emacs + #:use-module ((kolwynia home bdunahu packages) + #:prefix pkgs:) + #:use-module ((kolwynia home bdunahu app-preferences) + #:prefix app:) + #:use-module ((kolwynia home bdunahu ssh) + #:prefix ssh-host:) + #:use-module ((kolwynia home bdunahu mail) ;gitignored + #:prefix mail:) + #:use-module (gnu home) + #:export (bdunahu)) + +;;; Commentary: +;;; Code: + +(define bdunahu + (home-environment + (packages + `(,@pkgs:emacs + ,@pkgs:browser + ,@pkgs:pass + ,@pkgs:media + ,@pkgs:mail + ,@pkgs:tex + ,@pkgs:desktop + ,@pkgs:pdf + ,@pkgs:fonts + ,@pkgs:development + ,@pkgs:reverse-engineering + ,@pkgs:university + ,@pkgs:emulators + ,@pkgs:games)) + (services + (list (service home-shepherd-service-type) + (service home-dicod-service-type) + ;; TODO: causes EXWM XELB: Authorization required, + ;; but no authorization protocol specified. + ;; ,(service home-startx-command-service-type) + (service home-dotfiles-service-type + (home-dotfiles-configuration + (directories '("./bdunahu/files")))) + (service home-gpg-agent-service-type + (home-gpg-agent-configuration + (pinentry-program + (file-append pinentry-emacs "/bin/pinentry-emacs")) + (ssh-support? #t) + (default-cache-ttl 28800) + (max-cache-ttl 28800) + (default-cache-ttl-ssh 28800) + (max-cache-ttl-ssh 28800))) + (service home-xdg-user-directories-service-type + (home-xdg-user-directories-configuration + (desktop "$HOME/dl") + (documents "$HOME/dc") + (download "$HOME/dl") + (music "$HOME/ik") + (pictures "$HOME/md/ig") + (publicshare "$HOME") + (templates "$HOME") + (videos "$HOME/md/vi"))) + (service home-bash-service-type + (home-bash-configuration + (aliases + '(("aardwolf" . "telnet aardmud.org 23") + ("auth" . "echo -e \"$PWD\n\" >> $HOME/.config/guix/shell-authorized-directories") + ("cp" . "cp -i") + ("grep" . "grep --color=auto") + ("guix-rcfg" . "sudo guix system -L ${HOME}/.dotfiles/ reconfigure ${HOME}/.dotfiles/kolwynia/os/${HOSTNAME}.scm") + ("ll" . "ls -l") + ("ls" . "ls -p --color=auto") + ("mkd" . "mkdir -pv") + ("mv" . "mv -i") + ("rm" . "rm -i") + ("suspend" . "sudo loginctl suspend") + ("usb0-shell" . "screen /dev/ttyUSB0 115200") + ("vi" . "vim") + ("xeb" . "emacsclient -nce '(switch-to-buffer nil)'") + ("xet" . "emacsclient -nce '(shell)'") + ("ytta" . "yt-dlp --extract-audio --format bestaudio/best") + ("yttv" . "yt-dlp -f b"))) + + (bashrc (list (plain-file "bashrc" " +# converts above aliases into eshell aliases automatically +alias | sed -E \"s/^alias ([^=]+)='(.*)'$/alias \\1 \\2 \\$*/g; s/'\\\\\\''/'/g;\" >~/.config/emacs/eshell/alias +"))) + (environment-variables + `(("PATH" . "$HOME/.local/bin:$PATH") + ("BROWSER" . ,(car app:default-browser)) + ("VISUAL" . ,(car app:default-editor)) + ("EDITOR" . ,(car app:default-editor)) + ("NETHACKOPTIONS" . "@$XDG_CONFIG_HOME/nethack/config") + ("ZATHURA_PLUGINS_PATH" . "$HOME/.guix-home/profile/lib/zathura"))))) + (service home-openssh-service-type + (home-openssh-configuration + (hosts + (list ssh-host:garmr + ssh-host:heimdallr + ssh-host:nott + ssh-host:surt + ssh-host:codeberg)))) + (service home-mcron-service-type + (home-mcron-configuration + (jobs + (list + #~(job + ;; twenty minutes + (lambda (current-time) (+ current-time (* 20 60))) + "offlineimap") + #~(job + (lambda (current-time) (+ current-time (* 5 60))) + "~/.local/bin/set-t1"))))) + (service home-xdg-configuration-files-service-type + `(("gdbinit" + ,(plain-file + (plain-file-name %default-gdbinit) + (string-append (plain-file-content %default-gdbinit) + "set disassembly-flavor intel +set confirm no +set history filename ~/.cache/gdb/history +set history save on +set history size unlimited"))))) + (service home-msmtp-service-type + (home-msmtp-configuration + (defaults + (msmtp-configuration + (port 587) + (tls? #t) + (tls-starttls? #t) + (log-file "/home/bdunahu/.local/state/msmtp.log") + (auth? #t))) + (accounts + (list + mail:operationnull + mail:umass)) + (default-account "operationnull"))) + (service home-xdg-mime-applications-service-type + (home-xdg-mime-applications-configuration + (default app:mime-app-alist) + (desktop-entries + (list + (xdg-desktop-entry + (file "torrent") + (name "Torrent") + (type 'application) + (config '((exec . "transmission-remote -a %u")))))))) + (simple-service 'xorg-dot + home-files-service-type + `((".Xresources" + ,(plain-file "Xresources" " +Nsxiv.window.background: #000000 +Nsxiv.window.foreground: #FFFFFF +Nsxiv.bar.font: MedievalSharp:size=9 +")) + (".config/gtk-2.0/settings.ini" + ,(plain-file "settings.ini" "[Settings] +gtk-application-prefer-dark-theme=1\n")) + (".config/gtk-3.0/settings.ini" + ,(plain-file "settings.ini" "[Settings] +gtk-application-prefer-dark-theme=1\n")))))))) + +;;; bdunahu.scm ends here diff --git a/kolwynia/home/bdunahu/app-preferences.scm b/kolwynia/home/bdunahu/app-preferences.scm new file mode 100644 index 0000000..b794f2d --- /dev/null +++ b/kolwynia/home/bdunahu/app-preferences.scm @@ -0,0 +1,219 @@ +;;; Copyright © 2026 bdunahu <bdunahu@operationnull.com> +(define-module (kolwynia home bdunahu app-preferences) + #:export (default-browser + default-editor + default-media + default-image + default-pdf + default-torrent + mime-app-alist)) + +;;; Commentary: +;;; the 'torrent' xdg app is defined in bdunahu.scm +;;; Code: + +(define default-browser '("librewolf" . "librewolf.desktop")) +(define default-editor '("emacsclient" . "emacsclient.desktop")) +(define default-media '("mpv" . "mpv.desktop")) +(define default-image '("nsxiv" . "nsxiv.desktop")) +(define default-pdf '("zathura" . "zathura.desktop")) +(define default-torrent '("torrent" . "torrent.desktop")) + +(define browser-mime + '("application/x-extension-htm" + "application/x-extension-xht" + "application/x-extension-xhtml" + "application/xhtml+xml" + "text/html" + "x-scheme-handler/http" + "x-scheme-handler/https")) + +(define editor-mime + '("application/json" + "application/x-sh" + "text/javascript" + "text/markdown" + "text/plain" + "text/troff" + "text/x-c" + "text/x-c++" + "text/x-diff" + "text/x-lisp" + "text/xml" + "text/x-scheme" + "text/x-shellscript" + "text/x-tex")) + +(define file-manager-mime + '("inode/directory")) + +(define media-mime + '("application/mxf" + "application/ogg" + "application/sdp" + "application/smil" + "application/streamingmedia" + "application/vnd.apple.mpegurl" + "application/vnd.ms-asf" + "application/vnd.rn-realmedia" + "application/vnd.rn-realmedia-vbr" + "application/x-cue" + "application/x-extension-m4a" + "application/x-extension-mp4" + "application/x-matroska" + "application/x-mpegurl" + "application/x-ogg" + "application/x-ogm" + "application/x-ogm-audio" + "application/x-ogm-video" + "application/x-shorten" + "application/x-smil" + "application/x-streamingmedia" + "audio/3gpp" + "audio/3gpp2" + "audio/aac" + "audio/ac3" + "audio/aiff" + "audio/AMR" + "audio/amr-wb" + "audio/dv" + "audio/eac3" + "audio/flac" + "audio/m3u" + "audio/m4a" + "audio/mp1" + "audio/mp2" + "audio/mp3" + "audio/mp4" + "audio/mpeg" + "audio/mpeg2" + "audio/mpeg3" + "audio/mpegurl" + "audio/mpg" + "audio/musepack" + "audio/ogg" + "audio/opus" + "audio/rn-mpeg" + "audio/scpls" + "audio/vnd.dolby.heaac.1" + "audio/vnd.dolby.heaac.2" + "audio/vnd.dts" + "audio/vnd.dts.hd" + "audio/vnd.rn-realaudio" + "audio/vorbis" + "audio/wav" + "audio/webm" + "audio/x-aac" + "audio/x-adpcm" + "audio/x-aiff" + "audio/x-ape" + "audio/x-m4a" + "audio/x-matroska" + "audio/x-mp1" + "audio/x-mp2" + "audio/x-mp3" + "audio/x-mpegurl" + "audio/x-mpg" + "audio/x-ms-asf" + "audio/x-ms-wma" + "audio/x-musepack" + "audio/x-pls" + "audio/x-pn-au" + "audio/x-pn-realaudio" + "audio/x-pn-wav" + "audio/x-pn-windows-pcm" + "audio/x-realaudio" + "audio/x-scpls" + "audio/x-shorten" + "audio/x-tta" + "audio/x-vorbis" + "audio/x-vorbis+ogg" + "audio/x-wav" + "audio/x-wavpack" + "video/3gp" + "video/3gpp" + "video/3gpp2" + "video/avi" + "video/divx" + "video/dv" + "video/fli" + "video/flv" + "video/mkv" + "video/mp2t" + "video/mp4" + "video/mp4v-es" + "video/mpeg" + "video/msvideo" + "video/ogg" + "video/quicktime" + "video/vnd.divx" + "video/vnd.mpegurl" + "video/vnd.rn-realvideo" + "video/webm" + "video/x-avi" + "video/x-flc" + "video/x-flic" + "video/x-flv" + "video/x-m4v" + "video/x-matroska" + "video/x-mpeg2" + "video/x-mpeg3" + "video/x-ms-afs" + "video/x-ms-asf" + "video/x-msvideo" + "video/x-ms-wmv" + "video/x-ms-wmx" + "video/x-ms-wvxvideo" + "video/x-ogm" + "video/x-ogm+ogg" + "video/x-theora" + "video/x-theora+ogg")) + +(define image-mime + '("image/avif" + "image/bmp" + "image/gif" + "image/heif" + "image/jpeg" + "image/jpg" + "image/pjpeg" + "image/png" + "image/tiff" + "image/x-bmp" + "image/x-pcx" + "image/x-png" + "image/x-portable-anymap" + "image/x-portable-bitmap" + "image/x-portable-graymap" + "image/x-portable-pixmap" + "image/x-tga" + "image/x-xbitmap")) + +(define pdf-mime + '("application/pdf" + "application/epub+zip")) + +(define torrent-mime + '("application/x-bittorrent" + "x-scheme-handler/magnet")) + +(define mime-app-alist + (apply append + (map (lambda (app types) + (map (lambda (e) (cons e (cdr app))) types)) + `(,default-browser + ,default-editor + ,default-editor + ,default-media + ,default-image + ,default-pdf + ,default-torrent) + `(,browser-mime + ,editor-mime + ,file-manager-mime + ,media-mime + ,image-mime + ,pdf-mime + ,torrent-mime)))) + +;;; app-preferences.scm ends here diff --git a/kolwynia/home/bdunahu/files/.config/emacs/early-init.el b/kolwynia/home/bdunahu/files/.config/emacs/early-init.el new file mode 100644 index 0000000..037dc17 --- /dev/null +++ b/kolwynia/home/bdunahu/files/.config/emacs/early-init.el @@ -0,0 +1,38 @@ +;;; -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + + +;;;; display load information + speedups +(defun bd/display-startup-time () + (message "Emacs loaded in %s with %d garbage collections." + (format "%.2f seconds" + (float-time + (time-subtract after-init-time before-init-time))) + gcs-done)) + +(add-hook 'emacs-startup-hook #'bd/display-startup-time) + +(setq frame-inhibit-implied-resize t) + +;; reduce the frequency of garbage collection during startup +;; by making it happen as little as possible +;; TODO: `most-positive-fixnum' will pressure system memory if used +;; as a permanent value +(setopt gc-cons-threshold most-positive-fixnum + gc-cons-percentage 0.5) + +(add-hook 'emacs-startup-hook + (lambda () + (setopt gc-cons-threshold (* 1024 1024 20) + gc-cons-percentage 0.2))) + + +;;;; avoid-blinding startup +(push '(menu-bar-lines . 0) default-frame-alist) +(push '(tool-bar-lines . 0) default-frame-alist) +(push '(background-color . "#000000") default-frame-alist) +(push '(foreground-color . "#ffffff") default-frame-alist) + + +;;; early-init.el ends here diff --git a/kolwynia/home/bdunahu/files/.config/emacs/gnus.el b/kolwynia/home/bdunahu/files/.config/emacs/gnus.el new file mode 100644 index 0000000..8482ec9 --- /dev/null +++ b/kolwynia/home/bdunahu/files/.config/emacs/gnus.el @@ -0,0 +1,65 @@ +;;; -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + + +(require 'pgg) +(require 'gnus) +(require 'gnus-util) + +(keymap-set gnus-article-mode-map "r" #'gnus-summary-very-wide-reply) +(keymap-set gnus-summary-mode-map "r" #'gnus-summary-very-wide-reply) +(keymap-set gnus-article-mode-map "R" #'gnus-summary-very-wide-reply-with-original) +(keymap-set gnus-summary-mode-map "R" #'gnus-summary-very-wide-reply-with-original) + +(setopt gnus-dbus-close-on-sleep t + gnus-interactive-exit nil + + gnus-check-new-newsgroups nil + gnus-large-newsgroup 200 + + message-kill-buffer-on-exit t + message-interactive t + + message-directory "/home/bdunahu/.ml/" + + message-send-mail-function 'message-send-mail-with-sendmail + message-sendmail-f-is-evil 't + sendmail-program "/home/bdunahu/.guix-home/profile/bin/msmtp" + message-sendmail-extra-arguments '("--read-envelope-from")) + +(setopt gnus-select-method '(nnnil "")) +(setopt gnus-secondary-select-methods + '((nntp "news.gwene.org") + (nnmaildir "admin" + (directory "~/.ml/admin")) + (nnmaildir "personal" + (directory "~/.ml/personal")) + (nnmaildir "rss" + (directory "~/.ml/rss")) + (nnmaildir "umass" + (directory "~/.ml/umass")))) + + +(setopt gnus-face-3 'calendar-today + gnus-face-4 'calendar-weekend-header + gnus-face-5 'calendar-weekday-header) + +(setopt gnus-summary-line-format + (concat + "%0{%U%R%z%}" + "%4{%-11,11&user-date;%}" + " " + "%2{%-20,20n%}" ;; name + " " + " " + "%5{%B%}" + "%s\n")) + +(setopt message-from-style 'angles + mml-secure-openpgp-encrypt-to-self t + mml-secure-openpgp-sign-with-sender t) +(add-hook 'gnus-message-setup-hook 'mml-secure-message-sign-pgpmime) + + +;;; gnus.el ends here diff --git a/kolwynia/home/bdunahu/files/.config/emacs/images/raven.png b/kolwynia/home/bdunahu/files/.config/emacs/images/raven.png Binary files differnew file mode 100644 index 0000000..6f27c08 --- /dev/null +++ b/kolwynia/home/bdunahu/files/.config/emacs/images/raven.png diff --git a/kolwynia/home/bdunahu/files/.config/emacs/images/wolf.png b/kolwynia/home/bdunahu/files/.config/emacs/images/wolf.png Binary files differnew file mode 100644 index 0000000..fabad74 --- /dev/null +++ b/kolwynia/home/bdunahu/files/.config/emacs/images/wolf.png diff --git a/kolwynia/home/bdunahu/files/.config/emacs/init.el b/kolwynia/home/bdunahu/files/.config/emacs/init.el new file mode 100644 index 0000000..7243419 --- /dev/null +++ b/kolwynia/home/bdunahu/files/.config/emacs/init.el @@ -0,0 +1,127 @@ +;;; -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + + +;;;; auto-generated files +;; disable the custom file by making it temporary +(setopt custom-file (make-temp-file "emacs-custom-") + tramp-auto-save-directory (expand-file-name "tmp/auto_saves/sessions/" user-emacs-directory) + ;; disable lockfiles + create-lockfiles nil + ;; move auto-saves to tmp folder + auto-save-list-file-prefix (expand-file-name "tmp/auto_saves/sessions/" user-emacs-directory) + auto-save-file-transforms `((".*" ,(expand-file-name "tmp/auto_saves/" user-emacs-directory) t)) + ;; move backups to tmp folder + backup-directory-alist `(("." . ,(expand-file-name "tmp/backups/" user-emacs-directory)))) +(make-directory (expand-file-name "tmp/auto_saves/" user-emacs-directory) t) + +(setenv "PATH" (format "%s:%s" (expand-file-name "~/.local/bin/") (getenv "PATH"))) + +(keymap-global-unset "C-z") +(keymap-global-unset "C-x C-z") +(keymap-global-set "C-x C-b" #'ibuffer) +(keymap-global-set "C-c SPC" #'pop-to-mark-command) + +(mapc + (lambda (command) + (put command 'disabled nil)) + '(upcase-region downcase-region)) + +(setopt warning-minimum-level :error + + inhibit-startup-message t + initial-major-mode 'eshell-mode + initial-scratch-message nil + + text-scale-mode-step 1.1 + + set-mark-command-repeat-pop t + + kill-whole-line t + kill-ring-max 1000 + undo-limit 320000 + + sentence-end-double-space nil + next-line-add-newlines t + scroll-up-aggressively '0.50 + scroll-down-aggressively '0.50 + scroll-step 1 + + use-short-answers t + vc-follow-symlinks t + completion-ignore-case t + save-place-mode t + indent-tabs-mode nil + read-buffer-completion-ignore-case t) +(setq-default tab-width 8) +(add-to-list 'default-frame-alist '(alpha . (92 . 92))) +(blink-cursor-mode -1) +(fringe-mode '(0 . 0)) +(global-visual-line-mode t) +(menu-bar-mode -1) +(minibuffer-depth-indicate-mode 1) +(scroll-bar-mode -1) +(tool-bar-mode -1) +(tooltip-mode -1) +(add-hook #'before-save-hook #'delete-trailing-whitespace) + +(keymap-global-set "C-c m" #'gnus) +(setopt readmail-command 'gnus + mail-user-agent 'gnus-user-agent + + gnus-init-file (expand-file-name "gnus" user-emacs-directory) + gnus-home-directory (expand-file-name "gnus-home" user-emacs-directory) + gnus-directory (expand-file-name "News" gnus-home-directory) + mail-source-directory (expand-file-name "Mail" gnus-home-directory) + + gnus-save-newsrc-file nil + gnus-read-newsrc-file nil) + + +(if (file-directory-p "~/.guix-profile") + ;; packages installed via guix + (progn (setopt package-archives nil + package-enable-at-startup t) + (add-to-list 'load-path (expand-file-name "~/.guix-home/profile/share/emacs/site-lisp")) + (require 'guix-emacs) + (guix-emacs-autoload-packages) + (guix-prettify-global-mode 1) + (setopt guix-directory "/home/bdunahu/pt/guix")) + (require 'package) + (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t) + (package-initialize)) + + +;;;; add my modules to load path +(mapc + (lambda (path) + (add-to-list 'load-path (locate-user-emacs-file path))) + '("modules" "libraries")) + + +;;;; load modules +(require 'bd--utility) +(require 'bd--secret) ;; contains bookmarks/email vars---git ignored +(require 'bd--gpg) +(require 'bd--tabs) +(require 'bd--browse) +(require 'bd--project) +(require 'bd--files) +(require 'bd--dictionary) +(require 'bd--chat) +(require 'bd--shells) +(require 'bd--minibuffer) +(require 'bd--buffer) +(require 'bd--window) +(require 'bd--devel) +(require 'bd--org) +(require 'bd--notes) +(require 'bd--emms) +(require 'bd--modeline) +(if (not (string= (system-name) "surt")) + (require 'bd--exwm)) +(require 'bd--themes) + + +;;; init.el ends here diff --git a/kolwynia/home/bdunahu/files/.config/emacs/libraries/copyright.el b/kolwynia/home/bdunahu/files/.config/emacs/libraries/copyright.el new file mode 100644 index 0000000..112512d --- /dev/null +++ b/kolwynia/home/bdunahu/files/.config/emacs/libraries/copyright.el @@ -0,0 +1,35 @@ +;;; copyright.el --- Insert a Guix copyright. -*- lexical-binding: t; -*- + +;; Copyright © 2020 Oleg Pykhalov <go.wigust@gmail.com> + +;; This file is part of GNU Guix. + +;; GNU Guix is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Guix is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; This package provides skeleton to insert a copyright with `guix-copyright'. + +;;; Code: + +(define-skeleton guix-copyright + "Insert a copyright by $USER notice at cursor." + "FULL_NAME <MAIL_ADDRESS>: " + comment-start + ";; Copyright © " `(format-time-string "%Y") " " + (or (format "%s <%s>" user-full-name user-mail-address) str) + comment-end) + +(provide 'copyright) +;;; copyright.el ends here diff --git a/kolwynia/home/bdunahu/files/.config/emacs/libraries/exwm-outer-gaps.el b/kolwynia/home/bdunahu/files/.config/emacs/libraries/exwm-outer-gaps.el new file mode 100644 index 0000000..c315e8b --- /dev/null +++ b/kolwynia/home/bdunahu/files/.config/emacs/libraries/exwm-outer-gaps.el @@ -0,0 +1,77 @@ +;;; -*- lexical-binding: t; -*- +;;; Commentary: + +;; modified version of https://github.com/lucasgruss/exwm-outer-gaps + +;;; Code: + + +(require 'exwm-workspace) +(require 'exwm-core) +(require 'exwm) +(require 'xelb) +(require 'xcb) + +(defgroup exwm-outer-gaps nil + "Outer gaps for exwm." + :group 'appearance + :prefix "exwm-outer-gaps") + +(defcustom exwm-outer-gaps-width 15 + "Width between the edge of the monitor and emacs frame for all sides.") + +(defcustom exwm-outer-gaps-increment-step 5 + "Default increment/decrement value for gaps.") + +(defcustom exwm-outer-gaps-max-width + (* exwm-outer-gaps-increment-step 20) + "The maximum size of the gaps.") + +(defun exwm-outer-gaps-compute-gaps () + "Hook to be ran after exwm-workspace--update-workareas-hook" + (let (workareas frames) + (dolist (w exwm-workspace--workareas) + (setf (aref w 3) (+ (aref w 3) exwm-outer-gaps-width) + (aref w 4) (+ (aref w 4) exwm-outer-gaps-width) + (aref w 5) (- (aref w 5) (* 2 exwm-outer-gaps-width)) + (aref w 6) (- (aref w 6) (* 2 exwm-outer-gaps-width)))))) + +(defun exwm-outer-gaps-apply () + "Function used to apply gaps to the emacs frames." + (exwm-workspace--update-workareas) + (dolist (f exwm-workspace--list) + (exwm-workspace--set-fullscreen f))) + +(defun exwm-outer-gaps-set (width) + "Sets the gap width to WIDTH. Automatically clamps the size of the gaps +from 0 to `exwm-outer-max-gaps-width'" + (setq exwm-outer-gaps-width + (max 0 (min width exwm-outer-gaps-max-width)))) + +(defun exwm-outer-gaps-increment () + "Increment the outer gaps by exwm-outer-gaps-increment-step" + (interactive) + (when exwm-outer-gaps-mode + (exwm-outer-gaps-set (+ exwm-outer-gaps-width exwm-outer-gaps-increment-step)) + (exwm-outer-gaps-apply))) + +(defun exwm-outer-gaps-decrement () + "Decrement the outer gaps by exwm-outer-gaps-increment-step" + (interactive) + (when exwm-outer-gaps-mode + (exwm-outer-gaps-set (- exwm-outer-gaps-width exwm-outer-gaps-increment-step)) + (exwm-outer-gaps-apply))) + +;;;###autoload +(define-minor-mode exwm-outer-gaps-mode + "Add useless outer gaps to exwm." + :global t + (if exwm-outer-gaps-mode + (add-hook 'exwm-workspace--update-workareas-hook + #'exwm-outer-gaps-compute-gaps) + (remove-hook 'exwm-workspace--update-workareas-hook + #'exwm-outer-gaps-compute-gaps)) + (exwm-outer-gaps-apply)) + + +(provide 'exwm-outer-gaps) diff --git a/kolwynia/home/bdunahu/files/.config/emacs/libraries/fill-column.el b/kolwynia/home/bdunahu/files/.config/emacs/libraries/fill-column.el new file mode 100644 index 0000000..2a70cd6 --- /dev/null +++ b/kolwynia/home/bdunahu/files/.config/emacs/libraries/fill-column.el @@ -0,0 +1,39 @@ +;;; -*- lexical-binding: t; -*- +;;; Commentary: + +;; yanked from https://codeberg.org/daviwil/dotfiles/src/branch/master/emacs + +;;; Code: + + +(defvar fill-column-desired-width 120 + "The desired width of a document centered in the window.") + +(defun fill-column--adjust-margins () + "Resets window margins, then calculates the appropriate +margin given the window width and `fill-column-desired-width' +if fill-column-mode is t." + (set-window-parameter nil 'min-margins nil) + (set-window-margins nil nil) + (when fill-column-mode + (let ((margin-width (max 0 + (truncate + (/ (- (window-width) + fill-column-desired-width) + 2.0))))) + (when (> margin-width 0) + (set-window-parameter nil 'min-margins '(0 . 0)) + (set-window-margins nil margin-width margin-width))))) + +(define-minor-mode fill-column-mode + "Toggle centered text layout in the current buffer." + :lighter " Centered" + :group 'editing + (if fill-column-mode + (add-hook 'window-configuration-change-hook #'fill-column--adjust-margins 'append 'local) + (remove-hook 'window-configuration-change-hook #'fill-column--adjust-margins 'local)) + (fill-column--adjust-margins)) + + +(provide 'fill-column) +;;; fill-column ends here diff --git a/kolwynia/home/bdunahu/files/.config/emacs/libraries/powerthesaurus.el b/kolwynia/home/bdunahu/files/.config/emacs/libraries/powerthesaurus.el new file mode 100644 index 0000000..2c76df0 --- /dev/null +++ b/kolwynia/home/bdunahu/files/.config/emacs/libraries/powerthesaurus.el @@ -0,0 +1,940 @@ +;;; powerthesaurus.el --- Powerthesaurus integration -*- lexical-binding: t; -*- + +;; Copyright (c) 2018-2023 Valeriy Savchenko (GNU/GPL Licence) + +;; Authors: Valeriy Savchenko <sinmipt@gmail.com> +;; URL: http://github.com/SavchenkoValeriy/emacs-powerthesaurus +;; Version: 0.4.1 +;; Package-Requires: ((emacs "26.1") (jeison "1.0.0") (s "1.13.0")) +;; Keywords: convenience, writing + +;; This file is NOT part of GNU Emacs. + +;; powerthesaurus.el is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; powerthesaurus.el is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with powerthesaurus.el. +;; If not, see <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;;; This package is an integration with powerthesaurus.org. +;;; It helps to look up a word in powerthesaurus and either replace or +;;; insert selected option in the buffer (depending on the current selection). + +;;; Code: +(require 'eieio) +(require 'cl-seq) +(require 'url) +(require 's) +(require 'subr-x) +(require 'jeison) + +(defvar powerthesaurus-request-headers + '(("Content-Type" . "application/json")) + "List of headers included in the request sent to 'powerthesaurus.org'.") + +(defvar powerthesaurus-user-agent "Chrome/74.0.3729.169") + +(defvar powerthesaurus-synchronous-requests nil + "If non-nil, requests send to 'powerthesaurus.org' are synchronous.") + +(defvar powerthesaurus-show-tags t + "Whether to show word tags during completion.") + +(defvar powerthesaurus-show-part-of-speech t + "Whether to show word's part of speech during completion.") + +(defvar powerthesaurus-show-rating t + "Whether to show word's rating during completion.") + +(defconst powerthesaurus-supported-query-types + (list :synonyms :antonyms :related :definitions :sentences)) + +(defconst powerthesaurus-api-url "https://api.powerthesaurus.org") + +(defface powerthesaurus-definition-part-of-speech + '((t :inherit font-lock-keyword-face)) + "Face of the definition's part of speech." + :group 'powerthesaurus) + +(defface powerthesaurus-definition-definition + '((t :weight bold)) + "Face of the actual definition part of the definition." + :group 'powerthesaurus) + +(defface powerthesaurus-definition-usages + '((t :inherit font-lock-comment-face)) + "Face of the usage example for the definition." + :group 'powerthesaurus) + +(defface powerthesaurus-definition-synonyms + '((t :inherit font-lock-type-face)) + "Face of the definition's synonyms." + :group 'powerthesaurus) + +(defface powerthesaurus-definition-author + '((t :inherit default)) + "Face of the definition's author." + :group 'powerthesaurus) + +(defface powerthesaurus-sentence-sentence + '((t :weight bold)) + "Face of the example sentence." + :group 'powerthesaurus) + +(defface powerthesaurus-sentence-author + '((t :inherit default)) + "Face of the example sentence author." + :group 'powerthesaurus) + +;;;###autoload +(defun powerthesaurus-lookup-dwim (&optional action-type query-type) + "Wrapper function for general lookup commands. + +When called interactively, optional argument ACTION-TYPE corresponds to +the prefix argument passed to this command, which is translated to an action +using `powerthesaurus-prefix-to-action'. When called programmatically, +its value can either be nil or a symbol that can be possibly returned by +`powerthesaurus-prefix-to-action' (e.g., `action-insert' or `action-display'). + +The argument passed to QUERY-TYPE should be the same as in +`powerthesaurus-lookup' or nil; in the latter case, +the user will be prompt for a valid value." + (interactive "P") + (pcase-let ((`(,query-term ,beg ,end) + ;; selection is active -> look up whatever is selected + (if (use-region-p) + (powerthesaurus--extract-query-region) + ;; point is is at a word -> look it up + (if (thing-at-point 'word) + (powerthesaurus--extract-original-word) + ;; nothing appropriate nearby -> ask the user + (list nil nil nil))))) + (setq query-term (read-string "Term: " query-term) + query-type (or query-type + (intern (completing-read "Query type: " + powerthesaurus-supported-query-types + nil t))) + action-type (powerthesaurus-prefix-to-action action-type query-type)) + (cond + ((eq action-type 'action-insert) + (when (null beg) + (setq beg (point) end (point)))) + ((eq action-type 'action-display) + (when (or beg end) + (setq beg nil end nil)))) + (funcall 'powerthesaurus-lookup query-term query-type beg end))) + +;;;###autoload +(defun powerthesaurus-lookup-synonyms-dwim (&optional action-type) + "Wrapper function for synonym lookup. +ACTION-TYPE accepts the same arguments as in `powerthesaurus-lookup-dwim'." + (interactive "P") + (powerthesaurus-lookup-dwim action-type :synonyms)) + +;;;###autoload +(defun powerthesaurus-lookup-antonyms-dwim (&optional action-type) + "Wrapper function for antonym lookup. +ACTION-TYPE accepts the same arguments as in `powerthesaurus-lookup-dwim'." + (interactive "P") + (powerthesaurus-lookup-dwim action-type :antonyms)) + +;;;###autoload +(defun powerthesaurus-lookup-related-dwim (&optional action-type) + "Wrapper function for related lookup. +ACTION-TYPE accepts the same arguments as in `powerthesaurus-lookup-dwim'." + (interactive "P") + (powerthesaurus-lookup-dwim action-type :related)) + +;;;###autoload +(defun powerthesaurus-lookup-definitions-dwim (&optional action-type) + "Wrapper function for definition lookup. +ACTION-TYPE accepts the same arguments as in `powerthesaurus-lookup-dwim'." + (interactive "P") + (powerthesaurus-lookup-dwim action-type :definitions)) + +;;;###autoload +(defun powerthesaurus-lookup-sentences-dwim (&optional action-type) + "Wrapper function for sentence lookup. +ACTION-TYPE accepts the same arguments as in `powerthesaurus-lookup-dwim'." + (interactive "P") + (powerthesaurus-lookup-dwim action-type :sentences)) + +;;;###autoload +(defun powerthesaurus-lookup (query-term query-type &optional beg end) + "Retrieve the given QUERY-TERM's synonyms, antonyms, etc... online. + +Argument QUERY-TYPE specifies the type of query and must be an element of +`powerthesaurus-supported-query-types'. +QUERY-TERM corresponds to the word/term/sentence to look up. + +If specified, BEG and END specify the beginning and end positions of +the text in the buffer to be replaced by the selected result. +Particularly, if both BEG and END are both nil, then the results of the queries +will be displayed on a distinct buffer. If only BEG is specified or +both BEG and END are the same, then the user will be prompted to select one of +the results to be inserted at BEG. Finally, if both BEG and END are specified +and are different, then the user will be prompted to select a result +which will replace the text between these bounds." + (powerthesaurus--query + query-term + query-type + (powerthesaurus--make-callback query-term query-type beg end))) + +;; =============================================================== +;; UX functions implementation +;; =============================================================== + +(defun powerthesaurus-prefix-to-action (uarg qtype) + "Map given prefix argument UARG to corresponding action type. + +A single universal argument (\\[universal-argument]) indicates that +the result of the query should be inserted at point, +potentially replacing the word under it or the selected phrase. +This corresponds to returning the symbol `action-insert'. + +A double universal argument (\\[universal-argument] \\[universal-argument]) +indicates that the results of the query should be displayed on +a separate buffer without modifying the current one. +This corresponds to returning the symbol `action-display'. + +If no prefix argument is given, +then the type of the query specified via QTYPE is used for +determining the action that should be preferred. +Particularly, if the type is one of 'synonyms', 'antonyms' or 'related', +then the result defaults to `action-insert'. +In any other case, it defaults to `action-display'." + (cond + ((null uarg) + (if (member qtype '(:synonyms :antonyms :related)) + 'action-insert + 'action-display)) + ((memq uarg '(action-insert action-display)) uarg) + ((equal uarg '(4)) 'action-insert) + ((equal uarg '(16)) 'action-display) + (t (error "Unexpected prefix argument")))) + +(defun powerthesaurus--extract-original-word (&optional pnt) + "Parse the word under point to look up. + +If optional argument PNT is not specified, +default to cursor's current location." + (setq pnt (or pnt (point))) + (save-mark-and-excursion + (goto-char pnt) + (unless (looking-at-p "\\<") + (backward-word)) + (let (beg end) + (setq beg (point)) + (forward-word) + (setq end (point)) + (powerthesaurus--extract-query-region beg end)))) + +(defun powerthesaurus--extract-query-region (&optional beg end) + "Parse the phrase in region. + +If optional arguments BEG and END are not specified, +the contents of the current active region are used." + (cl-flet ((substring-and-bounds + (lambda (beg end) + (list (buffer-substring-no-properties beg end) + beg end)))) + ;; If *either* BEG or END have been specified, + ;; then try to get the specified substring. + ;; Notice that in case only one of them has been passed, + ;; then `buffer-substring-no-properties' will take care of throwing an error. + (if (or beg end) + (substring-and-bounds beg end) + (if (use-region-p) + (substring-and-bounds (region-beginning) (region-end)) + (error "Failed parsing query term from active region"))))) + +(defun powerthesaurus--read-query-term (&optional prompt) + "Ask the user for which word to look up. +If PROMPT is not specified, a default one will be used." + (setq prompt (or prompt "Term: ")) + (list (substring-no-properties (read-string prompt)) nil nil)) + +(defun powerthesaurus--make-callback (query-term query-type + &optional beg end) + "Generate a callback to be executed upon successful completion of request. + +If BEG and/or END are non-nil, then `powerthesaurus--make-insert-callback' +will be used as the underlying callback generator, otherwise it defaults to +`powerthesaurus--make-display-callback'. + +QUERY-TYPE and QUERY-TERM will be passed to +the underlying callback generator, possibly altering its behavior to +better accommodate the corresponding type of query." + (cond + ((or beg end) + (powerthesaurus--make-insert-callback query-term query-type + (current-buffer) + beg end)) + (t + (powerthesaurus--make-display-callback query-term query-type)))) + +(defun powerthesaurus--make-insert-callback (query-term + query-type + buffer beg end) + "Generate a callback that will insert the query's result to buffer. + +The callback generated by this function accepts the data belonging to +the response to a previously made request as its sole argument. + +If END is nil or BEG and END are equal, +the generated callback will prompt the user to select a returned result and +insert it at point. +Otherwise, if BEG and END differ, +then the region between these points will be replaced by the selected result. +BEG must be non-nil. + +BUFFER is the buffer object where term will be replaced and +should be explicitly specified since, in case of asynchronous execution, +the callback may be executed with cursor under a different buffer. + +QUERY-TERM corresponds to the text to be replaced by +the generated callback, and BEG and END correspond to the substituted text's +beginning and ending positions within the buffer. + +QUERY-TYPE must be an element of `powerthesaurus-supported-query-types' and +is used for determining how to parse the aforementioned data. +In general, its argument should be the same as the type specified when +creating the corresponding request." + (let ((backend (if (or (null end) + (equal beg end)) + (lambda (new original) + (with-current-buffer buffer + (powerthesaurus--insert-text new original))) + (lambda (new original) + (with-current-buffer buffer + (powerthesaurus--replace-text new beg end original)))))) + (lambda (results) + (funcall backend + (powerthesaurus--select-candidate results) + query-term)))) + +(defun powerthesaurus--make-display-callback (query-term query-type) + "Generate a callback that will display the query's results to another buffer. + +The callback generated by this function accepts the data belonging to +the response to a previously made request as its sole argument. +The results of the query will then be extracted and displayed on +a different buffer. + +QUERY-TERM corresponds to the original text that was queried online. + +QUERY-TYPE must be an element of `powerthesaurus-supported-query-types' and +is used for determining how to parse the aforementioned data. +In general, its argument should be the same as the type specified when +creating the corresponding request. +Additionally, it affects aspects of the generated callback's behavior, +such as the default string used for separating the results displayed +in the buffer." + (lambda (results) + (powerthesaurus--display-results + results + query-term + query-type))) + +(defun powerthesaurus--replace-text (replacement beg end original) + "Pick an alternative from response and replace the selected text. + +REPLACEMENT corresponds to the new text to be inserted in place of ORIGINAL. +BEG and END correspond to the bounds of the selected text to be replaced." + (delete-region beg end) + (powerthesaurus--insert-text replacement original (min beg end))) + +(defun powerthesaurus--preprocess-text (text reference) + "Adjust cases of TEXT according to REFERENCE. + +For now, it supports upcasing and capitalization." + (cond ((s-uppercase-p reference) (upcase text)) + ((s-capitalized-p reference) (capitalize text)) + (t text))) + +(defun powerthesaurus--insert-text (text reference &optional pnt) + "Insert TEXT at the point after preprocessing it according to REFERENCE. + +REFERENCE corresponds to the term whose query yielded TEXT. + +If optional argument PNT is given, the insert text there. Otherwise, +insert text under cursor." + (when pnt (goto-char pnt)) + (insert (powerthesaurus--preprocess-text text reference))) + +(defun powerthesaurus--insert-definition-as-text (definition) + "Insert given lookup DEFINITION as text into the current buffer." + (let ((pos (string-join (mapcar + (lambda (index) + (propertize + (oref (powerthesaurus--part-of-speech-of-index index) singular) + 'face 'powerthesaurus-definition-part-of-speech)) + (oref definition pos)) + ", ")) + (usages (string-join (mapcar (lambda (usage) + (propertize + (format "%S" usage) + 'face 'powerthesaurus-definition-usages)) + (oref definition usages)) + "\n")) + (definition (propertize (oref definition text) + 'face 'powerthesaurus-definition-definition)) + (author (propertize (oref definition author) + 'face 'powerthesaurus-definition-author)) + (synonyms (string-join (mapcar (lambda (synonym) + (propertize + synonym + 'face 'powerthesaurus-definition-synonyms)) + (oref definition synonyms)) + ", "))) + (when (> (length pos) 0) + (insert pos "\n\n")) + (insert definition "\n\n") + (when (> (length usages) 0) + (insert usages "\n\n")) + (when (> (length synonyms) 0) + (insert "synonyms: " synonyms "\n\n")) + (insert author))) + +(defun powerthesaurus--insert-sentence-as-text (sentence) + "Insert given lookup SENTENCE as text into the current buffer." + (let ((text (propertize (oref sentence text) + 'face 'powerthesaurus-sentence-sentence)) + (author (propertize (oref sentence author) + 'face 'powerthesaurus-sentence-author))) + (insert text) + (when (and (> (length author) 0) (not (string= author "unknown"))) + (insert "\n\n" author)))) + +(defun powerthesaurus--insert-as-text (result) + "Insert given lookup RESULT as text into the current buffer." + (cond + ((powerthesaurus-definition-p result) + (powerthesaurus--insert-definition-as-text result)) + ((powerthesaurus-sentence-p result) + (powerthesaurus--insert-sentence-as-text result)) + (t (insert (oref result text))))) + +(defun powerthesaurus--display-results (results query-term query-type + &optional sep) + "Display results on a dedicated buffer. + +RESULTS must be a list of `powerthesaurus-result' instances. +QUERY-TERM and QUERY-TYPE must be the text that was queried online +and the corresponding query type that yielded the results to be displayed. + +Optional argument SEP is the string that will be used to separate +the displayed results in the buffer. If not specified, +its default value varies depending on value of QUERY-TYPE." + (unless sep + (cond + ((member query-type '(:definitions :sentences)) + (setq sep "\n────────────────\n")) + (t (setq sep "\n")))) + (let* ((buf-name (format "*Powerthesaurus - \"%s\" - %s*" + query-term query-type)) + (buf-exists (get-buffer buf-name)) + (buf (or buf-exists (get-buffer-create buf-name)))) + (with-current-buffer buf + (when buf-exists + (fundamental-mode) + (read-only-mode -1) + (erase-buffer)) + (dolist (elt results) + (powerthesaurus--insert-as-text elt) + (insert "\n" + sep + (propertize "\014" 'display "") + "\n")) + (help-mode) + (goto-char (point-min))) + (pop-to-buffer buf))) + +(defun powerthesaurus--compose-completion-candidate (result) + "Compose completion candidate out of the given RESULT. + +RESULT should be an instance of `powerthesaurus-result'." + (let* ((text (oref result text)) + (rating (format "%s★ " (oref result rating)))) + (propertize text 'line-prefix rating))) + +(defun powerthesaurus--compose-completion-candidates (results) + "Compose completion candidates out of the given RESULTS. + +RESULT should be a list of `powerthesaurus-result'." + (if (not powerthesaurus-show-rating) + (mapcar (lambda (result) (oref result text)) results) + (let* ((ratings (mapcar + (lambda (result) (number-to-string (oref result rating))) + results)) + (maxlen (cl-reduce #'max (mapcar #'length ratings)))) + (cl-mapcar (lambda (result rating) + (let* ((len (length rating)) + (padding-len (1+ (- maxlen len))) + (padding (make-string padding-len ? )) + (rating-pretty (format "%s★%s" rating padding))) + (propertize (oref result text) 'line-prefix rating-pretty))) + results ratings)))) + +(defun powerthesaurus--annotate-candidate (candidate max-candidate-length) + "Annotate given completion CANDIDATE. + +MAX-CANDIDATE-LENGTH is the maximum length among all candidates, it is required +for proper annotation alignment." + (let* ((tags (string-join (oref candidate tags) ", ")) + (padding-len (- max-candidate-length (length (oref candidate text)))) + (padding (make-string padding-len ? )) + (pos (string-join (mapcar + (lambda (index) + (oref (powerthesaurus--part-of-speech-of-index index) shorter)) + (oref candidate pos)) + ", ")) + (annotation "")) + (when (and powerthesaurus-show-part-of-speech (> (length pos) 0)) + (setq annotation pos)) + (when (and powerthesaurus-show-tags (> (length tags) 0)) + (setq annotation (concat annotation "\t#" tags))) + (if (> (length annotation) 0) + (concat padding "\t\t\t" annotation) + ""))) + +(defun powerthesaurus--select-candidate (candidates) + "Prompt the user to select one of the CANDIDATES returned from a query." + (let* ((candidates-processed (powerthesaurus--compose-completion-candidates candidates)) + (candidates-by-text (mapcar + (lambda (candidate) `(,(oref candidate text) . ,candidate)) + candidates)) + (maxlen (cl-reduce #'max (mapcar + (lambda (candidate) (length (oref candidate text))) + candidates))) + ;; this is the only way we can keep the order while using + ;; the default implementation of completing-read function + ;; see: https://emacs.stackexchange.com/a/41808/23751 + (completion-table + (lambda (string pred action) + (if (eq action 'metadata) + `(metadata (display-sort-function . identity) + (cycle-sort-function . identity) + (annotation-function . ,(lambda (text) + (powerthesaurus--annotate-candidate + (assoc-default text candidates-by-text) + maxlen)))) + (complete-with-action + action candidates-processed string pred)))) + ;; ivy still will try to sort it lexicographically: deny it + (ivy-sort-functions-alist '((t . (lambda (x y) 0)))) + ;; ivy-rich can mess up our efforts of displaying rating + (ivy--display-transformers-alist nil)) + ;; If we try to call completing-read with an active company popup, + ;; we inherit its key map. That leads to some funny bugs (see issue#33). + (when (fboundp 'company-uninstall-map) + (company-uninstall-map)) + (substring-no-properties + (completing-read "Choose a candidate: " completion-table nil nil)))) + +;; =============================================================== +;; Requests and JSON parsing +;; =============================================================== + +(defclass powerthesaurus--part-of-speech nil + ((singular :initarg :singular :type string) + (plural :initarg :plural :type string) + (shorter :initarg :shorter :type string))) + +(defconst powerthesaurus-parts-of-speech + (vector + (powerthesaurus--part-of-speech :singular "adjective" + :plural "adjectives" + :shorter "adj.") + (powerthesaurus--part-of-speech :singular "noun" + :plural "nouns" + :shorter "n.") + (powerthesaurus--part-of-speech :singular "pronoun" + :plural "pronouns" + :shorter "pr.") + (powerthesaurus--part-of-speech :singular "adverb" + :plural "adverbs" + :shorter "adv.") + (powerthesaurus--part-of-speech :singular "idiom" + :plural "idioms" + :shorter "idi.") + (powerthesaurus--part-of-speech :singular "verb" + :plural "verbs" + :shorter "v.") + (powerthesaurus--part-of-speech :singular "interjection" + :plural "interjections" + :shorter "int.") + (powerthesaurus--part-of-speech :singular "phrase" + :plural "phrases" + :shorter "phr.") + (powerthesaurus--part-of-speech :singular "conjunction" + :plural "conjunctions" + :shorter "conj.") + (powerthesaurus--part-of-speech :singular "preposition" + :plural "prepositions" + :shorter "prep.") + (powerthesaurus--part-of-speech :singular "phrasal verb" + :plural "phrasal verbs" + :shorter "phr. v.")) + "All parts of speech supported by powerthesaurus.") + +(defun powerthesaurus--part-of-speech-of-index (index) + "Return the POS info for the given API INDEX." + (elt powerthesaurus-parts-of-speech (1- index))) + +(jeison-defclass powerthesaurus-result nil + ((text :initarg :text :type string :path (node targetTerm name) + :documentation "Actual text of the word from Powerthesaurus") + (rating :initarg :rating :type number :path (node rating) + :documentation "User rating of the word") + (tags :initarg :tags :type (list-of string) :path (node relations tags) + :documentation "Tags of the word") + (pos :initarg :pos :type (list-of number) :path (node relations parts_of_speech) + :documentation "Parts of speech indicies (1-based) of the word"))) + +(defun powerthesaurus--get-synonym-names (json-array) + "For the given synonym JSON-ARRAY, return its name as string." + (mapcar (lambda (json) (jeison-read 'string json '(name))) json-array)) + +(jeison-defclass powerthesaurus-definition nil + ((text :initarg :text :type string :path (node definition) + :documentation "Definition from Powerthesaurus") + (rating :initarg :rating :type number :path (node rating) + :documentation "User rating of the definition") + (synonyms :initarg :synonyms :type (list-of string) + :path (node (powerthesaurus--get-synonym-names synonyms)) + :documentation "List of synonyms for the definition") + (usages :initarg :usages :type (list-of string) :path (node usages) + :documentation "List of usages for the definition") + (author :initarg :author :type string :path (node author title) + :documentation "Original author of the definition") + (pos :initarg :pos :type (list-of number) :path (node partsOfSpeech) + :documentation "Parts of speech indicies (1-based) of the definition"))) + +(jeison-defclass powerthesaurus-sentence nil + ((text :initarg :text :type string :path (node sentence) + :documentation "Sentence example from Powerthesaurus") + (rating :initarg :rating :type number :path (node rating) + :documentation "User rating of the sentence") + (author :initarg :author :type string :path (node author title) + :documentation "Original author of the sentence"))) + +(defun powerthesaurus--query (term type &optional callback sync) + "Make a query to Powerthesaurus. + +TERM is the main text of the query. +TYPE should be a query type for thesaurus (e.g. ':synonyms' or ':related'). +CALLBACK gets called whenever the response is received and processed. +SYNC is t for synchronous version of the request." + (let ((query (pcase type + ((pred powerthesaurus--is-thesaurus-query-type) + #'powerthesaurus--query-thesaurus) + (:definitions #'powerthesaurus--query-definition) + (:sentences #'powerthesaurus--query-sentence) + (_ (error "Unknown query type '%s'" type))))) + (funcall query term type callback sync))) + +(defun powerthesaurus--request-term-id (term callback &optional sync) + "Request id for the given TERM. + +CALLBACK gets called whenever the response is received and processed. +SYNC is t for synchronous version of the request. + +Powerthesaurus APIs require explicit IDs assigned to every term. +This request fetches it for the further use." + (powerthesaurus--query-impl + `(("query" . ,term)) + powerthesaurus--search-query + callback + (lambda (data) (jeison-read t data '(data search terms 0 id))) + sync)) + +(defmacro powerthesaurus--with-term-id (term name sync &rest body) + "Request id for the given TERM, bind it to NAME, and execute BODY. + +TERM is the term to get ID for. +SYNC is t for synchronous version of the request." + (declare (indent 3) (debug t)) + `(let ((on-success + (lambda (,name) + ,@body))) + (powerthesaurus--request-term-id ,term on-success ,sync))) + +(defun powerthesaurus--query-thesaurus (term type &optional callback sync) + "Request thesaurus information from Powerthesaurus. + +TERM is the text to get definition for. +TYPE should be a query type for thesaurus (e.g. ':synonyms' or ':related'). +CALLBACK gets called whenever the response is received and processed. +SYNC is t for synchronous version of the request." + (powerthesaurus--with-term-id term term-id sync + (powerthesaurus--query-impl + `(("type" . ,(powerthesaurus--type-of-thesaurus-query type)) + ("termID" . ,term-id) + ("sort" . + (("field" . "RATING") + ("direction" . "DESC")))) + powerthesaurus--thesaurus-query + callback + (lambda (data) (jeison-read '(list-of powerthesaurus-result) data '(data thesauruses edges))) + sync))) + +(defun powerthesaurus--is-thesaurus-query-type (query-type) + "Return 't' if the given QUERY-TYPE is for thesaurus queries." + (member query-type '(:synonyms :antonyms :related))) + +(defun powerthesaurus--type-of-thesaurus-query (type) + "Return an API type corresponding to the given query TYPE." + (pcase type + (:synonyms "SYNONYM") + (:antonyms "ANTONYM") + (:related "RELATED") + (_ (error "Unknown thesaurus query type '%s'" type)))) + +(defun powerthesaurus--query-definition (term type &optional callback sync) + "Request definitions from Powerthesaurus. + +TERM is the text to get definition for. +TYPE should be nothing but ':definitions'. +CALLBACK gets called whenever the response is received and processed. +SYNC is t for synchronous version of the request." + (powerthesaurus--with-term-id term term-id sync + (powerthesaurus--query-impl + `(("termID" . ,term-id)) + powerthesaurus--definition-query + callback + (lambda (data) (jeison-read '(list-of powerthesaurus-definition) data '(data definitions edges))) + sync))) + +(defun powerthesaurus--query-sentence (term type &optional callback sync) + "Request sentences from Powerthesaurus. + +TERM is the text for sentence examples. +TYPE should be nothing but ':sentences'. +CALLBACK gets called whenever the response is received and processed. +SYNC is t for synchronous version of the request." + (powerthesaurus--with-term-id term term-id sync + (powerthesaurus--query-impl + `(("termID" . ,term-id)) + powerthesaurus--sentence-query + callback + (lambda (data) (jeison-read '(list-of powerthesaurus-sentence) data '(data sentences edges))) + sync))) + +(defun powerthesaurus--query-impl (variables query &optional callback postprocess sync) + "Request data from Powerthesaurus GraphQL API. + +VARIABLES is an alist of query-specific parameters. +QUERY is the actual GraphQL query. +CALLBACK gets called whenever the response is received and processed. +POSTPROCESS is the additional processing of the JSON response alist. +SYNC is t for synchronous version of the request." + (make-local-variable 'url-show-status) + (let* ((post (or postprocess 'identity)) + (sync (or (null callback) + sync + powerthesaurus-synchronous-requests)) + (url-request-data (json-encode `(("variables" . ,variables) + ("query" . ,query)))) + (url-request-extra-headers powerthesaurus-request-headers) + (url-request-method "POST") + ;; User agent has to be set separately like this, so that + ;; url-retrieve won't add anything else to it. + (url-user-agent powerthesaurus-user-agent) + ;; Prohibit it from writing "Contacting host:..." every + ;; time we send a request, it's not informative. + (url-show-status nil) + (callback (lambda (&rest _) + (with-local-quit + (let* ((raw (string-trim + (buffer-substring + url-http-end-of-headers (point-max)))) + ;; TODO: parse JSON more efficiently + ;; if native method is available + (json (json-read-from-string raw)) + (data (funcall post json))) + (funcall callback data)))))) + (if (not sync) + (url-retrieve powerthesaurus-api-url callback) + (with-current-buffer + (url-retrieve-synchronously powerthesaurus-api-url) + (funcall callback))))) + +(defun powerthesaurus--wrap-as-callback (fun) + "Wrap the given FUN function as a `request' callback." + (cl-function + (lambda (&key data &allow-other-keys) + ;; in order to allow users to quit powerthesaurus + ;; prompt with C-g, we need to wrap callback with this + (with-local-quit (funcall fun data))))) + +;; =============================================================== +;; Define old API's now deprecated functions. +;; =============================================================== + +;;;###autoload +(defun powerthesaurus-lookup-word-dwim () + "Wrapper function for powerthesaurus-lookup-word commands. + +If a region is selected use powerthesaurus-lookup-word +if a thing at point is not empty use powerthesaurus-lookup-word-at-point +otherwise as for word using powerthesaurus-lookup-word" + (interactive) + (let (beg end) + ;; selection is active -> look up whatever is selected + (if (use-region-p) + (progn + (setq beg (region-beginning)) + (setq end (region-end)) + (powerthesaurus-lookup-word beg end)) + ;; point is is at a word -> look it up + (if (thing-at-point 'word) + (powerthesaurus-lookup-word-at-point (point)) + ;; nothing appropriate nearby -> ask the user + (powerthesaurus-lookup-word))))) + +;;;###autoload +(defun powerthesaurus-lookup-word-at-point (word-point) + "Find word at `WORD-POINT', look it up in powerthesaurs, and replace it." + (interactive (list (point))) + (pcase-let ((`(,word ,beg ,end) + (powerthesaurus--extract-original-word word-point))) + (powerthesaurus-lookup word :synonyms beg end))) + +;;;###autoload +(defun powerthesaurus-lookup-word (&optional beginning end) + "Find the given word's synonyms at powerthesaurus.org. + +`BEGINNING' and `END' correspond to the selected text with a word to replace. +If there is no selection provided, additional input will be required. +In this case, a selected synonym will be inserted at the point." + (interactive + ;; it is a simple interactive function instead of interactive "r" + ;; because it doesn't produce an error in a buffer without a mark + (if (use-region-p) (list (region-beginning) (region-end)) + (list nil nil))) + (pcase-let ((`(,word _ _) + (if beginning + (powerthesaurus--extract-query-region beginning end) + (powerthesaurus--read-query-term "Word to fetch: ")))) + (powerthesaurus-lookup word :synonyms (or beginning (point)) end))) + +(make-obsolete 'powerthesaurus-lookup-word + 'powerthesaurus-lookup "0.2.0") +(make-obsolete 'powerthesaurus-lookup-word-at-point + 'powerthesaurus-lookup "0.2.0") +(make-obsolete 'powerthesaurus-lookup-word-dwim + 'powerthesaurus-lookup "0.2.0") + +;; =============================================================== +;; GraphQL queries +;; =============================================================== + +(defconst powerthesaurus--search-query + "query SEARCH($query: String!) { + search(query: $query) { + terms { + id + name + } + } +}") + +(defconst powerthesaurus--thesaurus-query + "query THESAURUS($termID: ID!, $type: List!, $sort: ThesaurusSorting!) { + thesauruses(termId: $termID, sort: $sort, list: $type) { + edges { + node { + targetTerm { + name + } + relations + rating + votes + } + } + } +}") + +(defconst powerthesaurus--definition-query + "query DEFINITION($termID: ID!) { + definitions(termId: $termID) { + edges { + node { + definition + rating + votes + synonyms + usages + partsOfSpeech + author { + title + } + } + } + } +}") + +(defconst powerthesaurus--sentence-query + "query SENTENCE($termID: ID!) { + sentences(termId: $termID) { + edges { + node { + sentence + rating + votes + author { + title + } + } + } + } +}") + +;; =============================================================== +;; UI shortcuts +;; =============================================================== + +;;;###autoload +(when (require 'hydra nil :noerror) + (eval '(defhydra powerthesaurus-hydra (:color blue :hint nil) + " + Power Thesaurus + ^Similarity^ ^Information^ + --------------------------------------- + _s_: Synonyms _d_: Definitions + _a_: Antonyms _e_: Example Sentences + _r_: Related Words + _q_: Quit + " + ("s" powerthesaurus-lookup-synonyms-dwim) + ("a" powerthesaurus-lookup-antonyms-dwim) + ("r" powerthesaurus-lookup-related-dwim) + ("d" powerthesaurus-lookup-definitions-dwim) + ("e" powerthesaurus-lookup-sentences-dwim) + ("q" nil)))) + +;;;###autoload +(when (require 'transient nil :noerror) + (eval '(transient-define-prefix powerthesaurus-transient () + "Transient for Power Thesaurus." + [["Similarity" + ("s" "Synonyms" powerthesaurus-lookup-synonyms-dwim) + ("a" "Antonyms" powerthesaurus-lookup-antonyms-dwim) + ("r" "Related Words" powerthesaurus-lookup-related-dwim)] + ["Information" + ("d" "Definitions" powerthesaurus-lookup-definitions-dwim) + ("e" "Example Sentences" powerthesaurus-lookup-sentences-dwim)]]))) + +(provide 'powerthesaurus) +;;; powerthesaurus.el ends here diff --git a/kolwynia/home/bdunahu/files/.config/emacs/libraries/selector.el b/kolwynia/home/bdunahu/files/.config/emacs/libraries/selector.el new file mode 100644 index 0000000..3b77190 --- /dev/null +++ b/kolwynia/home/bdunahu/files/.config/emacs/libraries/selector.el @@ -0,0 +1,653 @@ +;;; -*- lexical-binding: t; -*- +;;; Commentary: + +;; modified version of lcolonq: https://github.com/lcolonq/emacs + +;;; Code: + + +(require 'dash) +(require 'recentf) + +(defgroup selector nil + "Efficient selection and navigation." + :group 'convenience) + +(defgroup selector-faces nil + "Faces for `selector'." + :group 'selector + :group 'faces) + +(defface selector-source-name + '((default :underline t :inherit bold) + (((class color) (background dark)) :foreground "white")) + "Face used to highlight source names.") + +(defface selector-highlight + '((t :inherit highlight)) + "Face used to highlight the current selection.") + +(defvar selector-minibuffer-lines 20 + "Number of lines to display in the minibuffer.") + +(defvar selector-exit-hook nil + "Hook run when exiting minibuffer selection.") + +(defvar selector--sources '()) +(defvar selector--last nil) +(defvar selector--matching '()) +(defvar selector--source 0) +(defvar selector--index 0) +(defvar selector--action nil) +(defvar selector--result nil) +(defvar selector--drawn-this-frame 0) + +(defvar selector-minibuffer-map (make-sparse-keymap)) +(define-key selector-minibuffer-map (kbd "\\") (lambda () (interactive) nil)) +(define-key selector-minibuffer-map (kbd "C-g") 'selector-quit) +(define-key selector-minibuffer-map (kbd "C-c") 'selector-quit) +(define-key selector-minibuffer-map (kbd "<return>") 'selector-do) +(define-key selector-minibuffer-map (kbd "C-m") 'selector-do) +(define-key selector-minibuffer-map (kbd "<backtab>") 'selector-previous) +(define-key selector-minibuffer-map (kbd "<tab>") 'selector-next) +(define-key selector-minibuffer-map (kbd "<up>") 'selector-previous) +(define-key selector-minibuffer-map (kbd "<down>") 'selector-next) +(define-key selector-minibuffer-map (kbd "<left>") 'selector-previous-source) +(define-key selector-minibuffer-map (kbd "<right>") 'selector-next-source) +(define-key selector-minibuffer-map (kbd "C-p") 'selector-previous) +(define-key selector-minibuffer-map (kbd "C-n") 'selector-next) +(define-key selector-minibuffer-map (kbd "M-v") 'selector-previous-source) +(define-key selector-minibuffer-map (kbd "C-v") 'selector-next-source) + +(defun selector-minibuffer-line-face (str face) + "Write STR to the minibuffer in FACE." + (cl-incf selector--drawn-this-frame) ;; sort of an ugly hack, + ;; but this fixes the annoying "cursor jumping" glitch when multiple monitors + ;; are active. the real fix probably should live in selector-nearby? + (when (< selector--drawn-this-frame selector-minibuffer-lines) + (let ((before (point))) + (goto-char (point-max)) + (insert (concat "\n" str)) + (goto-char before) + (forward-line) + (put-text-property (line-beginning-position) (point-max) 'face face)))) + +(defun selector-minibuffer-clear () + "Clear minibuffer." + (save-excursion + (goto-char (minibuffer-prompt-end)) + (delete-region (line-end-position) (point-max)))) + +(defun selector-minibuffer-input () + "Get current minibuffer input." + (buffer-substring-no-properties + (minibuffer-prompt-end) + (line-end-position))) + +(cl-defstruct (selector-candidate (:constructor selector-candidate--create) + (:copier nil) + (:conc-name selector-candidate--)) + type (display nil :type string) face value action) + +(cl-defun selector-candidate-create + (display &key + value + (type 'normal) + (face 'default) + (action '())) + "Create a candidate. +DISPLAY is the string to display (using FACE) / match against. +VALUE is the value to pass to actions when the candidate is selected. +TYPE is either normal or dummy - dummy candidates always appear in the +results list regardless of the input pattern. +ACTION is an alist mapping keybindings to candidate-specific actions." + (selector-candidate--create + :type type + :display display + :face face + :value (if value value display) + :action action)) + +(defun selector-candidate-display (candidate) + "Return the display string for CANDIDATE." + (cond ((selector-candidate-p candidate) (selector-candidate--display candidate)) + (t candidate))) + +(defun selector-candidate-value (candidate) + "Return the value of CANDIDATE." + (cond ((selector-candidate-p candidate) (selector-candidate--value candidate)) + (t candidate))) + +(defun selector-candidate-type (candidate) + "Return the candidate type of CANDIDATE." + (cond ((selector-candidate-p candidate) (selector-candidate--type candidate)) + (t 'normal))) + +(defun selector-candidate-face (candidate) + "Return the display face for CANDIDATE." + (cond ((selector-candidate-p candidate) (selector-candidate--face candidate)) + (t 'default))) + +(defun selector-candidate-action (candidate) + "Return the actions for CANDIDATE." + (cond ((selector-candidate-p candidate) (selector-candidate--action candidate)) + (t '()))) + +(defun selector-candidate-display-string (candidate) + "Return the display of CANDIDATE as a string." + (let ((display (selector-candidate-display candidate))) + (cond ((stringp display) display) + (t (error "Invalid candidate display %s for candidate %s (of type %s)" + display candidate (type-of display)))))) + +(defun selector-highlight-candidate (candidate) + "Return a copy of CANDIDATE with the face set to selector-highlight." + (selector-candidate--create + :type (selector-candidate-type candidate) + :display (selector-candidate-display candidate) + :face 'selector-highlight + :value (selector-candidate-value candidate) + :action (selector-candidate-action candidate))) + +(defun selector-match (candidate regex) + "Determine whether CANDIDATE is a match for REGEX." + (let ((type (selector-candidate-type candidate))) + (cond ((eq 'dummy type) t) + (t (string-match-p regex (selector-candidate-display-string candidate)))))) + +(cl-defstruct (selector-source (:constructor selector-source--create) + (:copier nil)) + name candidates actions keymap) + +(defun selector-action-function (action) + "Return the function associated with ACTION." + (if (functionp action) + action + (cdr action))) + +(defun selector-actions-keymap (actions) + "Return a keymap for ACTIONS." + (let ((keymap (make-sparse-keymap))) + (set-keymap-parent keymap selector-minibuffer-map) + (mapc + (lambda (a) + (unless (functionp a) + (define-key keymap (car a) + (lambda () (interactive) + (selector-do (cdr a)))))) + actions) + keymap)) + +(cl-defun selector-source-create (name &key candidates (actions '())) + "Create a new source named NAME with the given CANDIDATES and ACTIONS. + +CANDIDATES is either: +- A list of candidates +- A function returning a list of candidates given a regex +ACTIONS is a list of actions, which can be: +- functions taking candidate values as arguments +- pairs of key strings and such functions" + (selector-source--create + :name name + :candidates + (if (functionp candidates) candidates + (--map (if (selector-candidate-p it) it (selector-candidate-create it)) + candidates)) + :actions actions + :keymap (selector-actions-keymap actions))) + +(defun selector-matching-candidates (candidates pattern) + "Return the candidates in CANDIDATES matching PATTERN." + (cond ((functionp candidates) (funcall candidates pattern)) + (t (let ((regex (selector-pattern-regex pattern))) + (--filter (selector-match it regex) candidates))))) + +(defun selector-filter-source (source pattern) + "Return a copy of SOURCE including only the candidates matching PATTERN." + (selector-source--create + :name (selector-source-name source) + :candidates (selector-matching-candidates (selector-source-candidates source) pattern) + :actions (selector-source-actions source) + :keymap (selector-source-keymap source))) + +(defun selector-pattern-regex (pattern) + "Convert PATTERN into a regular expression." + (apply #'string-join + (--map (concat "\\(" it "\\)") (split-string pattern)) + '(".*"))) + +(defun selector-matching-sources (sources pattern) + "Return the sources in SOURCES matching PATTERN." + (let* ((matches (--map (selector-filter-source it pattern) sources))) + (-filter #'selector-source-candidates matches))) + +(defun selector-display-source (source) + "Display SOURCE." + (when source + (selector-minibuffer-line-face (selector-source-name source) 'selector-source-name) + (--map (selector-minibuffer-line-face + (selector-candidate-display-string it) + (selector-candidate-face it)) + (selector-source-candidates source)))) + +(defun selector-nearby (sources) + "Filter SOURCES to only include candidates close to the selected candidate." + (let* ((adjacent + (--map + (cond ((and (< (cdr it) (+ selector--source selector-minibuffer-lines)) + (> (cdr it) selector--source)) + (cons (car it) 'g)) + ((= (cdr it) selector--source) + (cons (car it) 'e)) + (t nil)) + (-zip-pair sources (number-sequence 0 (length sources)))))) + (--map + (when it + (let* ((candidates (selector-source-candidates (car it)))) + (selector-source--create + :name (selector-source-name (car it)) + :candidates + (cond ((eq (cdr it) 'g) + (-take selector-minibuffer-lines candidates)) + (t + (cl-loop for i from (max (- selector--index + (- (/ selector-minibuffer-lines 2) 1)) + 0) + for j in (-take + selector-minibuffer-lines + (-drop + (- selector--index + (- (/ selector-minibuffer-lines 2) 1)) + candidates)) + collect (if (= i selector--index) + (selector-highlight-candidate j) + j)))) + :actions (selector-source-actions (car it)) + :keymap (selector-source-keymap (car it))))) + adjacent))) + +(defun selector-update-transient-map () + "Update the transient keymap to match the current source." + (let ((source (car (nthcdr selector--source selector--matching)))) + (when source + (set-transient-map (selector-source-keymap source))))) + +(defun selector-minibuffer-render () + "Draw matching candidates to minibuffer." + (setq selector--drawn-this-frame 0) + (save-excursion + (let ((pattern (selector-minibuffer-input))) + (unless (string= pattern selector--last) + (setq selector--last pattern + selector--index 0 + selector--source 0 + selector--matching (selector-matching-sources selector--sources pattern)))) + (-map #'selector-display-source (selector-nearby selector--matching)) + (goto-char (minibuffer-prompt-end)) + (put-text-property (line-end-position) (point-max) 'readonly t)) + (selector-update-transient-map)) + +(defun selector-minibuffer-setup (initial) + "Ready minibuffer for completion with INITIAL as initial input." + (add-hook 'pre-command-hook 'selector-minibuffer-clear nil t) + (add-hook 'post-command-hook 'selector-minibuffer-render nil t) + (setq-local max-mini-window-height selector-minibuffer-lines) + (when initial + (save-excursion + (minibuffer-prompt-end) + (insert initial))) + (end-of-line) + (selector-update-transient-map)) + +(defun selector-previous-source () + "Move to the previous source." + (interactive) + (setq selector--index 0) + (setq selector--source (if (= selector--source 0) + (- (length selector--matching) 1) + (- selector--source 1)))) + +(defun selector-next-source () + "Move to the next source." + (interactive) + (setq selector--index 0) + (setq selector--source (% (+ selector--source 1) (length selector--matching)))) + +(defun selector-previous () + "Move to the previous candidate." + (interactive) + (let* ((new-source-index (if (= selector--source 0) + (- (length selector--matching) 1) + (- selector--source 1))) + (source (car (nthcdr new-source-index selector--matching)))) + (setq selector--index (- selector--index 1)) + (when (< selector--index 0) + (setq selector--index (- (length (selector-source-candidates source)) 1) + selector--source new-source-index)))) + +(defun selector-next () + "Move to the next candidate." + (interactive) + (let* ((source (car (nthcdr selector--source selector--matching)))) + (setq selector--index (+ selector--index 1)) + (when (= selector--index (length (selector-source-candidates source))) + (setq selector--index 0 + selector--source (% (+ selector--source 1) (length selector--matching)))))) + +(defun selector-quit () + "Quit the selection interface without running an action." + (interactive) + (run-hooks 'selector-exit-hook) + (keyboard-escape-quit)) + +(defun selector-do (&optional action-function) + "Act upon selected candidate. +If ACTION-FUNCTION is given use it, otherwise use the first action for the candidate." + (interactive) + (if (null selector--matching) + (progn + (setq selector--action (lambda (x) x) + selector--result nil)) + (progn + (let* ((source (car (nthcdr selector--source selector--matching))) + (candidate (car (nthcdr selector--index (selector-source-candidates source))))) + (setq selector--action (cond (action-function + action-function) + ((selector-candidate-action candidate) + (selector-candidate-action candidate)) + (t + (let ((actions (selector-source-actions source))) + (if actions + (selector-action-function (car actions)) + (lambda (x) x))))) + selector--result (selector-candidate-value candidate))))) + (run-hooks 'selector-exit-hook) + (exit-minibuffer)) + +;;;###autoload +(cl-defun selector (sources &key prompt initial) + "Select a candidate and run an action using SOURCES. +Display PROMPT as the prompt, or \"pattern: \" if not given. +Use INITIAL as the initial input." + (setq selector--sources sources + selector--last nil + selector--matching (selector-matching-sources sources "") + selector--source 0 + selector--index 0 + selector--action nil + selector--result nil) + (let ((inhibit-message t)) + (minibuffer-with-setup-hook + (apply-partially 'selector-minibuffer-setup initial) + (read-from-minibuffer (or prompt "pattern: ") nil selector-minibuffer-map))) + (funcall selector--action selector--result)) + +(defvar selector-completing-read-candidate-transformer (lambda (x) x)) + +;;;###autoload +(defun selector-completing-read (prompt collection &optional predicate require-match + initial-input hist def inherit-input-method) + "Replacement for `completing-read'. +PROMPT, COLLECTION, PREDICATE, REQUIRE-MATCH, INITIAL-INPUT, HIST, DEF, and +INHERIT-INPUT-METHOD have the same meaning as in `completing-read'." + (ignore predicate hist def inherit-input-method) + (let ((unspecified-source + (if require-match + '() + (list + (selector-source-create + "Other" + :candidates + (list (selector-candidate-create + "Specify" + :type 'dummy + :action (lambda (_) (selector-input))))))))) + (or + (cond ((functionp collection) + (selector + (cons + (selector-source-create + "Completions" + :candidates + (-non-nil + (--map + (when-let ((disp (funcall selector-completing-read-candidate-transformer it))) + (selector-candidate-create disp :value it)) + (funcall collection "" nil t)))) + unspecified-source) + :prompt prompt + :initial initial-input)) + ((hash-table-p collection) + (selector + (cons + (selector-source-create + "Completions" + :candidates (hash-table-keys collection)) + unspecified-source) + :prompt prompt + :initial initial-input)) + ((obarrayp collection) + (let ((candidates (list))) + (mapatoms (lambda (x) (push (selector-candidate-create (symbol-name x)) candidates)) collection) + (selector + (cons (selector-source-create "Completions" :candidates candidates) unspecified-source) + :prompt prompt + :initial initial-input))) + (t (selector + (cons (selector-source-create + "Completions" + :candidates + (--map (if (consp it) + (selector-candidate-create (car it)) + it) + collection)) + unspecified-source) + :prompt prompt + :initial initial-input))) + (selector-input)))) + +(defun selector-input () "Return last minibuffer input." selector--last) + +(defvar selector-extended-command-actions + (list (lambda (c) + (add-to-list 'extended-command-history c) + (command-execute (intern-soft c))) + (cons (kbd "C-h") (lambda (c) (describe-function (intern-soft c)))))) + +;;;###autoload +(defun selector-extended-commands-source () + "Source for extended commands (`M-x')." + (selector-source-create + "Commands" + :candidates + (-map + #'selector-candidate-create + (all-completions "" obarray #'commandp)) + :actions + selector-extended-command-actions)) + +;;;###autoload +(defun selector-extended-command-history-source () + "Source for extended command history." + (selector-source-create + "Command History" + :candidates + (-map + #'selector-candidate-create + extended-command-history) + :actions + selector-extended-command-actions)) + +;;;###autoload +(defun selector-apropos-command-source () + "Source for command lookup." + (selector-source-create + "Commands" + :candidates + (lambda (r) (-map #'selector-candidate-create (all-completions r obarray #'commandp))) + :actions + (list (lambda (c) (describe-function (intern-soft c)))))) + +;;;###autoload +(defun selector-apropos-function-source () + "Source for function lookup." + (selector-source-create + "Functions" + :candidates + (lambda (r) (-map #'selector-candidate-create (all-completions r obarray #'fboundp))) + :actions + (list (lambda (c) (describe-function (intern-soft c)))))) + +;;;###autoload +(defun selector-apropos-variable-source () + "Source for variable lookup." + (selector-source-create + "Variables" + :candidates + (lambda (r) (-map #'selector-candidate-create + (all-completions + r obarray + (lambda (x) (let ((sym (intern-soft x))) + (and (boundp sym) (not (keywordp sym)))))))) + :actions + (list (lambda (c) (describe-variable (intern-soft c)))))) + +(defvar selector-buffer-actions + (list 'switch-to-buffer + (cons (kbd "C-k") 'kill-buffer))) + +;;;###autoload +(defun selector-buffers-source (&optional sort-pred) + "Source for open buffers. +An optional SORT-PRED may be provided to sort the buffers (see `sort')." + (selector-source-create + "Buffers" + :candidates + (--map (selector-candidate-create (buffer-name it)) + (if sort-pred (sort (buffer-list) sort-pred) (buffer-list))) + :actions + selector-buffer-actions)) + +;;;###autoload +(defun selector-create-buffer-source () + "Dummy source to create a buffer." + (selector-source-create + "Other" + :candidates + (list (selector-candidate-create + "Create buffer" + :type 'dummy + :action (lambda (_) (switch-to-buffer (selector-input))))))) + +(defvar selector-file-actions + (list 'find-file + (cons (kbd "C-d") (lambda (f) + (when (y-or-n-p (concat "Delete file " f "? ")) + (delete-file f)))))) + +;;;###autoload +(defun selector-files-source () + "Source for files in current directory." + (selector-source-create + "Files" + :candidates + (-map #'selector-candidate-create (directory-files default-directory)) + :actions + selector-file-actions)) + +;;;###autoload +(defun selector-create-file-source () + "Dummy source to create a file." + (selector-source-create + "Other" + :candidates + (list (selector-candidate-create + "Create file" + :type 'dummy + :action (lambda (_) (find-file (selector-input))))))) + +;;;###autoload +(defun selector-recentf-source () + "Source for recentf." + (selector-source-create + "Recent Files" + :candidates + (-map #'selector-candidate-create recentf-list) + :actions + selector-file-actions)) + +;;;###autoload +(defun selector-M-x () + "Preconfigured `selector' interface to replace `execute-external-command'." + (interactive) + (selector (list (selector-extended-command-history-source) + (selector-extended-commands-source)))) + +;;;###autoload +(defun selector-apropos (&optional initial) + "Preconfigured `selector' interface to replace `apropos'. +INITIAL is the initial text to match." + (interactive) + (selector (list (selector-apropos-command-source) + (selector-apropos-function-source) + (selector-apropos-variable-source)) + :initial (if initial initial (thing-at-point 'symbol t)))) + +;;;###autoload +(defun selector-for-buffers () + "Preconfigured `selector' interface for open buffers and recentf." + (interactive) + (selector (list (selector-buffers-source) + (selector-recentf-source) + (selector-create-buffer-source)))) + +;;;###autoload +(defun selector-for-files () + "Preconfigured `selector' interface for files in the current directory." + (interactive) + (selector (list (selector-files-source) + (selector-create-file-source)))) + +;;;###autoload +(defun selector-read-file-name (prompt &optional dir default-filename mustmatch initial predicate) + "Replacement for `read-file-name'. +PROMPT, DIR, DEFAULT-FILENAME, MUSTMATCH, INITIAL and PREDICATE have the same +meaning as in `read-file-name'." + (ignore default-filename mustmatch predicate) + (let ((d (if dir dir default-directory))) + (concat d (selector (list (selector-source-create + "Files" + :candidates (-map #'selector-candidate-create (directory-files d))) + (selector-source-create + "Other" + :candidates (list (selector-candidate-create + "New file" + :type 'dummy + :action (lambda (_) (selector-input)))))) + :prompt prompt + :initial initial)))) + +(defun selector-file-contents-actions (file) + "Actions for candidate values corresponding to lines in FILE." + (list + (lambda (index) + (find-file file) + (goto-char (point-min)) + (forward-line index) + (pulse-momentary-highlight-one-line (point))))) + +(defun selector-file-contents-source (file) + "Source for lines in FILE." + (selector-source-create + file + :candidates + (-map-indexed + (lambda (index l) + (selector-candidate-create l :value index)) + (split-string (f-read-text file) "\n")) + :actions + (selector-file-contents-actions file))) + + +(provide 'selector) +;;; selector.el ends here diff --git a/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--browse.el b/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--browse.el new file mode 100644 index 0000000..7ba6513 --- /dev/null +++ b/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--browse.el @@ -0,0 +1,146 @@ +;;; -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + +(require 'selector) +(require 'dash) +(require 'fill-column) + +(defun bd/browse (url &optional pref &rest _) + "Given PREF, launches URL in an external browser or eww." + (interactive) + (pcase pref + ('eww (eww url)) + ('tor (start-process "torbrowser" nil "torbrowser" "--new-window" url)) + ('chromium (start-process "chromium" nil "chromium" "--new-window" url)) + (_ (start-process "browser" nil (getenv "BROWSER") "--new-window" url)))) + +(defun bd/selector-bookmarks () + "Selector source for all bookmarks." + (selector-source-create + "Bookmarks" + :candidates + (-map + (lambda (b) (selector-candidate-create (car b) :value (cdr b))) + bd/bookmarks) + :actions + (list (lambda (x) (apply #'bd/browse x))))) + +(defmacro bd/search-candidate (name url pref) + "Syntax for a search candidate given NAME, URL, and PREF." + `(selector-candidate-create + ,(concat "Search " name) + :type 'dummy + :action (lambda (_) (browse-url (concat ,url (selector-input)) ,pref)))) + +(defun rip-video (url) + "Play URL (or search string) in mpv." + (message "Ludu %s" url) + (start-process "rip" nil + "mpv" "--force-window=yes" + (concat (if (string-match "https://.*" url) + "ytdl://" + "ytdl://ytsearch:") url))) + +(defun rip-html (url) + "Open an HTML document in an emacs org buffer." + (with-current-buffer-window url + '((display-buffer-same-window)) + nil + (princ + (shell-command-to-string + (concat "curl --silent " url " | pandoc --from=html --to=org --standalone"))) + (org-mode))) + +(defun bd/selector-rip-video () + "Selector source for streaming a video off of youtube." + (selector-candidate-create + "Search Immediate" + :type 'dummy + :action (lambda (_) (rip-video (selector-input))))) + +(defun bd/selector-search () + "Selector source for all search engines." + (selector-source-create + "Browser" + :candidates + (list (bd/search-candidate "DuckDuckGo" "https://duckduckgo.com/html/?q=" 'wolf) + (bd/search-candidate "SearXNG" "https://searx.operationnull.com/searxng/search?q=" 'wolf) + (bd/search-candidate "SearXNG-E" "https://searx.operationnull.com/searxng/search?q=" 'eww) + (bd/search-candidate "Wikipedia" "https://en.wikipedia.org/w/index.php?search=" 'eww) + (bd/search-candidate "Invidious" "https://inv.nadeko.net/search?q=" 'eww) + (bd/search-candidate "Urban Dictionary" "https://www.urbandictionary.com/define.php?term=" 'wolf) + (bd/search-candidate "Nethack Wiki" "https://nethackwiki.com/w/index.php?search=" 'eww) + (bd/search-candidate "Archive of Our Own" "https://archiveofourown.org/works/search?work_search%5Bquery%5D=" 'eww) + (bd/search-candidate "Archwiki" "https://wiki.archlinux.org/index.php?title=Special%3ASearch&search=" 'eww) + + (bd/selector-rip-video) + (bd/search-candidate "Torbrowser" "" 'tor) + (bd/search-candidate "Librewolf" "" 'wolf)))) + +(defun bd/browse-dispatcher () + "Select and `browse-url' a bookmark or search feature." + (interactive) + (unwind-protect + (selector + (list (bd/selector-bookmarks) + (bd/selector-search))))) + +(setopt browse-url-handlers + `((,(regexp-opt '("youtube.com" "youtu.be" "vid.puffyan.us" "deezer.page" "deezer.com")) . + (lambda (url &rest _) (rip-video url)))) + url-privacy-level '(email os emacs lastloc cookies)) + +(use-package elpher + :bind + (:map elpher-mode-map + ("l" . #'elpher-back) + ("d" . #'elpher-download) + ("w" . #'elpher-copy-current-url) + ("A" . #'elpher-copy-link-url) + ("E" . #'elpher-bookmark-current) + ("TAB" . #'elpher-next-link) + ("g" . #'elpher-reload) + ("G" . #'elpher-go)) + :config + (defun bd/elpher (original url &optional new-window) + "Handle gemini links." + (cond ((string-match-p "\\`\\(gemini\\|gopher\\)://" url) + (elpher-go url)) + (t (funcall original url new-window)))) + (advice-add 'eww :around 'bd/elpher) + (setopt elpher-default-url-type "gemini" + elpher-connection-timeout 120 + elpher-gemini-max-fill-width 85 + elpher-use-emacs-bookmark-menu t)) + +(use-package eww + :defer 1 + :bind + (:map eww-mode-map + ("i" . eww-toggle-images) + ("o" . (lambda () (interactive) (rip-html (eww-current-url))))) + :hook + ;; eww-mode by default sets this as local var to eww-browse-url + ((eww-mode . + (lambda () + (setq-local browse-url-browser-function #'bd/browse))) + (eww-after-render . eww-readable)) + :config + (setopt eww-search-prefix "https://searx.operationnull.com/searxng/search?q=" + eww-auto-rename-buffer 'title + eww-browse-url-new-window-is-tab nil + browse-url-browser-function 'bd/browse + browse-url-secondary-browser-function #'browse-url-default-browser + eww-header-line-format "%t: %u" + eww-use-browse-url (regexp-opt '("mailto:" + "youtube.com" + "youtu.be")) + shr-use-fonts nil + shr-inhibit-images t + shr-cookie-policy nil + shr-max-width 90)) + + +(provide 'bd--browse) +;;; bd--browse.el ends here diff --git a/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--buffer.el b/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--buffer.el new file mode 100644 index 0000000..4a09805 --- /dev/null +++ b/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--buffer.el @@ -0,0 +1,32 @@ +;;; -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + + +(use-package autorevert + :init + (global-auto-revert-mode) + :config + (setopt global-auto-revert-non-file-buffers t + auto-revert-interval 30)) + +(use-package midnight + :config + ;; kill forgotten browser windows + (push + "\.\*\\(LibreWolf\\|Chromium\\|IceCat\\|Tor\sBrowser\\)" + clean-buffer-list-kill-regexps) + ;; never kill irc buffers + (push + ".*operationnull.com" + clean-buffer-list-kill-never-regexps) + (setopt clean-buffer-list-delay-special 1800 + midnight-period (* 12 3600))) + +(use-package atomic-chrome + :config + (atomic-chrome-start-server)) + + +(provide 'bd--buffer) +;;; bd--buffer.el ends here diff --git a/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--chat.el b/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--chat.el new file mode 100644 index 0000000..5fa0c2d --- /dev/null +++ b/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--chat.el @@ -0,0 +1,118 @@ +;;; -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + + +(require 'fill-column) +(use-package rcirc + :bind (:map rcirc-mode-map + ("C-c j" . #'bd/rcirc-jump-net) + ("C-c q" . #'bd/rcirc-detach-buffer)) + :hook + ((rcirc-mode . (lambda () + (setq-local fill-column-desired-width 80) + (fill-column-mode) + (rcirc-omit-mode)))) + :config + (setopt bd/rcirc-networks '("libera" "furnet")) + (defun bd/rcirc-jump-net () + "Prompts the user for a irc network in BD/RCIRC-NETWORKS, then issues +ZNC to hop networks." + (interactive) + (let ((buffer (current-buffer))) + (when (and (buffer-local-value 'rcirc-server-buffer buffer) + (eq (process-status (rcirc-buffer-process)) 'open)) + (let ((target (completing-read "Jump to: " bd/rcirc-networks))) + (if (stringp target) + (rcirc-send-string (rcirc-buffer-process) + "PRIVMSG" "*status" : + (concat "JUMPNETWORK " target))))))) + (defun bd/rcirc-detach-buffer () + "If the current buffer is an rcirc channel, detaches through ZNC and +deletes the buffer. This bypasses the default behavior of deleting an active +channel, which is issuing the PART command." + (interactive) + (let ((buffer (current-buffer))) + (when (and (rcirc-buffer-process) + (eq (process-status (rcirc-buffer-process)) 'open)) + (with-rcirc-server-buffer + (setq rcirc-buffer-alist + (rassq-delete-all buffer rcirc-buffer-alist))) + (rcirc-update-short-buffer-names) + (if (rcirc-channel-p rcirc-target) + (rcirc-send-string (rcirc-buffer-process) + "PRIVMSG" "*status" : + (concat "DETACH " rcirc-target)))) + (setq rcirc-target nil) + (kill-buffer buffer))) + (setopt rcirc-fill-column 80 + rcirc-omit-threshold 5 + rcirc-reconnect-delay 60 + rcirc-omit-responses '("JOIN" "PART" "QUIT" "NICK" "AWAY") + rcirc-track-minor-mode t + rcirc-track-ignore-server-buffer-flag t + rcirc-server-alist + '(("operationnull.com" + :nick "Gondul" + :user-name "Gondul" + :port 6697 + :encryption tls)))) + +(use-package gptel + :bind (("C-c g" . gptel-menu) + ("C-c k" . (lambda () (interactive) (gptel "*evka*") (switch-to-buffer "*evka*")))) + :config + (defvar bd/llama-cpp-buffer-name "*llama-cpp-proc*") + (defvar bd/llama-cpp-reasoning-buffer-name "*llama-cpp-reasoning*") + (defvar bd/llama-cpp-port "4568") + (defvar bd/llama-cpp-threads "8") + (defvar bd/llama-cpp-model-file "Qwen3-8B.Q4_K_M.gguf") + ;; most models seem to ignore this, or llama-cpp doesn't add /no_think like it's supposed to + (defvar bd/llama-cpp-reasoning-budget nil) + (defun bd/gptel-start-backend () + (interactive) + (let ((process (get-buffer-process bd/llama-cpp-buffer-name))) + (if process + (message "llama-cpp process is already running!") + (progn + (start-process-shell-command + "llama-cpp" bd/llama-cpp-buffer-name + (concat "llama-server --reasoning-budget " + (if bd/llama-cpp-reasoning-budget "-1" "0") + " --port " bd/llama-cpp-port + " -t " bd/llama-cpp-threads + " -m " (expand-file-name bd/llama-cpp-model-file "~/.config/guix/assets/")))) + (unless (get-buffer bd/llama-cpp-reasoning-buffer-name) + (generate-new-buffer bd/llama-cpp-reasoning-buffer-name))))) + (defun bd/gptel-stop-backend () + (interactive) + (let ((process (get-buffer-process bd/llama-cpp-buffer-name))) + (if process + (progn + (delete-process process) + (kill-buffer bd/llama-cpp-buffer-name) + (message "Killed %s." process)) + (message "No llama-cpp process is running.")))) + (defun bd/gptel-restart-backend () + (interactive) + (bd/gptel-stop-backend) + (bd/gptel-start-backend)) + + (bd/gptel-start-backend) + + (add-to-list 'gptel-directives + '(evka . "You are a wolf (furry) named Evka hired as a secretary to complete language-based tasks. First describe an action your character does, e.x.: *I tap my claws on the desk*. Finish by responding to the task tersely, in character./no_think")) + + (setopt gptel-model 'qwen-4b + gptel-backend (gptel-make-openai "llama-cpp" + :stream t + :protocol "http" + :host (concat "localhost:" bd/llama-cpp-port) + :models '(qwen-4b)) + gptel-max-tokens 500 + gptel--system-message (alist-get 'evka gptel-directives) + gptel-include-reasoning bd/llama-cpp-reasoning-buffer-name)) + + +(provide 'bd--chat) +;;; bd--chat.el ends here diff --git a/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--devel.el b/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--devel.el new file mode 100644 index 0000000..dfc9f15 --- /dev/null +++ b/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--devel.el @@ -0,0 +1,237 @@ +;;; -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + +(require 'selector) +(require 'dash) + +(setopt display-line-numbers-type 'relative) +(defvar bd/enable-line-numbers-in-hooks + '(prog-mode-hook) + "List of hook symbols to add `display-line-numbers-mode' to.") +(mapc + (lambda (hook) + (add-hook hook #'display-line-numbers-mode)) + bd/enable-line-numbers-in-hooks) + +;; skr (skribe) is a scheme extension +(add-to-list 'auto-mode-alist '("\\.skr\\'" . scheme-mode)) + +(defun bd/beginning-of-visual-line-dwim (&optional n) + (interactive "P") + (let ((pt (point))) + (back-to-indentation) + (when (or n (eq pt (point))) + (beginning-of-visual-line n)))) + +(define-minor-mode dwim-cursor-mode + "Toggle dwim-cursor-mode." + :init-value nil + :group 'quality + :light " SC" + :keymap (list + (cons (kbd "C-a") #'bd/beginning-of-visual-line-dwim))) + +(use-package prog-mode + :hook + ((js-mode . (lambda () + (add-to-list 'prettify-symbols-alist '("function" . ?ƒ)))) + (prog-mode . (lambda () + (font-lock-add-keywords + nil '(("\\<\\(FIX\\(ME\\)?\\|TODO\\)" + 1 font-lock-warning-face t))))) + (prog-mode . dwim-cursor-mode)) + :config + (global-prettify-symbols-mode 1)) + +(use-package tramp + :config + (defun request-sudo () + "Uses TRAMP to edit current opened file as root." + (interactive) + (when buffer-file-name + (find-alternate-file + (concat "/sudo:root@localhost:" + buffer-file-name)))) + (setopt tramp-remote-path + (append tramp-remote-path + '(tramp-own-remote-path + "~/.guix-profile/bin" "~/.guix-profile/sbin")))) + +(use-package vc + :bind (("C-x v B" . #'bd/vc-browse-remote)) + :config + (defun bd/vc-browse-remote (&optional current-line) + "Open the repository's remote URL in the browser. +If CURRENT-LINE is non-nil, point to the current branch, file, and line. +Otherwise, open the repository's main page." + (interactive "P") + (let* ((remote-url (string-trim (vc-git--run-command-string nil "config" "--get" "remote.origin.url"))) + (branch (string-trim (vc-git--run-command-string nil "rev-parse" "--abbrev-ref" "HEAD"))) + (file (string-trim (file-relative-name (buffer-file-name) (vc-root-dir)))) + (line (line-number-at-pos))) + (message "Opening remote on browser: %s" remote-url) + (if (and remote-url (string-match "\\(?:git@\\|https://\\)\\([^:/]+\\)[:/]\\(.+?\\)\\(?:\\.git\\)?$" remote-url)) + (let ((host (match-string 1 remote-url)) + (path (match-string 2 remote-url))) + ;; Convert SSH URLs to HTTPS (e.g., git@github.com:user/repo.git -> https://github.com/user/repo) + (when (string-prefix-p "git@" host) + (setq host (replace-regexp-in-string "^git@" "" host))) + ;; Construct the appropriate URL based on CURRENT-LINE + (browse-url + (if current-line + (format "https://%s/%s/blob/%s/%s#L%d" host path branch file line) + (format "https://%s/%s" host path)))) + (message "Could not determine repository URL"))))) + +(use-package hl-line + :hook + ((prog-mode . hl-line-mode) + (text-mode . hl-line-mode))) + +(use-package compile + :demand t + :hook ((compilation-filter . ansi-color-compilation-filter)) + :config + (setopt compilation-always-kill t + compilation-scroll-output 'first-error + compilation-ask-about-save nil + ansi-color-for-compilation-mode t) + (defun bd/compile-dwim (f) + (let ((default-directory (bd/get-directory-dwim))) + (call-interactively f))) + (add-to-list 'display-buffer-alist + '((major-mode . compilation-mode) + (display-buffer-in-side-window) + (side . bottom) + (slot . -1) + (width . 0.15) + (post-command-select-window t))) + + (keymap-set prog-mode-map + "C-," #'(lambda () + (interactive) + (bd/compile-dwim #'recompile))) + (keymap-set prog-mode-map + "C-<" #'(lambda () + (interactive) + (bd/compile-dwim #'compile)))) + +(use-package man + :config + (setopt Man-notify-method 'pushy)) + +(use-package eldoc + :init + (global-eldoc-mode)) + +(use-package flymake + :bind (("C-c f f" . #'flymake-mode) + :map flymake-mode-map + ("C-c f s" . #'flymake-start) + ("C-c f n" . #'flymake-goto-next-error) + ("C-c f p" . #'flymake-goto-prev-error) + ("C-c f b" . #'flymake-show-buffer-diagnostics) + ("C-c f d" . #'flymake-show-project-diagnostics)) + :config + (setopt flymake-no-changes-timeout nil + flymake-start-on-flymake-mode t + flymake-start-on-save-buffer t + flymake-proc-compilation-prevents-syntax-check t + flymake-wrap-around nil + flymake-show-diagnostics-at-end-of-line nil)) + +(require 'geiser) +(require 'geiser-mode) +(require 'geiser-guile) + +(use-package cider) + +(use-package gdb-mi + :config + (setopt gdb-debuginfod-enable-setting nil)) + +(use-package eglot + :defer t + :bind (:map eglot-mode-map + ("C-c C-f" . eglot-format) + ("C-c C-e" . eglot-rename)) + :config + (setopt eglot-autoshutdown t + eglot-prefer-plaintext t + jsonrpc-event-hook nil) + (add-to-list 'eglot-server-programs + '(c-mode . ("ccls" "--init={\"clang\": {\"extraArgs\": [\"-std=c++20\"]}}")))) + +(use-package rainbow-mode + :hook css-mode) + +(use-package lua-mode + :config + (setopt lua-indent-level 4 + lua-indent-nested-block-content-align nil) + (defun lua-at-most-one-indent (old-function &rest arguments) + (let ((old-res (apply old-function arguments))) + (if (> old-res lua-indent-level) lua-indent-level old-res))) + (advice-add #'lua-calculate-indentation-block-modifier + :around #'lua-at-most-one-indent)) + +(use-package clojure-mode) + +(use-package slime + :defer t + :commands slime + :bind (:map slime-mode-map + ("C-c C-k" . slime-eval-buffer)) + :config + ;; more memory for ml libraries + (setopt inferior-lisp-program "sbcl --dynamic-space-size 4096")) + +(use-package yasnippet + :hook (vc-git-log-edit-mode . yas-minor-mode) + :config + (add-to-list 'yas-snippet-dirs (expand-file-name "~/pt/guix/etc/snippets/yas"))) + +(use-package paren + :config + (setopt show-paren-delay 0 + show-paren-style 'mixed + show-paren-highlight-openparen t + show-paren-context-when-offscreen t + show-paren-when-point-in-periphery t + show-paren-when-point-inside-paren t)) + +(use-package rainbow-delimiters + :hook prog-mode) + +(use-package paredit + :hook (ielm-mode + emacs-lisp-mode + eshell-mode + geiser-repl-mode + clojure-mode + cider-repl-mode + + lisp-mode + scheme-mode + slime-repl-mode + lisp-interaction-mode) + :config + (defun bd/paredit-preserve-repl (f &rest args) + "Wrapper around F (paredit-RET), discarding ARGS." + (pcase (cons major-mode (eolp)) + ('(inferior-emacs-lisp-mode . t) (ielm-return)) + ('(eshell-mode . t) (eshell-send-input)) + ('(geiser-repl-mode . t) (geiser-repl-maybe-send)) + ('(cider-repl-mode . t) (eshell-send-input)) + ('(slime-repl-mode . t) (slime-repl-return)) + (_ (funcall f)))) + (advice-add #'paredit-RET :around #'bd/paredit-preserve-repl) + (eldoc-add-command + 'paredit-backward-delete + 'paredit-close-round)) + +(use-package copyright) + +(provide 'bd--devel) +;;; bd--devel.el ends here diff --git a/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--dictionary.el b/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--dictionary.el new file mode 100644 index 0000000..e032837 --- /dev/null +++ b/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--dictionary.el @@ -0,0 +1,20 @@ +;;; -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + + +(use-package dictionary + :bind (("C-c i" . dictionary-lookup-definition)) + :config + (setopt dictionary-server "localhost" + dictionary-use-single-buffer t)) + +(use-package powerthesaurus + :bind (("C-c t" . powerthesaurus-transient)) + :config + (setopt powerthesaurus-show-rating nil + powerthesaurus-user-agent "Chrome/138.0.0.0")) + + +(provide 'bd--dictionary) +;;; bd--dictionary.el ends here diff --git a/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--emms.el b/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--emms.el new file mode 100644 index 0000000..f4e5064 --- /dev/null +++ b/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--emms.el @@ -0,0 +1,68 @@ +;;; -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + + +(use-package emms + :bind (("C-z C-s" . #'emms-quickstart) + ("C-z C-m" . #'switch-to-emms) + :map emms-playlist-mode-map + ("q" . #'quit-window)) + :config + (emms-all) + + (defun emms-quickstart () + "Queues a shuffled playlist and starts +playback." + (interactive) + (emms-stop) + (when (bufferp emms-playlist-buffer-name) + (kill-buffer emms-playlist-buffer-name)) + (emms-play-directory-tree (expand-file-name "~/ik/")) + (emms-shuffle)) + (defun switch-to-emms () + (interactive) + + (if (get-buffer emms-playlist-buffer-name) + (emms-playlist-mode-go) + (message "The Ainur cannot hear you..."))) + + (add-to-list 'emms-player-list 'emms-player-mpv) + (emms-playing-time-disable-display) + (setq-default emms-playlist-default-major-mode 'emms-playlist-mode + + emms-player-list '(emms-player-mpv) + emms-player-mpv-environment '("PULSE_PROP_media.role=music") + emms-player-mpv-parameters '("--quiet" "--really-quiet" "--no-audio-display" "--force-window=no" "--vo=null")) + (setopt + emms-track-description-function + '(lambda (track) + (let ((artist (emms-track-get track 'info-artist)) + (title (emms-track-get track 'info-title))) + (cond + ((and artist title) + (concat artist " - " title)) + (title + title) + (t + (emms-track-simple-description track)))))) + (setopt emms-source-file-default-directory (expand-file-name "~/ik/playlists/") + emms-info-report-each-num-tracks 2000 + emms-playlist-buffer-name "*Playlist*" + emms-mode-line-icon-enabled-p nil + emms-mode-line-length-limit 35 + emms-mode-line-format " [%s] " + emms-repeat-playlist t + emms-info-functions '(emms-info-native + emms-info-exiftool)) + (add-to-list 'display-buffer-alist + '((major-mode . emms-playlist-mode) + (display-buffer-in-side-window) + (side . left) + (slot . 0) + (width . 0.2) + (post-command-select-window t)))) + + +(provide 'bd--emms) +;;; bd--emms.el ends here diff --git a/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--exwm.el b/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--exwm.el new file mode 100644 index 0000000..1738ebe --- /dev/null +++ b/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--exwm.el @@ -0,0 +1,115 @@ +;;; -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + + +(use-package exwm + :demand t + :config + + (require 'exwm-randr) + (setopt exwm-randr-workspace-monitor-plist '(0 "HDMI-1" 1 "eDP-1") + exwm-workspace-number 10) + (add-hook 'exwm-randr-screen-change-hook + (lambda () + (start-process-shell-command + "xrandr" nil + "xrandr --output HDMI-1 --mode 2560x1440 --primary --auto --left-of eDP-1 --output eDP-1 --mode 1920x1080") + (bd/set-bg))) + (exwm-randr-mode) + + (defun bd/exwm-update-title () + "Changes the buffer name to reflect the class name for +that buffer." + (exwm-workspace-rename-buffer exwm-title)) + (add-hook 'exwm-update-title-hook #'bd/exwm-update-title) + (define-key exwm-mode-map [?\C-q] 'exwm-input-send-next-key) + (exwm-enable) + (setopt exwm-replace nil + exwm-manage-force-tiling nil + exwm-input-prefix-keys + `([?\C-x] + [?\C-u] + [?\C-g] + [?\C-h] + [?\C-z] + [?\C-`] + [?\M-x] + [?\M-`] + [?\M-&] + [?\M-:] + [?\M-!] + ,@(mapcar (lambda (i) + (kbd (concat "s-" (number-to-string i)))) + (number-sequence 0 9))) + + exwm-input-global-keys + `(([?\s-n] . other-window) + ([?\s-p] . (lambda () + (interactive) + (other-window -1))) + ([?\s-L] . bd/lock) + ([f2] . bd/toggle-mute) + ([f5] . bd/decrement-volume) + ([f6] . bd/increment-volume) + ([f7] . bd/decrement-brightness) + ([f8] . bd/increment-brightness) + ([f9] . emms-previous) + ([f10] . emms-next) + ([print] . bd/shoot-part) + ([S-print] . bd/shoot-full) + ([?\s-O] . bd/browse-dispatcher) + ([?\s-P] . bd/password) + ([?\s-r] . exwm-reset) + ([?\s-d] . toggle-window-dedicated) + ([?\s-t] . bd/toggle-tab-bar) + ([?\s-q] . kill-current-buffer) + ([?\s-x] . (lambda (command) + (interactive (list (read-shell-command "s-x "))) + (start-process-shell-command command nil command))) + ,@(mapcar (lambda (i) + `(,(kbd (format "s-%s" (car i))) . + (lambda () + (interactive + (exwm-workspace-switch-create ,(car (cdr i))))))) + '((! 0) (@ 1) (\# 2) ($ 3) (% 4) (^ 5) (& 6) (* 7) (\( 8) (\) 9)))) + + exwm-input-simulation-keys + '(([?\C-b] . [left]) + ([?\C-f] . [right]) + ([?\C-p] . [up]) + ([?\C-n] . [down]) + ([?\C-a] . [home]) + ([?\C-e] . [end]) + ([?\C-j] . [S-return]) + ([?\C-m] . [return]) + ([?\M-v] . [prior]) + ([?\C-v] . [next]) + ([?\C-d] . [delete]) + ([?\C-k] . [S-end delete]) + ([?\M-w] . [C-c]) + ([?\C-y] . [C-v]) + ([?\C-s] . [C-g]) + ([?\C-r] . [C-S-g]) + ([?\M-d] . [C-delete]) + ([?\M-b] . [C-left]) + ([?\M-f] . [C-right])))) + +(use-package exwm-outer-gaps + :defer 1 + :config + (setopt exwm-outer-gaps-mode 1 + exwm-outer-gaps-width 10) + (exwm-outer-gaps-apply)) + +(use-package server + :defer 1 + :config + (setopt server-client-instructions nil) + (unless (server-running-p) + (server-start))) + +(setopt tab-bar-select-tab-modifiers '(super)) + +(provide 'bd--exwm) +;;; bd--exwm.el ends here diff --git a/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--files.el b/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--files.el new file mode 100644 index 0000000..c2f3df8 --- /dev/null +++ b/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--files.el @@ -0,0 +1,92 @@ +;;; -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + + +(use-package files + :config + (setopt safe-local-variable-directories + '("/home/bdunahu/pt/guix"))) + +(use-package recentf + :demand t + :bind + (("C-x g" . recentf-open)) + :init + (recentf-mode 1) + :config + (setopt recentf-max-saved-items 3500 + recentf-auto-cleanup 300)) + +(defun bd/zathura (file) + "Open FILE with zathura." + (start-process "zathura" nil "zathura" (expand-file-name file))) +(defun bd/mpv (file) + "Open FILE with mpv." + (start-process "mpv" nil "mpv" "--force-window=yes" (expand-file-name file))) +(defun bd/info (file) + "Open FILE with info." + (info file)) +(defun bd/nsxiv (file) + "Open FILE with nsxiv." + (start-process "nsxiv" nil "nsxiv" (expand-file-name file))) +(defun bd/qemu (file) + "Open FILE with QEMU." + (let ((options `("qemu-system" nil "qemu-system-x86_64" ,(expand-file-name file) + "-net" "nic" "-net""user,hostfwd=tcp:127.0.0.1:2222-:22" + "--accel" "kvm" "-m" "8G"))) + (unless (string-match-p "graphic" file) + (setq options (append options (list "-nographic")))) + (apply 'start-process options))) +(defun bd/rom (file) + "Open FILE with an emulator." + (let ((command + (cdr (assoc (file-name-extension file) + '(("gba" . "mgba") + ("z64" . "mupen64plus") + ("iso" . "dolphin-emu") + ("ciso" . "dolphin-emu") + ("n64" . "mupen64plus") + ("sfc" . "bsnes")))))) + (start-process command nil command (expand-file-name file)))) + +(defun bd/external-find-file-wrapper (f &rest args) + "Wrapper around F (find-file), passing ARGS." + (defun bd/open-with-function (f) + (funcall f (car args)) + (recentf-add-file (car args))) + + (let ((ext (or (file-name-extension (car args)) ""))) + (cond + ((string-match (regexp-opt '("epub" "pdf")) ext) + (bd/open-with-function #'bd/zathura)) + ((string-match (regexp-opt '("mkv" "mov" "mp4" "webm" "m4v" + "wav" "mp3" "opus" "ogv" "flac" + "m4a" "ogg")) ext) + (bd/open-with-function #'bd/mpv)) + ((string-match (regexp-opt '("info")) ext) + (bd/open-with-function #'bd/info)) + ((string-match (regexp-opt '("jpg" "jpeg" "png" "webp" + "ico" "gif" "JPG" "PNG")) ext) + (bd/open-with-function #'bd/nsxiv)) + ((string-match (regexp-opt '("qcow2")) ext) + (bd/open-with-function #'bd/qemu)) + ((string-match (regexp-opt '("gba" "z64" "n64" "sfc" "iso" "ciso")) ext) + (bd/open-with-function #'bd/rom)) + (t (apply f args))))) +(advice-add #'find-file :around #'bd/external-find-file-wrapper) + +(use-package dired + :demand t + :config + (setopt dired-listing-switches "-alhLG --time-style=long-iso --group-directories-first" + dired-recursive-copies 'always + dired-recursive-deletes 'always + dired-auto-revert-buffer t + dired-dwim-target t + dired-guess-shell-alist-user + `((,(regexp-opt '(".pdf")) "pdftotext -nopgbrk -enc UTF-8 -eol unix -layout")))) + + +(provide 'bd--files) +;;; bd--files.el ends here diff --git a/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--gpg.el b/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--gpg.el new file mode 100644 index 0000000..88d9425 --- /dev/null +++ b/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--gpg.el @@ -0,0 +1,59 @@ +;;; -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + + +(defvar bd/password-store-kill-ring-pointer nil + "The tail of the kill ring whose car is the password.") +(defvar bd/password-store-time-before-clear 10 + "The time before a killed password is cleared.") + +(defun bd/password-store-list () + "List password-store entries." + (mapcar (lambda (file) + (file-name-sans-extension (file-relative-name file "~/.password-store/"))) + (directory-files-recursively "~/.password-store" ".*\\.gpg$"))) + +(defun bd/password-store-clear (id) + "Clears the most recent password copied to the kill ring, printing ID." + (when bd/password-store-kill-ring-pointer + (setcar bd/password-store-kill-ring-pointer nil) + (kill-new "") + (setq bd/password-store-kill-ring-pointer nil) + (message "Cleared password for %s from the kill ring and system clipboard." id))) + +(defun bd/read-password (id) + "Read the password-store entry corresponding to ID." + (bd/password-store-clear "id") + (let ((find-file-hook (remq 'recentf-track-opened-file find-file-hook))) + (find-file (concat "~/.password-store/" id ".gpg")) + (goto-char 1) + (kill-new (buffer-substring-no-properties (line-beginning-position) (line-end-position))) + (setq bd/password-store-kill-ring-pointer kill-ring-yank-pointer) + (kill-buffer (current-buffer)) + (run-at-time bd/password-store-time-before-clear nil + (lambda () (funcall #'bd/password-store-clear id))) + (message "Copied password for %s to the kill ring and system clipboard. Will clear in %s seconds." + id bd/password-store-time-before-clear))) + +(defun bd/password () + "Interactively select a password-store password." + (interactive) + (bd/read-password (completing-read "Yank: " (bd/password-store-list)))) + +(use-package pinentry + :defer 1 + :config + (pinentry-start) + (defun pinentry-toggle () + "Stops and starts Pinentry service. Workaround +for a bug I've encountered." + (interactive) + (pinentry-stop) + (pinentry-start)) + (setopt enable-recursive-minibuffers t + pinentry-popup-prompt-window nil)) + + +(provide 'bd--gpg) +;;; bd--gpg.el ends here diff --git a/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--image.el b/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--image.el new file mode 100644 index 0000000..1d5876c --- /dev/null +++ b/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--image.el @@ -0,0 +1,22 @@ +;;; -*- lexical-binding: t; -*- +;;; Commentary: +;;; not loaded bd 10/28/24 +;;; Code: + + +(use-package image-mode + :config + (defun toggle-mode-line () + "If the mode line is displayed, toggle it off. +If the mode line is off, set it to the default value." + (interactive) + (setq mode-line-format + (if mode-line-format + nil + (default-value 'mode-line-format)))) + (add-hook 'image-mode-hook 'toggle-mode-line) + (keymap-set image-mode-map "l" #'toggle-mode-line)) + + +(provide 'bd--image) +;;; bd--image.el ends here diff --git a/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--minibuffer.el b/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--minibuffer.el new file mode 100644 index 0000000..cf5641b --- /dev/null +++ b/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--minibuffer.el @@ -0,0 +1,171 @@ +;;; -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + + +(require 's) +(use-package icomplete + :demand t + :bind + ((:map icomplete-minibuffer-map + ("RET" . icomplete-force-complete-and-exit))) + :config + (setopt completing-read-function #'completing-read-default + read-file-name-function #'read-file-name-default + completion-styles '(basic + substring + initials + flex) + icomplete-delay-completions-threshold 0 + icomplete-compute-delay 0.10 + icomplete-show-matches-on-no-input nil + icomplete-separator " | " + completions-max-height '30 + completions-detailed t) + (icomplete-vertical-mode t)) + +(use-package completion-preview + :hook + ((comint-mode . completion-preview-mode) + (c-mode . completion-preview-mode) + (c++-mode . completion-preview-mode) + (emacs-lisp-mode . completion-preview-mode))) + +(use-package selector + :demand t + :config + (setopt selector-minibuffer-lines 15) + (defvar bd/navigate-recent-display-number 6 + "The number of recent buffers that show up in bd/navigate.") + (defvar bd/blacklisted-buffer-regexp-list + '( + "\\*Async Shell Command\\*" + "\\*http" + "\\magit-process" + "\\*Minibuf" + "\\*Echo Area" + "\\*newsticker" + "\\*Org Preview LaTeX Output\\*" + "\\*Shell Command Output\\*" + "\\*tramp" + "\\*eldoc" + "\\*server\\*" + ) + "Buffers that should not show up in buffer-related +selection commands.") + + (defun bd/buffer-blacklisted-p (buf) + "Return non-nil if BUF is blacklisted." + (cl-reduce (lambda (x y) (or x y)) (mapcar (lambda (r) (string-match r buf)) + bd/blacklisted-buffer-regexp-list))) + + (defun bd/buffer-list () + "Return a list of non-blacklisted buffers." + (cl-remove-if #'bd/buffer-blacklisted-p (mapcar 'buffer-name (buffer-list)))) + + (defun bd/selector-recent-buffers () + (selector-source-create + "Recent" + :candidates + (take bd/navigate-recent-display-number + (cl-remove-if (lambda (b) + (get-buffer-window b 'visible)) + (bd/buffer-list))) + :actions + selector-buffer-actions)) + + (defun bd/selector-project-files () + (selector-source-create + "Project Files" + :candidates + (let ((proj (project-current))) + (when proj + (project-files proj))) + :actions + selector-file-actions)) + + (defmacro bd/selector-buffer-type (name c) + `(selector-source-create + ,name + :candidates + (cl-remove-if-not ,c (bd/buffer-list)) + :actions + selector-buffer-actions)) + + (defun bd/navigate () + (interactive) + (selector + (list + (bd/selector-recent-buffers) + (bd/selector-buffer-type "EWW" #'bd/buffer-eww-p) + (bd/selector-buffer-type "EXWM" #'bd/buffer-exwm-p) + (bd/selector-buffer-type "Shell" #'bd/buffer-shell-p) + (bd/selector-buffer-type "IRC" #'bd/buffer-irc-p) + (bd/selector-buffer-type "Text" #'bd/buffer-text-p) + (bd/selector-buffer-type "Source" #'bd/buffer-prog-p) + (bd/selector-buffer-type "Scratch" #'bd/buffer-scratch-p) + (bd/selector-buffer-type "Directories" #'bd/buffer-dired-p) + (bd/selector-buffer-type "Ordinary" #'bd/buffer-ordinary-p) + (bd/selector-project-files) + (selector-recentf-source)))) + (keymap-global-set "C-x b" 'bd/navigate) + + (defun bd/selector-rg () + "Sources for lines found via grep (or a clone)." + (interactive) + (let ((query (read-string "rg: "))) + (defun conv (x) + (cons (car x) (cons (- (string-to-number (cadr x)) 1) (caddr x)))) + (defun all-in-file (key list) + (--map (to-candidate (cdr it)) (--filter (s-equals? key (car it)) list))) + (defun to-candidate (x) + (selector-candidate-create (cdr x) :value (car x))) + (let* ((dir (expand-file-name (bd/get-directory-dwim))) + (result (with-temp-buffer + (call-process "rg" nil t nil "-n" "-." query dir) + (buffer-string))) + (lines (--map (conv (s-split-up-to ":" it 2)) (--filter (not (s-blank? it)) (s-split "\n" result)))) + (files (-uniq (-map #'car lines))) + (sources (--map (selector-source-create + it + :candidates (all-in-file it lines) + :actions (selector-file-contents-actions it)) + files))) + (when (not (null sources)) + (selector sources))))) + (keymap-global-set "C-z s" 'bd/selector-rg) + (keymap-global-set "C-z d" 'bd/selector-occur)) + +(defun bd/selector-occur () + "Sources for lines in the current file." + (interactive) + (when-let ((file (buffer-file-name))) + (selector (list (selector-file-contents-source file))))) + +(defun bd/selector-rg () + "Sources for lines found via grep (or a clone)." + (interactive) + (let ((query (read-string "rg: "))) + (defun conv (x) + (cons (car x) (cons (- (string-to-number (cadr x)) 1) (caddr x)))) + (defun all-in-file (key list) + (--map (to-candidate (cdr it)) (--filter (s-equals? key (car it)) list))) + (defun to-candidate (x) + (selector-candidate-create (cdr x) :value (car x))) + (let* ((dir (expand-file-name (bd/get-directory-dwim))) + (result (with-temp-buffer + (call-process "rg" nil t nil "-n" "-." query dir) + (buffer-string))) + (lines (--map (conv (s-split-up-to ":" it 2)) (--filter (not (s-blank? it)) (s-split "\n" result)))) + (files (-uniq (-map #'car lines))) + (sources (--map (selector-source-create + it + :candidates (all-in-file it lines) + :actions (selector-file-contents-actions it)) + files))) + (when (not (null sources)) + (selector sources))))) + + +(provide 'bd--minibuffer) +;;; bd--minibuffer.el ends here diff --git a/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--modeline.el b/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--modeline.el new file mode 100644 index 0000000..2ca7ccb --- /dev/null +++ b/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--modeline.el @@ -0,0 +1,99 @@ +;;; -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + + +;;;; remove all the stupid stupid stupid crap +(define-minor-mode minor-mode-blackout-mode + "Hides minor modes from the mode line." + t) + +(catch 'done + (mapc (lambda (x) + (when (and (consp x) + (equal (cadr x) '("" minor-mode-alist))) + (let ((original (copy-sequence x))) + (setcar x 'minor-mode-blackout-mode) + (setcdr x (list "" original))) + (throw 'done t))) + mode-line-modes)) +(global-set-key (kbd "C-c ,") 'minor-mode-blackout-mode) + +(defvar-local bd/buffer-identification-mode-line + '(:eval (format "%s" (propertize (buffer-name) 'face + (if (mode-line-window-selected-p) + 'modus-themes-fg-cyan-intense + 'mode-line-inactive)))) + "Formats the modeline-buffer-name.") + +(defvar-local bd/project-mode-line + '(:eval + (when-let ((project (project-current)) + (file? (buffer-file-name))) + (let ((last-coding-system-used last-coding-system-used)) + (format "%s " + (propertize + (project-name project) + 'face 'shadow + 'mouse-face 'mode-line-highlight + 'help-echo "mouse-1: Project menu" + 'local-map project-mode-line-map)))))) + +(defvar-local bd/global-mode-string + '(:eval (when (mode-line-window-selected-p) + global-mode-string)) + "Displays the global mode string only on the current window.") + +(column-number-mode 1) +(setopt mode-line-position-column-line-format '("%l:%c") + mode-line-percent-position nil) +(defvar-local bd/line-position + '(:eval + (when (mode-line-window-selected-p) + mode-line-position))) + +(defvar-local bd/vc-mode-line + '(:eval (when vc-mode + (format "%s " + (propertize (cadr (split-string vc-mode "[:-]")) 'face 'shadow)))) + "Formats the checked out git repository.") + +(defvar-local bd/modeline-window-dedicated + '(:eval + (when (window-dedicated-p) + (format "%s -- " + (propertize "LK" 'face 'font-lock-comment-face)))) + "Indicator for dedicated window.") + +(dolist (construct '(bd/buffer-identification-mode-line + bd/project-mode-line + bd/vc-mode-line + bd/global-mode-string + bd/line-position + bd/modeline-window-dedicated)) + (put construct 'risky-local-variable t)) + + +(setopt mode-line-right-align-edge 'window) +(setq-default mode-line-format + '("%e" + mode-line-front-space + bd/project-mode-line + bd/buffer-identification-mode-line + " -- " + mode-line-modes + "-- " + bd/line-position + mode-line-format-right-align + bd/modeline-window-dedicated + bd/vc-mode-line + mode-line-mule-info + mode-line-modified + mode-line-front-space + bd/global-mode-string + mode-line-front-space + )) + + +(provide 'bd--modeline) +;;; bd--modeline.el ends here diff --git a/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--notes.el b/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--notes.el new file mode 100644 index 0000000..13f80f4 --- /dev/null +++ b/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--notes.el @@ -0,0 +1,77 @@ +;;; -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + + +(defvar scratch-buffer nil + "Non-nil if the current buffer is a scratch buffer.") +(make-variable-buffer-local 'scratch-buffer) +(defun bd/send-to-scratch () + "Creates/switches to the scratch for `major-mode', +then pastes the active region." + (interactive) + (let* ((mode major-mode) + (name (format "*scratch for %s*" mode)) + (contents (when (region-active-p) + (buffer-substring-no-properties + (region-beginning) (region-end)))) + (buf (get-buffer name))) + (pop-to-buffer + (with-current-buffer (get-buffer-create name) + (funcall mode) + (setq-local scratch-buffer t) + (when contents + (insert (format "\n\n%s" contents))) + (current-buffer))))) +(keymap-global-set "C-c s" #'scratch-buffer) +(keymap-global-set "C-c C-s" #'bd/send-to-scratch) +;; default *scratch* must have var set +(add-hook 'emacs-startup-hook + (lambda () + (with-current-buffer "*scratch*" + (setq-local scratch-buffer t)))) +(advice-add 'scratch-buffer :after (lambda () (setq-local scratch-buffer t))) + +(use-package denote + :defer 1 + :hook + ((dired-mode . denote-dired-mode-in-directories)) + :bind (("C-c d d" . 'denote) + ("C-c d f" . 'denote-open-or-create) + :map org-mode-map + ("C-c l" . 'denote-link)) + :config + + (defconst bd/denote-skribe-front-matter + "(post + :title \"%s\" + :date %s + :tags '(\"%s\") + ;; identifier: %s +\n\n)") + (defun bd/denote-skribe-format-date (date) + "Format DATE as a scheme procedure." + (format-time-string "(make-date* %Y %m %d %H %M)" date)) + (defun bd/denote-format-keywords-for-skribe-front-matter (keywords) + "Format front matter KEYWORDS for skribe file type. +KEYWORDS is a list of strings." + (string-join keywords "\" \"")) + :config + (setopt denote-file-type 'org + denote-known-keywords + '("ss" "writing" "reading" "art" + "csu" "umass" "cs" "guix" + "emacs" "programs" "mem") + denote-directory (expand-file-name "~/dc/") + denote-prompts '(title file-type keywords subdirectory) + denote-dired-directories (list denote-directory))) + +(use-package denote-journal + :bind (("C-c d j" . 'denote-journal-new-or-existing-entry)) + :config + (setopt denote-journal-directory (expand-file-name "~/dc/log") + denote-journal-title-format 'day-date-month-year)) + + +(provide 'bd--notes) +;;; bd--notes.el ends here diff --git a/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--org.el b/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--org.el new file mode 100644 index 0000000..b88a72b --- /dev/null +++ b/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--org.el @@ -0,0 +1,255 @@ +;;; -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + + +(require 'fill-column) +(use-package org + :demand t + :hook + ((org-mode . (lambda () + (org-indent-mode) + (org-toggle-inline-images) + (fill-column-mode) + (abbrev-mode) + (org-latex-preview '(16))))) + :config + (setopt org-ellipsis " ▾" + org-babel-python-command "python3" + org-confirm-babel-evaluate nil + org-hide-emphasis-markers t + org-startup-folded 'showeverything + org-src-window-setup 'current-window) + (plist-put org-format-latex-options :scale 1.3) + (push '("\\.pdf\\'" . "zathura %s") org-file-apps) + (add-hook 'org-babel-after-execute-hook #'org-redisplay-inline-images) + (org-babel-do-load-languages + 'org-babel-load-languages + '((emacs-lisp . t) + (shell . t) + (lisp . t) + (scheme . t) + (dot . t) + (latex . t) + (python . t))) + (define-abbrev org-mode-abbrev-table + "lbm" "\\begin{equation*}\n\\begin{bmatrix}\n\\end{bmatrix}\n\\end{equation*}") + (define-abbrev org-mode-abbrev-table + "lca" "\\begin{equation*}\n\\begin{cases}\n\\end{cases}\n\\end{equation*}") + (define-abbrev org-mode-abbrev-table + "gvd" "#+begin_src dot :file images/1.png\ndigraph g {\nrankdir=LR;\n\tnode [shape = doublecircle]; A;\n\tnode [shape = point]; qi\n\tnode[shape=circle];\n}\n#+end_src") + (define-abbrev org-mode-abbrev-table + "les" "\\begin{equation*}\n\\end{equation*}") + (define-abbrev org-mode-abbrev-table + "lbm" "\\begin{equation*}\n\\begin{bmatrix}\n\\end{bmatrix}\n\\end{equation*}") + (define-abbrev org-mode-abbrev-table + "lds" "\\begin{drawstack}\n\\end{drawstack}")) + +(use-package ox + :config + (add-to-list 'org-latex-packages-alist '("" "listings")) + (setopt org-latex-toc-command "\\tableofcontents \\clearpage" + org-latex-src-block-backend 'listings + org-latex-image-default-width ".6\\linewidth" + org-latex-compiler "xelatex" + org-export-with-toc nil + org-export-preserve-breaks nil + org-latex-classes + '(("article" + "\\PassOptionsToPackage{svgnames}{xcolor} +\\documentclass[11pt]{article} +\\usepackage[margin=1in]{geometry} +\\usepackage{xcolor,color,tikz,amsmath,amssymb,amsthm,amsfonts,graphicx,enumitem,listings,comment} +\\lstset{frame=single,aboveskip=1em, + framesep=.5em,backgroundcolor=\\color{AliceBlue}, + rulecolor=\\color{Black},framerule=1pt} +\\usepackage{xcolor} +\\newcommand\\basicdefault[1]{\\scriptsize\\color{Black}\\fontfamily{pcr}\\selectfont} +\\lstset{basicstyle=\\basicdefault{\\spaceskip1em}} +\\lstset{keywordstyle=\\color{DarkGreen}\\bfseries, + identifierstyle=\\color{DarkRed}, + commentstyle=\\color{DimGray}\\upshape, + stringstyle=\\color{DarkBlue}\\upshape, + emphstyle=\\color{Chocolate}\\upshape, + showstringspaces=false, + columns=fullflexible, + keepspaces=true} +\\lstset{columns=fullflexible,basicstyle=\\ttfamily} +\\setlength{\\headsep}{0.75 in} +\\setlength{\\parskip}{0.1 in} + +\\makeatletter +\\renewcommand{\\maketitle}{% + \\begingroup\\parindent0pt + \\begin{center} + \\LARGE{\\bfseries\\@title}\\par\\bigskip + \\large{\\@author}\\par\\medskip + \\normalsize\\@date\\par\\bigskip + \\end{center} + \\endgroup\\@afterindentfalse\\@afterheading} +\\makeatother +[DEFAULT-PACKAGES] +\\hypersetup{linkcolor=Blue,urlcolor=DarkBlue, + citecolor=DarkRed,colorlinks=true} +[PACKAGES] +[EXTRA]" + ("\\section{%s}" . "\\section*{%s}") + ("\\subsection{%s}" . "\\subsection*{%s}") + ("\\subsubsection{%s}" . "\\subsubsection*{%s}") + ("\\paragraph{%s}" . "\\paragraph*{%s}") + ("\\subparagraph{%s}" . "\\subparagraph*{%s}")) + ("report" "\\documentclass[11pt]{report}" + ("\\part{%s}" . "\\part*{%s}") ("\\chapter{%s}" . "\\chapter*{%s}") + ("\\section{%s}" . "\\section*{%s}") + ("\\subsection{%s}" . "\\subsection*{%s}") + ("\\subsubsection{%s}" . "\\subsubsection*{%s}")) + ("acmart" "\\PassOptionsToPackage{svgnames}{xcolor} +\\documentclass[sigconf,authorversion,nonacm]{acmart} +\\usepackage{xcolor,color,tikz,amsmath,amssymb,amsthm,amsfonts,graphicx,enumitem,listings,comment} +\\usepackage{xcolor} +\\lstset{frame=single,aboveskip=1em, + framesep=.5em,backgroundcolor=\\color{AliceBlue}, + rulecolor=\\color{Black},framerule=1pt} +\\lstset{keywordstyle=\\color{DarkGreen}\\bfseries, + identifierstyle=\\color{DarkRed}, + commentstyle=\\color{DimGray}\\upshape, + stringstyle=\\color{DarkBlue}\\upshape, + emphstyle=\\color{Chocolate}\\upshape, + showstringspaces=false, + columns=fullflexible, + keepspaces=true}" + ("\\section{%s}" . "\\section*{%s}") + ("\\subsection{%s}" . "\\subsection*{%s}") + ("\\subsubsection{%s}" . "\\subsubsection*{%s}") + ("\\paragraph{%s}" . "\\paragraph*{%s}") + ("\\subparagraph{%s}" . "\\subparagraph*{%s}")) + ("book" "\\documentclass[11pt]{book}" ("\\part{%s}" . "\\part*{%s}") + ("\\chapter{%s}" . "\\chapter*{%s}") + ("\\section{%s}" . "\\section*{%s}") + ("\\subsection{%s}" . "\\subsection*{%s}") + ("\\subsubsection{%s}" . "\\subsubsection*{%s}"))))) + +(use-package oc + :config + (setopt org-cite-global-bibliography + (directory-files-recursively + (concat (xdg-user-dir "DOCUMENTS") "/bib/") + ".*\\.bib$") + org-cite-export-processors + '((latex biblatex)))) + +(use-package org-agenda + :bind + (("C-c n a" . org-agenda) + ("C-c n c" . org-capture) + ("C-c n s" . org-schedule) + ("C-c n d" . org-deadline) + ("C-c n r" . org-refile)) + :config + (advice-add 'org-refile :after 'org-save-all-org-buffers) + + (defvar-local bd/course-list + '(("598" . ?0)) + "Courses for tagging, capturing, and various +agenda views.") + + (defvar-local bd/device-list + '(("garmr" . ?G) + ("heimdallr" . ?H) + ("hodr" . ?M) + ("surt" . ?I) + ("vali" . ?V)) + "Devices for tagging, capturing, and various +agenda views.") + + (defun bd/combine-tags (tag-alist add? or-p) + "Given TAG-ALIST in the form of +ORG-TAG-ALIST, returns a concatenated string +representing all the tags ORd or ANDed together." + (apply #'concat + (mapcar (lambda (e) + (concat (when or-p "|") (if add? "+" "-") (car e))) + tag-alist))) + + (setopt org-log-done 'time + org-deadline-warning-days 7 + org-log-into-drawer "history" + org-agenda-restore-windows-after-quit t + org-agenda-show-future-repeats nil + org-agenda-block-separator nil + org-deadline-warning-days 0 + org-todo-keywords + '((sequence "TODO(t)" "NEXT(n!)" "HOLD(h!)" "|" "DONE(d)" "CANC(c)")) + org-tag-alist + `(("noexport" . ?e) + + ("chore" . ?C) + ,@bd/device-list + + ("idea" . ?i) + ("programming" . ?p) + ("web" . ?s) + ("writing" . ?w) + ("reading" . ?r) + + ,@bd/course-list) + org-directory "~/dc/agenda/" + + org-agenda-files (list org-directory) + org-refile-use-outline-path 'file + org-refile-targets '((org-agenda-files :level . 0)) + org-capture-templates + `(("t" "Task Entry" entry + (file ,(concat org-directory "inbox.org")) + "* %?\n:PROPERTIES:\n:CREATED: %U\n:END:\n%i\nrecorded visiting: %a" + :empty-lines 1))) + + (let ((orphan-view '(tags-todo "-{.*}" + ((org-agenda-overriding-header "\nUnfiltered Items\n"))))) + (setopt org-agenda-custom-commands + `(("c" "Chores" + ((agenda "" ((org-agenda-entry-types '(:deadline)) + (org-agenda-show-all-dates nil) + (org-agenda-span 21) + (org-agenda-skip-function + '(org-agenda-skip-entry-if 'notregexp + (regexp-opt (cons "chore" (mapcar #'car bd/device-list))))) + (org-agenda-overriding-header "Priority Deadlines (+21d)\n"))) + (tags-todo (concat "chore" (bd/combine-tags bd/device-list nil nil)) + ((org-agenda-overriding-header "\nMundane\n"))) + ,@(mapcar (lambda (e) + `(tags-todo ,(car e) + ((org-agenda-overriding-header + (concat "\nDevice: " ,(capitalize (car e)) "\n"))))) + bd/device-list) + ,orphan-view)) + ("r" "Recreational" + ((tags-todo "+idea" + ((org-agenda-skip-function + '(org-agenda-skip-entry-if 'regexp "chore")) + (org-agenda-overriding-header "Ideas\n"))) + (tags-todo "+reading|+writing" + ((org-agenda-skip-function + '(org-agenda-skip-entry-if 'regexp "chore")) + (org-agenda-overriding-header "\nReading/Writing\n"))) + (tags-todo "+programming|+web" + ((org-agenda-skip-function + '(org-agenda-skip-entry-if 'regexp "chore")) + (org-agenda-overriding-header "\nProgramming\n"))) + ,orphan-view)) + ("s" "College" + ((tags-todo (bd/combine-tags bd/course-list t t) + ((org-agenda-overriding-header "\nAll Courses\n"))) + (agenda "" ((org-agenda-entry-types '(:deadline :scheduled)) + (org-agenda-show-all-dates nil) + (org-agenda-span 15) + (org-scheduled-past-days 7) + (org-agenda-skip-function + '(org-agenda-skip-entry-if 'notregexp + (regexp-opt (mapcar #'car bd/course-list)))) + (org-agenda-overriding-header "\nUpcoming Deadlines (+15d)\n"))) + ,orphan-view)))))) + + +(provide 'bd--org) +;;; bd--org.el ends here diff --git a/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--project.el b/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--project.el new file mode 100644 index 0000000..243e3cd --- /dev/null +++ b/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--project.el @@ -0,0 +1,18 @@ +;;; -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + + +(use-package project + :defer t + :config + (setopt project-switch-commands + '((project-find-file "Find file") + (project-find-regexp "Find regexp") + (project-find-dir "Find directory") + (magit-project-status "Magit") + (project-shell "Shell")))) + + +(provide 'bd--project) +;;; bd--project.el ends here diff --git a/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--shells.el b/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--shells.el new file mode 100644 index 0000000..1072694 --- /dev/null +++ b/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--shells.el @@ -0,0 +1,135 @@ +;;; -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + + +(add-to-list 'exec-path "/home/bdunahu/.local/bin") + +(use-package vterm + :config + (with-eval-after-load "term" (defalias 'term 'vterm)) + ;; use vterm for visual visual commands + (defun bd/eshell-exec-visual (&rest args) + "Run the specified PROGRAM in a vterm emulation buffer. +ARGS are passed to the program. At the moment, no piping of input is +allowed." + (let* (eshell-interpreter-alist + (interp (eshell-find-interpreter (car args) (cdr args))) + (program (car interp)) + (args (mapconcat #'shell-quote-argument + (flatten-tree + (eshell-stringify-list (append (cdr interp) + (cdr args)))) " ")) + (term-buf + (generate-new-buffer + (concat "*" (file-name-nondirectory program) "*"))) + (eshell-buf (current-buffer)) + (vterm-shell (concat (shell-quote-argument + (file-local-name program)) + " " args))) + (save-current-buffer + (switch-to-buffer term-buf) + (vterm-mode) + (setq-local eshell-parent-buffer eshell-buf) + (let ((proc (get-buffer-process term-buf))) + (if (and proc (eq 'run (process-status proc))) + (set-process-sentinel proc #'eshell-term-sentinel) + (error "Failed to invoke visual command"))))) + nil) + (advice-add #'eshell-exec-visual :override #'bd/eshell-exec-visual)) + +(use-package esh-module + :config + (add-to-list 'eshell-modules-list 'eshell-smart)) + +(use-package esh-mode + :config + (setopt eshell-scroll-to-bottom-on-input 'this)) + +(use-package em-banner + :config + (setopt eshell-banner-message (concat "\n" (propertize " " 'display (create-image (expand-file-name "images/wolf.png" user-emacs-directory) 'png nil :scale 0.8 :align-to "center")) "\n"))) + +(use-package em-hist + :config + (setopt eshell-hist-ignoredups t + eshell-history-append t)) + +(use-package em-term + :config + (mapc (lambda (x) (add-to-list 'eshell-visual-commands x)) + '( + "angband" + "nethack" + "r2" + )) + (setopt eshell-destroy-buffer-when-process-dies t)) + +(use-package em-unix + :config + (setopt eshell-cp-overwrite-files nil + eshell-mv-overwrite-files nil)) + +(use-package em-prompt + :config + (defun bd/get-prompt-path () + (abbreviate-file-name (eshell/pwd))) + (defun bd/eshell-prompt () + "Return a prettified shell prompt." + (concat + (system-name) + (format " %s" (bd/get-prompt-path)) + " >\n")) + (setopt eshell-prompt-function 'bd/eshell-prompt + eshell-prompt-regexp (rx bol (eval (system-name)) (one-or-more anything) " >\n"))) + +(use-package eshell + :bind + (:map eshell-mode-map + ("<tab>" . #'completion-at-point)) + :config + (defun eshell/clear (&optional scrollback) + "Clear the eshell buffer and output the banner message." + (interactive) + (let ((inhibit-read-only t)) + (delete-all-overlays) + (set-text-properties (point-min) (point-max) nil) + (erase-buffer) + (eval eshell-banner-message))) + (defun eshell/c (&optional scrollback) + (eshell/clear scrollback)) + (defun eshell/o (file) + (interactive) + (find-file file)) + (setopt eshell-buffer-maximum-lines 7500)) + + +(use-package shell + :bind + (:map shell-mode-map + ("C-c C-k" . #'comint-clear-buffer)) + :config + (setopt shell-command-prompt-show-cwd t + shell-highlight-undef-enable t + shell-kill-buffer-on-exit t + comint-prompt-read-only t)) + + +(use-package proced + :defer t + :hook (proced-mode . + (lambda () + (visual-line-mode -1) + (toggle-truncate-lines 1) + (proced-toggle-auto-update 1))) + :config + (setopt proced-enable-color-flag t + proced-tree-flag t + proced-auto-update-flag 'visible + proced-auto-update-interval 3 + proced-descend t + proced-filter 'user)) + + +(provide 'bd--shells) +;;; bd--shells.el ends here diff --git a/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--tabs.el b/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--tabs.el new file mode 100644 index 0000000..6d4f12f --- /dev/null +++ b/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--tabs.el @@ -0,0 +1,43 @@ +;;; -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + + +(use-package tab-bar + :demand t + :config + (defun bd/get-mode-line-modes (buffer) + (with-current-buffer buffer + (format-mode-line (remove '(t erc-modified-channels-object) mode-line-modes)))) + (defun bd/tab-bar-name-function () + (concat (tab-bar-tab-name-current) + " " + (bd/get-mode-line-modes (window-buffer (minibuffer-selected-window))))) + (defun bd/toggle-tab-bar () + (interactive) + (setopt tab-bar-show (not tab-bar-show)) + ;; required to wait for the frame to update + (sit-for 0) + ;; dumb outer-gaps bug + (exwm-outer-gaps-apply)) + + (tab-bar-select-tab 1) + (tab-bar-mode) + (tab-bar-history-mode) + (setopt tab-bar-tab-name-function #'bd/tab-bar-name-function + tab-bar-show t + + tab-bar-select-restore-windows nil + + ;; remove useless gui elements + tab-bar-format + '(tab-bar-format-tabs) + tab-bar-close-button-show nil + tab-bar-auto-width-max nil + + ;; add useless text elements + tab-bar-tab-hints nil)) + + +(provide 'bd--tabs) +;;; bd--tabs.el ends here diff --git a/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--themes.el b/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--themes.el new file mode 100644 index 0000000..cd24cab --- /dev/null +++ b/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--themes.el @@ -0,0 +1,115 @@ +;;; -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + + +(use-package modus-themes + :load-path (lambda () (expand-file-name "themes/" data-directory)) + :demand t + :init + (load-theme 'modus-vivendi-tinted t) + :hook + ((modus-themes-post-load . bd/modus-set-faces)) + :config + (defun bd/modus-set-faces (&rest _) + "Blends the modeline with the echo area, +and some other minor face changes." + (modus-themes-with-colors + (custom-set-faces + `(eshell-prompt ((,c :foreground ,fg-main :background ,bg-prose-block-contents :height 1.1 :extend t)))))) + (setopt modus-themes-to-toggle '(modus-operandi-tinted modus-vivendi-tinted) + modus-themes-mixed-fonts t + modus-themes-italic-constructs t + modus-themes-bold-constructs t + modus-themes-variable-pitch-ui t + modus-themes-prompts '(bold) + modus-themes-headings + '((0 variable-pitch regular 1.4) + (1 variable-pitch regular 1.4) + (2 variable-pitch regular 1.3) + (3 variable-pitch regular 1.2) + (t variable-pitch regular 1.2)) + modus-themes-common-palette-overrides + '((bg-main "#000B0E") ;; primary + (bg-active bg-main) + (fg-main "#c6b7ad") + (fg-active fg-main) + (fg-mode-line-active "#008EA2") + (bg-mode-line-active "#012C31") ;; primary + (fg-mode-line-inactive "#8D6D91") + (bg-mode-line-inactive "#442c50") ;; secondary + (border-mode-line-active nil) + (border-mode-line-inactive nil) + (bg-tab-bar bg-main) + (bg-tab-current "#042429") ;; primary + (bg-tab-other "#100014") ;; secondary + + (fg-heading-0 "#b2ebf2") + (fg-heading-1 "#98fb98") + (fg-heading-2 "#fa80e6") + (fg-heading-3 "#ff7f50") + (fg-heading-4 "#ffd700") + + (fg-prompt "#FF4E00") ;; tertiary + (bg-prompt unspecified) + + (bg-region "#E65C19") ;; tertiary + (fg-region "#fffff0") + + (bg-hl-line "#034852") ;; primary + + (fg-line-number-active fg-main) + (fg-line-number-inactive "#a9a9a9") + (bg-line-number-active unspecified) + (bg-line-number-inactive "#0D5D62") ;; primary + + (fringe bg-main) + (cursor "#FF5300") ;; tertiary + + (fg-prose-verbatim "#af9fff") + (bg-prose-block-contents "#244449") ;; primary + (fg-prose-block-delimiter "#c6b7ad") + (bg-prose-block-delimiter bg-prose-block-contents) + + (keyword "#4dd0e1") + (builtin "#a490ff") + (comment "#afa7b0") + (string "#50f2ca") + (fnname "#d8afd8") + (type "#89c6f9") + (variable "#98fb98") + (docstring "#f0e68c") + (constant "#fa80e6")))) +(run-hooks 'modus-themes-post-load-hook) + +(defun bd/enable-variable-pitch-exempt () + "Text modes to exempt from variable pitch fonts." + (unless (derived-mode-p 'latex-mode 'mhtml-mode 'nxml-mode 'yaml-mode) + (variable-pitch-mode 1))) + +(defvar bd/enable-variable-pitch-in-hooks + '(text-mode-hook) + "List of hook symbols to add `variable-pitch-mode' +to.") + +(mapc + (lambda (hook) + (add-hook hook #'bd/enable-variable-pitch-exempt)) + bd/enable-variable-pitch-in-hooks) + +(set-face-attribute 'variable-pitch nil + :family "Dejavu Serif" + :height 130) +(set-face-attribute 'fixed-pitch nil + :family "Iosevka" + :height 100) +(set-face-attribute 'default nil + :family "Iosevka" + :height 140) +(set-face-attribute 'modus-themes-ui-variable-pitch nil + :family "Iosevka" + :height 90) + + +(provide 'bd--themes) +;;; bd--themes.el ends here diff --git a/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--utility.el b/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--utility.el new file mode 100644 index 0000000..ee74f58 --- /dev/null +++ b/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--utility.el @@ -0,0 +1,160 @@ +;;; -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + +(require 'project) +(require 'xdg) + + +(defun bd/set-frame-alpha (value) + "Set the transparency of ALL frame backgrounds to VALUE. 0=transparent/100=opaque." + (interactive "nTransparency Value (50 - 100 opaque): ") + (setq value (max 50 (min value 100))) + (mapc (lambda (f) + (set-frame-parameter f 'alpha `(,value . ,value))) + (frame-list)) + (message "Alpha set to %d" value)) + +(defun bd/set-bg (&optional arg) + "Set the current wallpaper using feh. +ARG can be one of the following: + +- nil: set the most recent wallpaper +- directory: set a random image from the directory +- file: set the specified file" + (interactive + (list (read-file-name + "Select a wallpaper: " + (expand-file-name "~/wf/wall/") nil t))) + (let ((wall (expand-file-name "~/wf/wall/current"))) + (when arg + (cond + ((file-regular-p arg) (copy-file arg wall t)) + ((file-directory-p arg) + (let* ((images (directory-files arg (lambda (f) (string-match-p "\\.jpeg\\'" f)))) + (rfile (nth (random (length images)) images))) + (and rfile (copy-file rfile wall t)))))) + (start-process "set wallpaper" nil "feh" "--bg-fill" wall) + (message "Set wallpaper."))) + +(defun bd/lock () + "Lock the screen." + (interactive) + (start-process "lock" nil "slock")) + +(defun bd/shoot-full () + "Take a full-screen screenshot." + (interactive) + (let ((default-directory (xdg-user-dir "PICTURES"))) + (start-process-shell-command "flameshot" nil "flameshot full"))) + +(defun bd/shoot-part () + "Take a selective screen screenshot." + (interactive) + (let ((default-directory (xdg-user-dir "PICTURES"))) + (start-process-shell-command "flameshot" nil "flameshot launcher"))) + +(defun bd/toggle-mute () + "Toggle between muted and unmuted." + (interactive) + (start-process "sound toggle" nil "pactl" "set-sink-mute" "@DEFAULT_SINK@" "toggle")) + +(defun bd/set-volume (value) + "Set the volume to VALUE." + (start-process "set volume" nil "pactl" "set-sink-volume" "@DEFAULT_SINK@" value)) + +(defun bd/decrement-volume () + "Decrements the volume." + (interactive) + (bd/set-volume "-4%")) + +(defun bd/increment-volume () + "Increments the volume." + (interactive) + (bd/set-volume "+4%")) + +(defun bd/set-brightness (value) + "Set the brightness to VALUE." + (start-process "set brightness" nil "brightnessctl" "set" value)) + +(defun bd/decrement-brightness () + "decrements the brightness." + (interactive) + (bd/set-brightness "5%-")) + +(defun bd/increment-brightness () + "Increments the brightness." + (interactive) + (bd/set-brightness "5%+")) + +(defun bd/get-directory-dwim () + "Return the directory you always wanted." + (or (when (project-current) + (project-root (project-current))) ;; git + (locate-dominating-file "." "Makefile") ;; make + (locate-dominating-file "." "manifest.scm") ;; guix + default-directory)) + +(defun bd/buffer-eww-p (buf) + "Return non-nil if BUF is a `eww-mode' buffer." + (member + (buffer-local-value 'major-mode (get-buffer buf)) + '(eww-mode))) + +(defun bd/buffer-exwm-p (buf) + "Return non-nil if BUF is an `exwm-mode' buffer and is in the current workspace." + (and (member + (buffer-local-value 'major-mode (get-buffer buf)) + '(exwm-mode)) + (eq (exwm-workspace--position exwm-workspace--current) + (alist-get 'exwm--desktop (buffer-local-variables (get-buffer buf)))))) + +(defun bd/buffer-scratch-p (buf) + "Return non-nil if BUF is a scratch buffer." + (buffer-local-value 'scratch-buffer (get-buffer buf))) + +(defun bd/buffer-text-p (buf) + "Return non-nil if BUF derives from `text-mode'." + (provided-mode-derived-p (buffer-local-value 'major-mode (get-buffer buf)) 'text-mode)) + +(defun bd/buffer-prog-p (buf) + "Return non-nil if BUF derives from `prog-mode'." + (provided-mode-derived-p (buffer-local-value 'major-mode (get-buffer buf)) 'prog-mode)) + +(defun bd/buffer-shell-p (buf) + "Return non-nil if BUF derives from `text-mode'." + (member + (buffer-local-value 'major-mode (get-buffer buf)) + '(shell-mode eshell-mode term-mode vterm-mode))) + +(defun bd/buffer-dired-p (buf) + "Return non-nil if BUF is a `dired-mode' buffer." + (member + (buffer-local-value 'major-mode (get-buffer buf)) + '(dired-mode))) + +(defun bd/buffer-irc-p (buf) + "Return non-nil if BUF is an `irc-mode' buffer." + (member + (buffer-local-value 'major-mode (get-buffer buf)) + '(rcirc-mode erc-mode))) + +(defun bd/buffer-ordinary-p (buf) + "Return non-nil if BUF does not fit into known categories." + (not (or (bd/buffer-eww-p buf) + (bd/buffer-exwm-p buf) + (bd/buffer-text-p buf) + (bd/buffer-prog-p buf) + (bd/buffer-shell-p buf) + (bd/buffer-scratch-p buf) + (bd/buffer-dired-p buf) + (bd/buffer-irc-p buf)))) + +(defun bd/kill-quietly (proc) + "Kill PROC quietly." + (ignore-errors (cond ((bufferp proc) (kill-buffer proc)) + ((stringp proc) (interrupt-process proc))))) + + +(provide 'bd--utility) +;;; bd--utility.el ends here diff --git a/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--window.el b/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--window.el new file mode 100644 index 0000000..bdc173b --- /dev/null +++ b/kolwynia/home/bdunahu/files/.config/emacs/modules/bd--window.el @@ -0,0 +1,59 @@ +;;; -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + + +(require 'transient) + +(setopt switch-to-buffer-obey-display-actions t + switch-to-buffer-in-dedicated-window 'pop) +;; C-u C-h a ^display-buffer-[^-] +(add-to-list 'display-buffer-alist + '("^\\*Async Shell Command\\*.*$" + (display-buffer-no-window))) + +(defun bd/layout--do-with-haste (f) + (let* ((args (transient-args 'bd/layout-dispatcher)) + (haste (if (member "haste" args) 3 1))) + (funcall f haste))) +(transient-define-prefix bd/layout-dispatcher () + ["Dispatcher > Layout\n" + ["Infixes" + ("s" "haste" "haste")]] + [["Commands" + ("-" "text decrease" + (lambda () (interactive) (bd/layout--do-with-haste #'text-scale-decrease)) + :transient t) + ("=" "text increase" + (lambda () (interactive) (bd/layout--do-with-haste #'text-scale-increase)) + :transient t) + ("b" "narrow" + (lambda () (interactive) (bd/layout--do-with-haste #'shrink-window-horizontally)) + :transient t) + ("f" "widen" + (lambda () (interactive) (bd/layout--do-with-haste #'enlarge-window-horizontally)) + :transient t) + ("p" "shrink" + (lambda () (interactive) (bd/layout--do-with-haste #'shrink-window)) + :transient t) + ("n" "enlarge" + (lambda () (interactive) (bd/layout--do-with-haste #'enlarge-window)) + :transient t) + ("|" "balance" balance-windows)] + ["" + ("N" "shift down" windmove-swap-states-down :transient t) + ("P" "shift up" windmove-swap-states-up :transient t) + ("F" "shift right" windmove-swap-states-right :transient t) + ("B" "shift left" windmove-swap-states-left :transient t)] + ["" + ("a" "alpha" bd/set-frame-alpha) + ("w" "wallpaper" bd/set-bg) + ("t" "theme" load-theme)] + ["" + ("z" "widen gaps" exwm-outer-gaps-increment :transient t) + ("x" "shrink gaps" exwm-outer-gaps-decrement :transient t)]]) +(keymap-global-set "C-c w" #'bd/layout-dispatcher) + + +(provide 'bd--window) +;;; bd--window.el ends here diff --git a/kolwynia/home/bdunahu/files/.config/eww/eww.scss b/kolwynia/home/bdunahu/files/.config/eww/eww.scss new file mode 100644 index 0000000..198a00b --- /dev/null +++ b/kolwynia/home/bdunahu/files/.config/eww/eww.scss @@ -0,0 +1,118 @@ +* +{ + all: unset; +} + +/* separator */ + +.sepbar +{ + color: #D9E0EE; + font-family: Iosevka; + font-size: 12px; + margin-right: 5px; + margin-left: 5px; +} + +/* bar */ +.bar +{ + background-color: rgba(#000B0E, 0.72); +} + +/* time*/ +.time-cpu-mem +{ + margin-right: 15px; +} +.time-label +{ + color: #91d7e3; + font-family: Iosevka; + font-size: 12px; +} + +/* mem cpu */ +.vol +{ + color: #6434ff; + background-color: rgba(#232323, 1.0); + border-radius: 0px; + margin-right: 6px; +} +.mem +{ + color: #ed8dff; + background-color: rgba(#232323, 1.0); + border-radius: 0px; + margin-right: 6px; +} +.cpu +{ + color: #606060; + background-color: rgba(#232323, 1.0); + border-radius: 0px; + margin-right: 6px; +} +.cpu-and-mem +{ + border-radius: 0px; + margin-right: 0px; +} + +/* workspaces */ +.active +{ + color: #ed8dff; +} + +.workspaces +{ + padding-top: 5px; + font-size: 12px; +} + +.mail +{ + color: #ed8dff; + font-family: Iosevka; + font-size: 12px; +} + +.t1 +{ + color: #c6a0f6; + font-family: Iosevka; + font-size: 12px; +} + +.weather +{ + color: #ff5300; + font-family: Iosevka; + font-size: 12px; +} + +.battery +{ + color: #d42ea2; + font-family: Iosevka; + font-size: 12px; +} + +.classes +{ + margin-left: 10px; +} + +.class +{ + margin-right: 10px; + color: #D9E0EE; + padding: 4px; + margin-top: 0px; + border-radius: 0px; + background: rgba(#042429, 0.48); + font-family: Iosevka; + font-size: 12px; +} diff --git a/kolwynia/home/bdunahu/files/.config/eww/eww.yuck b/kolwynia/home/bdunahu/files/.config/eww/eww.yuck new file mode 100644 index 0000000..335a687 --- /dev/null +++ b/kolwynia/home/bdunahu/files/.config/eww/eww.yuck @@ -0,0 +1,18 @@ +(include "pollers.yuck") +(include "widgets.yuck") + +(defwindow bar + :monitor 0 + :windowtype "dock" + :geometry (geometry :x "0%" + :y "0%" + :width "100%" + :height "20px" + :anchor "top center") + :reserve (struts :side "top" :distance "2.3%") + (bar)) + +;; Local Variables: +;; mode: scheme +;; compile-command: "eww daemon --restart; eww open bar" +;; End: diff --git a/kolwynia/home/bdunahu/files/.config/eww/pollers.yuck b/kolwynia/home/bdunahu/files/.config/eww/pollers.yuck new file mode 100644 index 0000000..c3cdecf --- /dev/null +++ b/kolwynia/home/bdunahu/files/.config/eww/pollers.yuck @@ -0,0 +1,14 @@ +(defpoll volume :interval "2s" "scripts/getvol") +(defpoll time :interval "30s" "date '+%H:%M'") +(defpoll date :interval "30s" "date '+%b %d'") +(defpoll ws :interval "0.15s" "scripts/update_workspaces") +(defpoll cs :interval "0.15s" "scripts/update_x_names") +(defpoll mail :interval "60s" "$HOME/.local/bin/mail-string") +(defpoll t1 :interval "60s" "$HOME/.local/bin/t1-string") +(defpoll weather :interval "1800s" "$HOME/.local/bin/string-weather") +(defpoll batperc :interval "60s" "echo \"$(cat /sys/class/power_supply/BAT0/capacity)%\"") + +;; Local Variables: +;; mode: scheme +;; compile-command: "eww daemon --restart; eww open bar" +;; End: diff --git a/kolwynia/home/bdunahu/files/.config/eww/scripts/getvol b/kolwynia/home/bdunahu/files/.config/eww/scripts/getvol new file mode 100755 index 0000000..9fbe60f --- /dev/null +++ b/kolwynia/home/bdunahu/files/.config/eww/scripts/getvol @@ -0,0 +1,9 @@ +#!/bin/sh + +RUNNING_SINK=$(pactl list sinks | awk ' + /^Sink #/ {sink=$2} + /State: RUNNING/ {print sink} +' | head -n1) + +pactl list sinks | grep -A 20 "^Sink $RUNNING_SINK" | grep '^[[:space:]]Volume:' | \ + head -n $(( $SINK + 1 )) | tail -n 1 | sed -e 's,.* \([0-9][0-9]*\)%.*,\1,' diff --git a/kolwynia/home/bdunahu/files/.config/eww/scripts/update_workspaces b/kolwynia/home/bdunahu/files/.config/eww/scripts/update_workspaces new file mode 100755 index 0000000..4fb1b1c --- /dev/null +++ b/kolwynia/home/bdunahu/files/.config/eww/scripts/update_workspaces @@ -0,0 +1,34 @@ +#!/bin/sh + +gib_workspace_names() { + wmctrl -d \ + | awk '{ print $1 " " $2 " " $9 }' \ + | grep -v NSP +} + +gib_workspace_yuck() { + buffered="" + gib_workspace_names | while read -r id active name; do + name="${name#*_}" + if [ "$active" == '*' ]; then + active_class="active" + else + active_class="inactive" + fi + + if wmctrl -l | grep --regexp '.*\s\+'"$id"'\s\+.*' >/dev/null; then + button_class="occupied" + button_name="●" + else + button_class="empty" + button_name="○" + fi + buffered+="(button :class \"$button_class $active_class\" :onclick \"wmctrl -s $id\" \"$button_name\")" + echo -n "$buffered" + buffered="" + done +} + +box_attrs=':orientation "h" :class "workspaces" :space-evenly false :halign "center" :valign "center" :vexpand false :spacing 8 ' + +echo "(box $box_attrs $(gib_workspace_yuck))" diff --git a/kolwynia/home/bdunahu/files/.config/eww/scripts/update_x_names b/kolwynia/home/bdunahu/files/.config/eww/scripts/update_x_names new file mode 100755 index 0000000..63117ef --- /dev/null +++ b/kolwynia/home/bdunahu/files/.config/eww/scripts/update_x_names @@ -0,0 +1,33 @@ +#!/run/current-system/profile/bin/guile \ +-s +!# + +(use-modules (ice-9 popen) + (ice-9 textual-ports) + (ice-9 rdelim)) + +(define cmd "wmctrl -l | awk -v ws=\"$(wmctrl -d | awk '$2 == \"*\" {print $1}')\" '$2 == ws {print}' | cut -d ' ' -f 5-") + +(define box-attrs '(:class "classes" + :orientation "h" + :valign "center" + :halign "start" + :space-evenly "false")) + +(define titles + (let* ((process (open-pipe* OPEN_READ "sh" "-c" cmd)) + (output (get-string-all process))) + (close-pipe process) + output)) + +(define labels + (map (lambda (t) `(eventbox + :onclick ,(string-concatenate `("wmctrl -a \"" ,t "\"")) + (label :class "class" + :text ,t + :truncate true + :valign "center"))) + (filter (lambda (s) (not (string=? s ""))) + (string-split titles #\newline)))) + +(write `(box ,@box-attrs ,@labels)) diff --git a/kolwynia/home/bdunahu/files/.config/eww/widgets.yuck b/kolwynia/home/bdunahu/files/.config/eww/widgets.yuck new file mode 100644 index 0000000..c7ea4d4 --- /dev/null +++ b/kolwynia/home/bdunahu/files/.config/eww/widgets.yuck @@ -0,0 +1,92 @@ +(defwidget bar [] + (box :class "bar" + :orientation "h" + (classeswidget) + (workspaces) + (power-time-cpu-mem))) + +(defwidget power-time-cpu-mem [] + (box :class "time-cpu-mem" + :halign "end" + :valign "center" + :space-evenly "false" + :orientation "h" + (cpu-and-mem) + (sep) + (weatherwidget) + (sep) + (mailwidget) + (sep) + (t1widget) + (sep) + (batterywidget) + (sep) + (label :text "${date}, " + :class "time-label" + :halign "end" + :valign "center" + :tooltip "time") + (label :text time + :class "time-label" + :halign "end" + :valign "center" + :tooltip "time"))) + +(defwidget cpu-and-mem [] + (box :class "cpu-and-mem" + :orientation "h" + :halign "end" + :valign "center" + :space-evenly "false" + (circular-progress :class "vol" + :value volume + :thickness 6) + (circular-progress :class "cpu" + :value {EWW_CPU.avg} + :thickness 6) + (circular-progress :class "mem" + :value {EWW_RAM.used_mem_perc} + :thickness 6))) + +(defwidget batterywidget [] + (label + :class "battery" + :text batperc)) + +(defwidget t1widget [] + (label + :class "t1" + :text "${t1}")) + +(defwidget mailwidget [] + (label + :class "mail" + :text "${mail}")) + +(defwidget weatherwidget [] + (label + :class "weather" + :text "${weather}")) + +(defwidget classeswidget [] + (literal :content cs)) + +(defwidget iconwidget [] + (image + :path "assets/raven.png" + :class "icon" + :image-height 20 + :preserve-aspect-ratio true)) + +(defwidget workspaces [] + (literal :content ws)) + +(defwidget sep [] + (box :orientation "h" + :valign "center" + (label :class "sepbar" :text "|"))) + +;; Local Variables: +;; mode: scheme +;; compile-command: "eww daemon --restart; eww open bar" +;; End: diff --git a/kolwynia/home/bdunahu/files/.config/guix/channels.scm b/kolwynia/home/bdunahu/files/.config/guix/channels.scm new file mode 100644 index 0000000..f0ed659 --- /dev/null +++ b/kolwynia/home/bdunahu/files/.config/guix/channels.scm @@ -0,0 +1,9 @@ +(append (list (channel + (name 'tanelorn) + (url "https://git.operationnull.com/tanelorn.git") + (introduction + (make-channel-introduction + "feb72dbc897bcf2db3901ea5b25caba4add860f7" + (openpgp-fingerprint + "5550 5CA6 9DE5 D342 7F31 F9AE 5F86 6C65 2A34 C996"))))) + %default-channels) diff --git a/kolwynia/home/bdunahu/files/.config/zathura/zathurarc b/kolwynia/home/bdunahu/files/.config/zathura/zathurarc new file mode 100644 index 0000000..ecdae54 --- /dev/null +++ b/kolwynia/home/bdunahu/files/.config/zathura/zathurarc @@ -0,0 +1,195 @@ +# start in dark mode +set recolor true +# mouse select copies to clipboard +nset selection-clipboard clipboard +set scroll-full-overlap 0.2 +# stops at page break +set scroll-page-aware true +set window-title-basename true +# start at width fit +set adjust-open width +# short version of the file path +set statusbar-home-tilde true +# center screen vertical midpoint +set vertical-center true +# synctex support +set synctex true +set zoom-step 3 + +# lots taken from +# https://web.archive.org/web/20220815064614/https://gist.github.com/ne9z/8778d614b90b85dfe8f6b698ad758f36 +map [normal] <C-b> scroll left +map [normal] <C-n> scroll down +map [normal] <C-p> scroll up +map [normal] <C-f> scroll right +map [normal] <C-g> abort +map [insert] <C-g> abort +map [normal] <C-[> abort +map [normal] <A-\<> goto top +map [normal] <A-\>> goto bottom +map [normal] a adjust_window best-fit +map [normal] s adjust_window width +map [normal] F display_link +map [normal] <C-c> copy_link +map [normal] f follow +map [normal] m mark_add +map [normal] \' mark_evaluate +map [normal] \, navigate next +map [normal] \. navigate previous +map [normal] <A-Right> navigate next +map [normal] <A-Left> navigate previous +map [normal] <PageDown> scroll full-down +map [normal] <PageUp> scroll full-up +map [normal] <C-P> print +map [normal] c recolor +map [normal] R reload +map [normal] v rotate rotate_cw +map [normal] V rotate rotate_ccw +map [normal] <Left> scroll left +map [normal] <Up> scroll up +map [normal] <Down> scroll down +map [normal] <Right> scroll right +map [normal] <A-a> scroll half-left +map [normal] <C-V> scroll half-down +map [normal] <A-V> scroll half-up +map [normal] <A-e> scroll half-right +map [normal] <C-a> scroll full-left +map [normal] <C-v> scroll full-down +map [normal] <Return> scroll full-down +map [normal] <A-v> scroll full-up +map [normal] <C-e> scroll full-right +map [normal] <Space> scroll full-down +map [normal] <C-h> scroll full-up +map [normal] <BackSpace> scroll full-up +map [normal] <S-Space> scroll full-up +map [normal] l jumplist backward +map [normal] r jumplist forward +map [normal] <A-r> bisect forward +map [normal] <A-l> bisect backward +# still need to use '/' to trigger search +map [normal] <C-s> search forward +map [normal] <C-r> search backward +map [normal] p snap_to_page +map [normal] <C-i> toggle_index +map [normal] i toggle_index +map [normal] <Tab> toggle_index +map [normal] <A-s> toggle_statusbar +map [normal] <A-i> focus_inputbar +map [normal] d toggle_page_mode +map [normal] q quit +map [normal] + zoom in +map [normal] - zoom out +map [normal] = zoom in +map [normal] <A-P> toggle_presentation +map [normal] <A-F> toggle_fullscreen +map [normal] j toggle_fullscreen +map [fullscreen] j toggle_fullscreen +map [fullscreen] q toggle_fullscreen +map [fullscreen] <C-b> scroll left +map [fullscreen] <C-n> scroll down +map [fullscreen] <C-p> scroll up +map [fullscreen] <C-f> scroll right +map [fullscreen] <C-g> abort +map [fullscreen] <C-[> abort +map [fullscreen] <A-\<> goto top +map [fullscreen] <A-\>> goto bottom +map [fullscreen] a adjust_window best-fit +map [fullscreen] s adjust_window width +map [fullscreen] F display_link +map [fullscreen] <C-c> copy_link +map [fullscreen] f follow +map [fullscreen] m mark_add +map [fullscreen] \' mark_evaluate +map [fullscreen] \, navigate next +map [fullscreen] \. navigate previous +map [fullscreen] <A-Right> navigate next +map [fullscreen] <A-Left> navigate previous +map [fullscreen] <PageDown> scroll full-down +map [fullscreen] <PageUp> scroll full-up +map [fullscreen] <C-P> print +map [fullscreen] c recolor +map [fullscreen] R reload +map [fullscreen] v rotate rotate_cw +map [fullscreen] V rotate rotate_ccw +map [fullscreen] <Left> scroll left +map [fullscreen] <Up> scroll up +map [fullscreen] <Down> scroll down +map [fullscreen] <Right> scroll right +map [fullscreen] <A-a> scroll half-left +map [fullscreen] <C-V> scroll half-down +map [fullscreen] <A-V> scroll half-up +map [fullscreen] <A-e> scroll half-right +map [fullscreen] <C-a> scroll full-left +map [fullscreen] <C-v> scroll full-down +map [fullscreen] <Return> scroll full-down +map [fullscreen] <A-v> scroll full-up +map [fullscreen] <C-e> scroll full-right +map [fullscreen] <Space> scroll full-down +map [fullscreen] <C-h> scroll full-up +map [fullscreen] <BackSpace> scroll full-up +map [fullscreen] <S-Space> scroll full-up +map [fullscreen] l jumplist backward +map [fullscreen] r jumplist forward +map [fullscreen] <A-r> bisect forward +map [fullscreen] <A-l> bisect backward +map [fullscreen] <C-s> search forward +map [fullscreen] <C-r> search backward +map [fullscreen] z snap_to_page +map [fullscreen] i toggle_index +map [fullscreen] <C-i> toggle_index +map [fullscreen] <Tab> toggle_index +map [fullscreen] <A-s> toggle_statusbar +map [fullscreen] <A-i> focus_inputbar +map [fullscreen] d toggle_page_mode +map [fullscreen] + zoom in +map [fullscreen] - zoom out +map [fullscreen] = zoom in +# status bar will obscure last item in index mode +map [index] <A-s> toggle_statusbar +map [index] q toggle_index +map [index] i toggle_index +map [index] <C-p> navigate_index up +map [index] <C-h> navigate_index up +map [index] <BackSpace> navigate_index up +map [index] <C-n> navigate_index down +map [index] <A-v> navigate_index up +map [index] <C-v> navigate_index down +map [index] \< navigate_index top +map [index] \> navigate_index bottom +map [index] <A-\<> navigate_index top +map [index] <A-\>> navigate_index bottom +map [index] <C-b> navigate_index collapse +map [index] <C-f> navigate_index expand +map [index] <C-i> navigate_index expand-all +map [index] <A-i> navigate_index collapse-all +map [index] <Up> navigate_index up +map [index] <Down> navigate_index down +map [index] <Left> navigate_index collapse +map [index] <Right> navigate_index expand +map [index] <C-m> navigate_index select +map [index] <Space> navigate_index select +map [index] <Return> navigate_index select +map [index] <C-j> navigate_index select +map [index] <Esc> toggle_index +map [index] <C-[> toggle_index +map [index] <C-g> toggle_index +map [index] <C-c> toggle_index +map [presentation] i toggle_index +map [presentation] r navigate next +map [presentation] <Down> navigate next +map [presentation] <Right> navigate next +map [presentation] <PageDown> navigate next +map [presentation] <Space> navigate next +map [presentation] l navigate previous +map [presentation] <Left> navigate previous +map [presentation] <Up> navigate previous +map [presentation] <PageUp> navigate previous +map [presentation] <S-Space> navigate previous +map [presentation] <BackSpace> navigate previous +map [presentation] <F5> toggle_presentation +map [presentation] q toggle_presentation +map [presentation] <C-h> navigate previous +map [presentation] <M-v> navigate previous +map [presentation] <C-v> navigate next +map [presentation] <A-\<> goto top +map [presentation] <A-\>> goto bottom
\ No newline at end of file diff --git a/kolwynia/home/bdunahu/files/.local/bin/bkup-home b/kolwynia/home/bdunahu/files/.local/bin/bkup-home new file mode 100755 index 0000000..b2d31b6 --- /dev/null +++ b/kolwynia/home/bdunahu/files/.local/bin/bkup-home @@ -0,0 +1,6 @@ +#!/bin/sh + +cryptsetup open /dev/sdb1 bkup +mount /dev/mapper/bkup /mnt + +rsync -aPHAXSu --inplace --delete /home/ /mnt/ diff --git a/kolwynia/home/bdunahu/files/.local/bin/fetch-album b/kolwynia/home/bdunahu/files/.local/bin/fetch-album new file mode 100755 index 0000000..3885f88 --- /dev/null +++ b/kolwynia/home/bdunahu/files/.local/bin/fetch-album @@ -0,0 +1,38 @@ +#!/bin/sh + +err() { echo "Usage: + rename [OPTIONS] +Options: + -d: delimiter + -a: artist/author + -A: album/book title + -y: year of publication +You will be prompted for these fields if not given." && exit 1 ;} + +[ "$PWD" = "${HOME}/ik/tmp" ] || { echo "Unsafe directory!" && exit 1 ;} + +while getopts "d:a:A:y:" o; do case "${o}" in + d) delimiter="${OPTARG}" ;; + a) artist="${OPTARG}" ;; + A) album="${OPTARG}" ;; + y) year="${OPTARG}" ;; + *) printf "Invalid option: -%s\\n" "$OPTARG" && err ;; + esac done +files=(*) +echo "Reference: ${files[0]}" +[ -z "$delimiter" ] && echo "What are the delimiters for these files?" && read -r delimiter +echo "Which index contains the track title? (Starting from 1)" && read -r index + +[ -z "$artist" ] && echo 'Enter an artist.' && read -r artist +[ -z "$album" ] && echo 'Enter an album.' && read -r album +[ -z "$year" ] && echo 'Enter a year.' && read -r year + +for file in *; +do + extension=$(echo $file | awk -F "." '{print $NF}') + title=$(echo $file | awk -F "${delimiter}" "{print \$${index}}" | + sed -re 's/^[[:blank:]]+|[[:blank:]]+$//g' -e 's/[[:blank:]]+/ /g') + new_file="${title}_${artist}_${album}_${year}.${extension}" + mv "./$file" "./$new_file" + tag-media -a "${artist}" -t "${title}" -A "${album}" -d "${year}" "${new_file}" +done diff --git a/kolwynia/home/bdunahu/files/.local/bin/guix-gc b/kolwynia/home/bdunahu/files/.local/bin/guix-gc new file mode 100755 index 0000000..23a423b --- /dev/null +++ b/kolwynia/home/bdunahu/files/.local/bin/guix-gc @@ -0,0 +1,7 @@ +#!/bin/sh + +sudo guix system delete-generations 2w +guix home delete-generations 2w +guix package --delete-generations=2w +guix pull --delete-generations=2w +guix gc diff --git a/kolwynia/home/bdunahu/files/.local/bin/mail-string b/kolwynia/home/bdunahu/files/.local/bin/mail-string new file mode 100755 index 0000000..e4f1d20 --- /dev/null +++ b/kolwynia/home/bdunahu/files/.local/bin/mail-string @@ -0,0 +1,4 @@ +#!/bin/sh + +mail="$(find /home/bdunahu/.ml/*/[Ii][Nn][Bb][Oo][Xx]/new/* -type f 2>/dev/null | wc -l)" +echo -n "${mail}M" diff --git a/kolwynia/home/bdunahu/files/.local/bin/sort-music b/kolwynia/home/bdunahu/files/.local/bin/sort-music new file mode 100755 index 0000000..013f194 --- /dev/null +++ b/kolwynia/home/bdunahu/files/.local/bin/sort-music @@ -0,0 +1,101 @@ +#!/usr/bin/env -S guix shell python -- python3 + +''' Imports ''' +import argparse +import logging +import sys +import glob +import os + +''' Global variables ''' +logger = logging.getLogger('sort_music.py') + +'''-----------------------------------------''' + +def parse_arguments(): + ''' Parse command line arguments ''' + parser = argparse.ArgumentParser() + parser.add_argument('-a', '--album', help='EXACT album name shared across designated files.', + required=True) + parser.add_argument('-f', '--format', help='ncmpcpp format of files. Default is %t_%a_%b_%y. Read the documentation for that program for more information. It MUST include an artist name (%a) and year (%y).', + default="%t_%a_%b_%y") + parser.add_argument('-v', '--verbose', help='Enable full debug output.', + action='store_true') + return parser.parse_args() + + + +def configure_logs(verbose): + ''' Configure program logging level ''' + level = logging.DEBUG if verbose else logging.INFO + + ''' Configure stream handler ''' + stream_handler = logging.StreamHandler(sys.stdout) + stream_handler.setFormatter(logging.Formatter('%(name)s - %(levelname)s - %(message)s')) + + ''' For main logger ''' + logger.addHandler(stream_handler) + logger.setLevel(level) + +'''-----------------------------------------''' + +class SortMusic(): + def __init__(self, logger, args): + self.logger = logger + self.album = args.album + self.delimiter = args.format[2] + self.artist_index = args.format.split(self.delimiter).index('%a') + self.year_index = args.format.split(self.delimiter).index('%y') + + logger.info(f'Starting rename with file extension {self.album} and artist_index {self.artist_index}') + + self.files = None # list of relevant files in specified directory + self.artist = None + self.year = None + + + def run(self): + self._find_files() + self._prompt() + self._organize() + + + def _find_files(self): + self.files = list(glob.glob(f"*{self.album}*")) + if len(self.files) == 0: + self.logger.error(f'Files in this album NOT found!') + exit(1) + + self.artist = self.files[0].split(self.delimiter).pop(self.artist_index).rsplit(".",1)[0] # remove file extension (sometimes occurs) + self.year = self.files[0].split(self.delimiter).pop(self.year_index).rsplit(".",1)[0] + + def _prompt(self): + self.logger.info(f'Found {len(self.files)} files written by {self.artist} in {self.year}.') + quit = input(f'Files will now be organized (y/n)\t').lower() + + if not quit.startswith('y'): + exit(1) + + def _organize(self): + path = f'./{self.artist}/({self.year}) {self.album}' + if not os.path.exists(path): + logger.info(f'Creating previously missing path {path}') + os.makedirs(path) + for file in self.files: + os.rename(f'./{file}', f'{path}/{file}') + +'''-----------------------------------------''' + +def main(): + ''' This is the main function ''' + args = parse_arguments() + configure_logs(args.verbose) + + ''' Initialize and run ''' + sorter = SortMusic(logger, args) + sorter.run() + + + +if __name__ == '__main__': + main() diff --git a/kolwynia/home/bdunahu/files/.local/bin/string-weather b/kolwynia/home/bdunahu/files/.local/bin/string-weather new file mode 100755 index 0000000..01ece24 --- /dev/null +++ b/kolwynia/home/bdunahu/files/.local/bin/string-weather @@ -0,0 +1,3 @@ +#!/bin/sh + +curl wttr.in/Amherst?format="%x+%t+%m\n" diff --git a/kolwynia/home/bdunahu/files/.local/bin/t1-string b/kolwynia/home/bdunahu/files/.local/bin/t1-string new file mode 100755 index 0000000..ffdd61a --- /dev/null +++ b/kolwynia/home/bdunahu/files/.local/bin/t1-string @@ -0,0 +1,17 @@ +#!/bin/sh + +loop=$(cat /tmp/t1 | jq .stat | tr -d '"') +[ -n "$loop" ] && echo -n "${loop} " +bg=$(cat /tmp/t1 | jq .bg) +[ -n "$bg" ] && echo -n "${bg}B " +iob=$(cat /tmp/t1 | jq .iob) +[ -n "$iob" ] && echo -n " ${iob}U" +rbat=$(cat /tmp/t1 | jq .rbat) +[ -n "$rbat" ] && [ "$rbat" -lt 25 ] && echo -n " RB" +res=$(echo "$(cat /tmp/t1 | jq .res) * 100 / 1" | bc) +[ -n "$res" ] && [ "$res" -lt 2500 ] && echo -n " PR" +pbat=$(echo "$(cat /tmp/t1 | jq .pbat) * 100 / 1" | bc) +[ -n "$pbat" ] && [ "$pbat" -lt 136 ] && echo -n " PB" +cage=$(cat /tmp/t1 | jq .cage) +[ -n "$cage" ] && [ 14 -lt "$cage" ] && echo -n " CA" +echo -n diff --git a/kolwynia/home/bdunahu/files/.local/bin/tag-media b/kolwynia/home/bdunahu/files/.local/bin/tag-media new file mode 100755 index 0000000..64b4586 --- /dev/null +++ b/kolwynia/home/bdunahu/files/.local/bin/tag-media @@ -0,0 +1,44 @@ +#!/bin/sh + +err() { echo "Usage: + tag [OPTIONS] file +Options: + -a: artist/author + -t: song/chapter title + -A: album/book title + -d: year of publication + -g: genre + -c: comment +You will be prompted for title, artist, album and date if not given." && exit 1 ;} + +while getopts "a:t:A:d:g:c:" o; do case "${o}" in + a) artist="${OPTARG}" ;; + t) title="${OPTARG}" ;; + A) album="${OPTARG}" ;; + d) date="${OPTARG}" ;; + g) genre="${OPTARG}" ;; + c) comment="${OPTARG}" ;; + *) printf "Invalid option: -%s\\n" "$OPTARG" && err ;; + esac done + +shift $((OPTIND - 1)) + +file="$1" + +temp="$(mktemp -p "$(dirname "$file")")" +trap 'rm -f $temp' HUP INT QUIT TERM PWR EXIT + +[ ! -f "$file" ] && echo 'Provide file to tag.' && err + +[ -z "$title" ] && echo 'Enter a title.' && read -r title +[ -z "$artist" ] && echo 'Enter an artist.' && read -r artist +[ -z "$album" ] && echo 'Enter an album.' && read -r album +[ -z "$date" ] && echo 'Enter a date.' && read -r date + +cp -f "$file" "$temp" && ffmpeg -i "$temp" -map 0 -y -codec copy \ + -metadata title="$title" \ + -metadata album="$album" \ + -metadata artist="$artist" \ + -metadata date="$date" \ + ${genre:+-metadata genre="$genre"} \ + ${comment:+-metadata comment="$comment"} "$file" diff --git a/kolwynia/home/bdunahu/files/.local/bin/touchpad-defaults b/kolwynia/home/bdunahu/files/.local/bin/touchpad-defaults new file mode 100755 index 0000000..6c07797 --- /dev/null +++ b/kolwynia/home/bdunahu/files/.local/bin/touchpad-defaults @@ -0,0 +1,6 @@ +#!/bin/sh + +# see: +# xinput --list +# xinput --list-props 'ELAN0412:00 04F3:311D Touchpad' +[[ $HOSTNAME == "garmr" ]] && xinput --set-prop "ELAN0412:00 04F3:311D Touchpad" "libinput Tapping Enabled" 1 diff --git a/kolwynia/home/bdunahu/files/.local/bin/unfreeze b/kolwynia/home/bdunahu/files/.local/bin/unfreeze new file mode 100755 index 0000000..072473d --- /dev/null +++ b/kolwynia/home/bdunahu/files/.local/bin/unfreeze @@ -0,0 +1,8 @@ +#!/bin/sh + +epid=$(pidof emacs) + +kill -USR2 "$epid" +kill -USR1 "$epid" + +echo "Done." diff --git a/kolwynia/home/bdunahu/files/.local/bin/upload b/kolwynia/home/bdunahu/files/.local/bin/upload new file mode 100755 index 0000000..a2db9b5 --- /dev/null +++ b/kolwynia/home/bdunahu/files/.local/bin/upload @@ -0,0 +1,43 @@ +#!/bin/sh + + +err() { echo "Usage: + upload [OPTIONS] +Options: + -t: time from now to expire in hours (default: 48) + file: a path to a file. If this is not given, receives input from stdin." && exit 1 ;} + +hours=48 + +while getopts ":t:" opt; do + case $opt in + t) + hours=$OPTARG + if [[ $OPTARG =~ ^-?[0-9]+$ ]]; then + hours=$OPTARG + else + err + fi + ;; + *) + err + ;; + esac +done + +shift $((OPTIND -1)) + +if [ -n "$1" ] && [ -f "$1" ]; then + source="$1" + ext="${1##*.}" +else + source=$(mktemp) + ext="txt" + cat > "$source" + chmod a+r "$source" +fi + +dest="$(cat /dev/random | tr -dc 'a-zA-Z0-9' | fold -w 4 | head -n 1)-$(date -d "+$hours hours" +%s).$ext" + +scp "$source" "root@operationnull.com:/var/www/operationnull/paste/$dest" && + echo "https://operationnull.com/paste/$dest" diff --git a/kolwynia/home/bdunahu/files/.local/bin/xkeyboard-auto b/kolwynia/home/bdunahu/files/.local/bin/xkeyboard-auto new file mode 100755 index 0000000..b81ced4 --- /dev/null +++ b/kolwynia/home/bdunahu/files/.local/bin/xkeyboard-auto @@ -0,0 +1,12 @@ +#!/bin/sh + +/home/bdunahu/.local/bin/xkeyboard-toggle +while true; +do + if [ -f /tmp/keyboard_plugged ]; then + rm /tmp/keyboard_plugged + sleep 2 + /home/bdunahu/.local/bin/xkeyboard-toggle + fi + sleep 1 +done diff --git a/kolwynia/home/bdunahu/files/.local/bin/xkeyboard-layout b/kolwynia/home/bdunahu/files/.local/bin/xkeyboard-layout new file mode 100755 index 0000000..de6f7a2 --- /dev/null +++ b/kolwynia/home/bdunahu/files/.local/bin/xkeyboard-layout @@ -0,0 +1,12 @@ +#!/bin/sh + +WORKMAN=$(setxkbmap -print | grep "workman") +echo $WORKMAN + +if [ -z WORKMAN ]; then + xkbcomp -I$HOME/.xkb ~/.xkb/keymap/standard $DISPLAY && + echo 'Switched to standard layout.' +else + test -f ~/.xkb/symbols/rocket && xkbcomp -I$HOME/.xkb ~/.xkb/keymap/rocket $DISPLAY && + echo 'Switched to workman layout.' +fi diff --git a/kolwynia/home/bdunahu/files/.local/bin/xkeyboard-toggle b/kolwynia/home/bdunahu/files/.local/bin/xkeyboard-toggle new file mode 100755 index 0000000..70f9516 --- /dev/null +++ b/kolwynia/home/bdunahu/files/.local/bin/xkeyboard-toggle @@ -0,0 +1,5 @@ +#!/bin/sh + +xset r rate 250 70 +xset s 600 +xkbcomp -I$HOME/.xkb ~/.xkb/keymap/standard $DISPLAY diff --git a/kolwynia/home/bdunahu/files/.local/bin/xrandr-refresh b/kolwynia/home/bdunahu/files/.local/bin/xrandr-refresh new file mode 100755 index 0000000..c9d55c5 --- /dev/null +++ b/kolwynia/home/bdunahu/files/.local/bin/xrandr-refresh @@ -0,0 +1,10 @@ +#!/bin/sh + +declare -i count=2 +declare -i seconds=1 + +while ((count)); do + xrandr >/dev/null + sleep $seconds + ((count--)) +done
\ No newline at end of file diff --git a/kolwynia/home/bdunahu/files/.local/bin/xrandr-toggle b/kolwynia/home/bdunahu/files/.local/bin/xrandr-toggle new file mode 100755 index 0000000..6acff6d --- /dev/null +++ b/kolwynia/home/bdunahu/files/.local/bin/xrandr-toggle @@ -0,0 +1,15 @@ +#!/bin/sh +intern=eDP-1 +extern=DP-1 +extern2=HDMI-1 + +if xrandr | grep "$extern disconnected" >/dev/null; then + xrandr --output "$extern" --off --output "$intern" --mode 1920x1080 --auto +# usually, HDMI-1 is a 2560x1440 screen, so cannot be duplicated well +elif xrandr | grep "$extern2 connected" >/dev/null; then + xrandr --output "$extern2" --primary --mode 1920x1080 --auto --same-as "$intern" +else + xrandr --output "$extern" --primary --mode 1920x1080 --auto --same-as "$intern" +fi + +echo "xrandr done!" diff --git a/kolwynia/home/bdunahu/files/.local/bin/xxinit b/kolwynia/home/bdunahu/files/.local/bin/xxinit new file mode 100755 index 0000000..1ec9a82 --- /dev/null +++ b/kolwynia/home/bdunahu/files/.local/bin/xxinit @@ -0,0 +1,6 @@ + #!/bin/sh + +DIR=/home/bdunahu/.guix-home/profile/ +$DIR/bin/xinit -- $DIR/bin/Xorg :0 vt1 -keeptty \ + -configdir $DIR/share/X11/xorg.conf.d \ + -modulepath $DIR/lib/xorg/modules diff --git a/kolwynia/home/bdunahu/files/.xinitrc b/kolwynia/home/bdunahu/files/.xinitrc new file mode 100644 index 0000000..0e51e5a --- /dev/null +++ b/kolwynia/home/bdunahu/files/.xinitrc @@ -0,0 +1,25 @@ +#!/bin/sh + +userresources=$HOME/.Xresources +usermodmap=$HOME/.Xmodmap + +# merge in defaults and keymaps + +if [ -f "$userresources" ]; then + xrdb -merge "$userresources" +fi + +if [ -f "$usermodmap" ]; then + xmodmap "$usermodmap" +fi + +picom --backend=glx & +xss-lock -- slock & +xset r rate 250 70 +xset s 600 +touchpad-defaults +xrandr-toggle +xkeyboard-auto & +eww daemon +eww open bar +exec emacs -mm diff --git a/kolwynia/home/bdunahu/files/.xkb/keymap/rocket b/kolwynia/home/bdunahu/files/.xkb/keymap/rocket new file mode 100644 index 0000000..4fdd8c1 --- /dev/null +++ b/kolwynia/home/bdunahu/files/.xkb/keymap/rocket @@ -0,0 +1,7 @@ +xkb_keymap { + xkb_keycodes { include "evdev+aliases(qwerty)" }; + xkb_types { include "complete" }; + xkb_compat { include "complete" }; + xkb_symbols { include "pc+us(workman)+inet(evdev)+rocket(rocket)" }; + xkb_geometry { include "pc(pc105)" }; +}; diff --git a/kolwynia/home/bdunahu/files/.xkb/keymap/standard b/kolwynia/home/bdunahu/files/.xkb/keymap/standard new file mode 100644 index 0000000..528dd72 --- /dev/null +++ b/kolwynia/home/bdunahu/files/.xkb/keymap/standard @@ -0,0 +1,7 @@ +xkb_keymap { + xkb_keycodes { include "evdev+aliases(qwerty)" }; + xkb_types { include "complete" }; + xkb_compat { include "complete" }; + xkb_symbols { include "pc+us+inet(evdev)+rocket(rocket)" }; + xkb_geometry { include "pc(pc105)" }; +}; diff --git a/kolwynia/home/bdunahu/files/.xkb/symbols/rocket b/kolwynia/home/bdunahu/files/.xkb/symbols/rocket new file mode 100644 index 0000000..a206a9a --- /dev/null +++ b/kolwynia/home/bdunahu/files/.xkb/symbols/rocket @@ -0,0 +1,9 @@ +partial modifier_keys +xkb_symbols "rocket" { + key <TAB> {[ BackSpace, Escape, BackSpace, BackSpace ]}; + key <CAPS> {[ space, space, space, nobreakspace ]}; + key <LCTL> {[ Tab, ISO_Left_Tab, Tab, ISO_Left_Tab ]}; + key <RTRN> {[ space, space, space, nobreakspace ]}; + key <RCTL> {[ Return, Return, Return, Return ]}; + key <SPCE> {[ Control_L, Control_R, Control_L, Control_R ]}; +}; diff --git a/kolwynia/home/bdunahu/packages.scm b/kolwynia/home/bdunahu/packages.scm new file mode 100644 index 0000000..7d0e510 --- /dev/null +++ b/kolwynia/home/bdunahu/packages.scm @@ -0,0 +1,221 @@ +;;; Copyright © 2025,2026 bdunahu <bdunahu@operationnull.com> +(define-module (kolwynia home bdunahu packages) + #:use-module (gnu) + #:use-module (gnu system) + #:use-module (guix packages) + #:use-module (tanelorn packages fonts) + #:use-module (tanelorn packages wm) + #:use-module (tanelorn packages engineering) + #:use-module (tanelorn packages emacs-xyz) + #:export (emacs + browser + pass + media + mail + tex + desktop + pdf + fonts + development + reverse-engineering + university + emulators + games)) + +;;; Commentary: +;;; Code: + +(use-package-modules + admin ;; netcat + algebra ;; bc + aspell ;; aspell, aspell-dict-en + assembly ;; nasm + base ;; make + chromium ;; ungoogled-chromium + clojure ;; clojure + commencement ;; gcc-toolchain + compton ;; picom + cpp ;; ccls + education ;; anki + emacs-build ;; emacs-dash + emacs ;; emacs-next + emacs-xyz ;; emacs-emms, etc. + emulators ;; mupen64plus*, bsnes, mgba + engineering ;; radare2, iaito + fonts ;; font-terminus, font-openmoji + fontutils ;; fontconfig + freedesktop ;; xdg-utils + games ;; nethack + gdb ;; gdb + gimp ;; gimp-next + gnome ;; brightnessctl + gnupg ;; gnupg, pinentry-emacs + graphviz ;; graphviz + haskell-xyz ;; pandoc + image ;; flameshot + imagemagick ;; imagemagick + image-viewers ;; feh, nsxiv + libreoffice ;; libreoffice + librewolf ;; librewolf + linux ;; tlp, alsa-plugins + lisp ;; sbcl + luanti ;; luanti + machine-learning ;; llama-cpp + mail ;; offlineimap + password-utils ;; pass-otp, password-store + pdf ;; xpdf, pdfgrep, zathura, zathura-pdf-mupdf + photo ;; perl-image-exiftool + pkg-config ;; pkg-config + pulseaudio ;; pavucontrol, pulseaudio, + python ;; python + python-xyz ;; python-lsp-server + rsync ;; rsync + texlive ;; texlive, texlive-biber + tex ;; texlive-dvipng + tor-browsers ;; torbrowser + video ;; ffmpeg, mpv, yt-dlp + virtualization ;; qemu + web ;; jq + xdisorg ;; xdotool, xrdb, wmctrl + xorg) ;; xf86-input-libinput, xf86-video-fbdev, xinit... + + + +(define emacs + (list emacs-next + pinentry-emacs + ;; + emacs-atomic-chrome + emacs-cider + emacs-clojure-mode + emacs-dash + emacs-denote + emacs-denote-journal + emacs-elpher + emacs-emms + emacs-exwm + emacs-f + emacs-gptel + emacs-guix + emacs-hydra + emacs-jeison + emacs-lua-mode + emacs-paredit + emacs-pinentry + emacs-rainbow-delimiters + emacs-rainbow-mode + emacs-s + emacs-slime + emacs-vterm + emacs-yasnippet + ;; + aspell ;for ispell + aspell-dict-en ; + wmctrl ;for exwm + perl-image-exiftool ;for emms + ccls ;for eglot + python-lsp-server ; + llama-cpp)) ;for emacs-gptel + +(define browser + (list torbrowser + ungoogled-chromium + librewolf)) + +(define pass + (list gnupg + pass-otp + password-store)) + +(define media + (list feh + ffmpeg + flameshot + gimp + imagemagick + mpv + nsxiv + pandoc + yt-dlp)) + +(define mail + (list offlineimap3)) + +(define tex + (list texlive + texlive-biber + texlive-dvipng + texlive-pgfgantt + texlive-libertinus)) + +(define desktop + (list alsa-plugins + eww/x11 + pavucontrol + picom + pulseaudio + setxkbmap + xdg-utils + xf86-input-libinput + xf86-video-fbdev + xinit + xinput + xkbcomp + xorg-server + xrandr + xrdb + xset + xss-lock)) + +(define pdf + (list pdfgrep + xpdf ;pdftotext + zathura + zathura-pdf-mupdf)) + +(define fonts + (list fontconfig + font-iosevka + font-medieval-sharp + font-openmoji + font-runa-mono + font-terminus + font-libertinus)) + +(define development + (list bc + cl-asdf + clojure + clojure-tools + gcc-toolchain + gdb + gnu-make + pkg-config + python + jq + netcat + sbcl)) + +(define reverse-engineering + (list nasm + iaito + radare2)) + +(define university + (list anki + graphviz + libreoffice + qemu)) + +(define emulators + (list bsnes + dolphin-emu + mgba + mupen64plus-ui-console + mupen64plus-video-glide64mk2)) + +(define games + (list crawl-tiles + luanti)) + +;;; packages.scm ends here diff --git a/kolwynia/home/bdunahu/ssh.scm b/kolwynia/home/bdunahu/ssh.scm new file mode 100644 index 0000000..5c137b2 --- /dev/null +++ b/kolwynia/home/bdunahu/ssh.scm @@ -0,0 +1,43 @@ +;;; Copyright © 2026 bdunahu <bdunahu@operationnull.com> +(define-module (kolwynia home bdunahu ssh) + #:use-module (gnu home services ssh) + #:export (garmr + heimdallr + nott + surt + codeberg)) + +;;; Commentary: +;;; Code: + +(define garmr + (openssh-host (name "garmr") + (host-name "localhost") + (user "root"))) + +(define heimdallr + (openssh-host (name "heimdallr") + (host-name "operationnull.com") + (user "root"))) + +(define nott + (openssh-host (name "nott") + (host-name "localhost") + (user "bdunahu") + (port 2222) + (extra-content " UserKnownHostsFile=/dev/null + StrictHostKeyChecking=no +"))) + +(define surt + (openssh-host (name "surt") + (host-name "192.168.1.250") + (user "root"))) + +(define codeberg + (openssh-host (name "codeberg.org") + (host-name "codeberg.org") + (user "git") + (identity-file "~/.ssh/codeberg"))) + +;;; ssh.scm ends here diff --git a/kolwynia/os/garmr.scm b/kolwynia/os/garmr.scm new file mode 100644 index 0000000..ad6cace --- /dev/null +++ b/kolwynia/os/garmr.scm @@ -0,0 +1,61 @@ +(define-module (kolwynia os garmr) + #:use-module (gnu) + #:use-module (gnu packages) + #:use-module (gnu packages linux) + #:use-module (gnu packages gnome) + #:use-module (gnu packages networking) + #:use-module (gnu services) + #:use-module (gnu services guix) + #:use-module (gnu services pm) + #:use-module (guix gexp) + #:use-module (kolwynia os ymir) + #:use-module ((kolwynia os garmr file-systems) + #:prefix fs:) + #:use-module ((kolwynia os ymir packages) + #:prefix pkg:) + #:use-module ((kolwynia os ymir users) + #:prefix users:) + #:use-module (kolwynia home bdunahu)) + +;;; Commentary: +;;; +;;; garmr is a corebooted and fully-libre laptop +;;; +;;; Code: + +(operating-system + (inherit ymir) + (host-name "garmr") + + (packages (cons* brightnessctl tlp pkg:ymir-packages)) + + (services + (cons* + ;; laptop power management + (service tlp-service-type + (tlp-configuration + (cpu-scaling-governor-on-ac (list "powersave")) + (cpu-scaling-governor-on-bat (list "powersave")) + (energy-perf-policy-on-ac "powersave") + (energy-perf-policy-on-bat "powersave") + (pcie-aspm-on-ac "powersave") + (pcie-aspm-on-bat "powersave") + (sched-powersave-on-bat? #t) + (sched-powersave-on-ac? #t) + (sata-linkpwr-on-ac "min_power") + (sata-linkpwr-on-bat "min_power") + (start-charge-thresh-bat0 60) + (stop-charge-thresh-bat0 80))) + (service thermald-service-type) + (simple-service 'network-manager-applet + profile-service-type + (list network-manager-applet)) + (service guix-home-service-type + `((,users:bdunahu-str ,bdunahu))) + + (operating-system-user-services ymir))) + + (mapped-devices fs:%mapped-devices) + (file-systems fs:%file-systems)) + +;;; garmr.scm ends here diff --git a/kolwynia/os/garmr/file-systems.scm b/kolwynia/os/garmr/file-systems.scm new file mode 100644 index 0000000..352d1f2 --- /dev/null +++ b/kolwynia/os/garmr/file-systems.scm @@ -0,0 +1,39 @@ +;;; Copyright © 2025 bdunahu <bdunahu@operationnull.com> +(define-module (kolwynia os garmr file-systems) + #:use-module (gnu system mapped-devices) + #:use-module (gnu system file-systems) + #:export (%mapped-devices %file-systems)) + +;;; Commentary: +;;; +;;; filesystems for garmr +;;; +;;; Code: + +(define %mapped-devices + (list (mapped-device + (source (uuid "671c8094-c8cd-47f9-8332-25513f16917b")) + (target "hidden") + (type luks-device-mapping)))) + +(define %file-systems + (cons* (file-system + (mount-point "/boot/efi") + (device (uuid + "1A7A-026F" + 'fat32)) + (type "vfat")) + (file-system + (mount-point "/home") + (device "/dev/mapper/hidden") + (type "ext4") + (dependencies %mapped-devices)) + (file-system + (mount-point "/") + (device (uuid + "0a0b9520-308f-4072-a62b-b91ffacdc5b0" + 'ext4)) + (type "ext4")) + %base-file-systems)) + +;;; file-systems.scm ends here diff --git a/kolwynia/os/hel.scm b/kolwynia/os/hel.scm new file mode 100644 index 0000000..e9b6289 --- /dev/null +++ b/kolwynia/os/hel.scm @@ -0,0 +1,45 @@ +(define-module (kolwynia os hel) + #:use-module (gnu) + #:use-module (gnu packages) + #:use-module (gnu packages linux) + #:use-module (gnu packages gnome) + #:use-module (gnu packages networking) + #:use-module (gnu packages xorg) + #:use-module (gnu services) + #:use-module (gnu services guix) + #:use-module (guix gexp) + #:use-module (kolwynia os ymir) + #:use-module ((kolwynia os hel file-systems) + #:prefix fs:) + #:use-module ((kolwynia os ymir packages) + #:prefix pkg:) + #:use-module ((kolwynia os ymir users) + #:prefix users:) + #:use-module (kolwynia home bdunahu)) + +;;; Commentary: +;;; +;;; hel is a intel i5 with RTX 1050ti +;;; +;;; Code: + +(operating-system + (inherit ymir) + (host-name "hel") + + (packages (cons* xf86-video-nouveau pkg:ymir-packages)) + + (services + (cons* + (simple-service 'network-manager-applet + profile-service-type + (list network-manager-applet)) + (service guix-home-service-type + `((,users:bdunahu-str ,bdunahu))) + + (operating-system-user-services ymir))) + + (mapped-devices fs:%mapped-devices) + (file-systems fs:%file-systems)) + +;;; hel.scm ends here diff --git a/kolwynia/os/hel/file-systems.scm b/kolwynia/os/hel/file-systems.scm new file mode 100644 index 0000000..b975c56 --- /dev/null +++ b/kolwynia/os/hel/file-systems.scm @@ -0,0 +1,39 @@ +;;; Copyright © 2026 bdunahu <bdunahu@operationnull.com> +(define-module (kolwynia os hel file-systems) + #:use-module (gnu system mapped-devices) + #:use-module (gnu system file-systems) + #:export (%mapped-devices %file-systems)) + +;;; Commentary: +;;; +;;; filesystems for hel +;;; +;;; Code: + +(define %mapped-devices + (list (mapped-device + (source (uuid "671c8094-c8cd-47f9-8332-25513f16917b")) + (target "hidden") + (type luks-device-mapping)))) + +(define %file-systems + (cons* (file-system + (mount-point "/boot/efi") + (device (uuid + "1A7A-026F" + 'fat32)) + (type "vfat")) + (file-system + (mount-point "/home") + (device "/dev/mapper/hidden") + (type "ext4") + (dependencies %mapped-devices)) + (file-system + (mount-point "/") + (device (uuid + "0a0b9520-308f-4072-a62b-b91ffacdc5b0" + 'ext4)) + (type "ext4")) + %base-file-systems)) + +;;; file-systems.scm ends here diff --git a/kolwynia/os/ymir.scm b/kolwynia/os/ymir.scm new file mode 100644 index 0000000..bba1b3b --- /dev/null +++ b/kolwynia/os/ymir.scm @@ -0,0 +1,117 @@ +;;; Copyright © 2025 bdunahu <bdunahu@operationnull.com> +(define-module (kolwynia os ymir) + #:use-module ((kolwynia os ymir users) + #:prefix users:) + #:use-module ((kolwynia os ymir packages) + #:prefix pkg:) + #:use-module (gnu) + #:use-module (gnu services desktop) + #:use-module (gnu system) + #:use-module (gnu packages suckless) + #:export (ymir)) + +;;; Commentary: +;;; +;;; ymir defines a default system configuration +;;; +;;; Code: + +(use-service-modules audio admin avahi base + dbus desktop file-sharing + networking sound ssh xorg) + +;;; generates a temporary file to notify a keyboard was plugged. +(define %keyboard-udev-rule + (udev-rule + "90-keyboard-hotplug.rules" + (string-append "ATTR{idVendor}==\"04b4\", ATTR{idProduct}==\"0510\", ACTION==\"add\", RUN+=\"/run/current-system/profile/bin/touch /tmp/keyboard_plugged\" RUN+=\"/run/current-system/profile/bin/chown " users:bdunahu-str " /tmp/keyboard_plugged\""))) + +(define ymir + (operating-system + (host-name "ymir") + (locale "en_US.utf8") + (timezone + (if #f + "America/New_York" + "America/Denver")) + (keyboard-layout + (keyboard-layout "us" + #:options '("ctrl:hyper_capscontrol"))) + (kernel-arguments + (delete "quiet" + %default-kernel-arguments)) + + (users (cons* users:bdunahu + %base-user-accounts)) + + (bootloader (bootloader-configuration + (bootloader grub-efi-bootloader) + (targets (list "/boot/efi")) + (timeout 1) + (keyboard-layout keyboard-layout))) + + (packages pkg:ymir-packages) + (services + `( + ;; so that non-root users in the wheel group can + ;; perform administrative tasks (similar to "sudo"). + ,polkit-wheel-service + ;; The global fontconfig cache directory can sometimes contain + ;; stale entries, possibly referencing fonts that have been GC'd, + ;; so mount it read-only. + ,fontconfig-file-system-service + + ,(service network-manager-service-type) + ,(service wpa-supplicant-service-type) ; needed by NetworkManager + ,(service modem-manager-service-type) + ,(service usb-modeswitch-service-type) + + ;; The D-Bus clique. + ,(service avahi-service-type) + ,(service udisks-service-type) + ,(service upower-service-type) + ,(service accountsservice-service-type) + ,(service cups-pk-helper-service-type) + ,(service colord-service-type) + ,(service geoclue-service-type) + ,(service polkit-service-type) + ,(service elogind-service-type + (elogind-configuration + (handle-power-key 'hibernate))) + ,(service dbus-root-service-type) + + ,(service ntp-service-type) + + ;; openssh + ,(service openssh-service-type + (openssh-configuration + (x11-forwarding? #t) + (permit-root-login 'prohibit-password) + (password-authentication? #f))) + + ;; xorg + ,(service screen-locker-service-type + (screen-locker-configuration + (name "slock") + (program (file-append slock "/bin/slock")))) + ,(service x11-socket-directory-service-type) + ,(udev-rules-service 'keyboard-hotplug %keyboard-udev-rule) + + ;; audio + ,(service pulseaudio-service-type) + ,(service alsa-service-type) + + ;; TODO: don't do this expensive operation; just copy file. + ;; ,(simple-service 'add-extra-hosts + ;; hosts-service-type + ;; (map + ;; (lambda (x) + ;; (host "0.0.0.0" x)) + ;; (read-hosts "/home/bdunahu/.config/guix/assets/blocklist.txt"))) + + ,@%base-services)) + + ;; OVERRIDE + (file-systems '()))) + +;;; ymir.scm ends here diff --git a/kolwynia/os/ymir/packages.scm b/kolwynia/os/ymir/packages.scm new file mode 100644 index 0000000..9331b10 --- /dev/null +++ b/kolwynia/os/ymir/packages.scm @@ -0,0 +1,106 @@ +;;; Copyright © 2025 bdunahu <bdunahu@operationnull.com> +(define-module (kolwynia os ymir packages) + #:use-module (gnu) + #:use-module (gnu system) + #:use-module (guix packages) + #:export (ymir-packages-utils + ymir-packages-linux + ymir-packages-interactive + ymir-packages-networking + ymir-packages)) + +;;; Commentary: +;;; Code: + +(use-package-modules + admin + bash + compression + cryptsetup + curl + databases + firmware + gawk + guile + guile-xyz + less + linux + man + networking + nss + pciutils + rust-apps + screen + texinfo + text-editors + version-control + vim + wget) + +(define ymir-packages-utils + (list bash + bzip2 + coreutils + curl + diffutils + e2fsprogs + findutils + gawk + grep + guile-3.0-latest + gzip + lzip + man-pages + patch + procps + psmisc + recutils + screen + sed + shadow + tar + unzip + which + xz + zip + zstd)) + +(define ymir-packages-linux + (list cryptsetup + eudev + kmod + pciutils + usbutils + util-linux+udev)) + +(define ymir-packages-interactive + (list git + guile-colorized + guile-readline + info-reader + kbd + less + man-db + mg + ripgrep + sudo + sysstat + vim)) + +(define ymir-packages-networking + (list inetutils + iproute + isc-dhcp + iw + macchanger + nss-certs + wget + wireless-tools)) + +(define ymir-packages + (append ymir-packages-interactive + ymir-packages-linux + ymir-packages-networking + ymir-packages-utils)) + +;;; packages.scm ends here diff --git a/kolwynia/os/ymir/users.scm b/kolwynia/os/ymir/users.scm new file mode 100644 index 0000000..a577998 --- /dev/null +++ b/kolwynia/os/ymir/users.scm @@ -0,0 +1,28 @@ +;;; Copyright © 2025 bdunahu <bdunahu@operationnull.com> +(define-module (kolwynia os ymir users) + #:use-module (gnu system accounts) + #:use-module (kolwynia utils) + #:export (bdunahu-str bdunahu)) + +;;; Commentary: +;;; +;;; provides the bdunahu user configuration +;;; +;;; Code: + +(define bdunahu-str "bdunahu") +(define bdunahu + (user-account + (name bdunahu-str) + (comment bdunahu-str) + (group "users") + (home-directory (string-append "/home/" bdunahu-str)) + (supplementary-groups + (cons* "audio" + "dialout" + "netdev" + "video" + "wheel" + (garmr?* "kvm"))))) + +;;; users.scm ends here diff --git a/kolwynia/utils.scm b/kolwynia/utils.scm new file mode 100644 index 0000000..990cef1 --- /dev/null +++ b/kolwynia/utils.scm @@ -0,0 +1,14 @@ +;;; Copyright © 2025 bdunahu <bdunahu@operationnull.com> +(define-module (kolwynia utils) + #:export (garmr?*)) + +;;; Commentary: +;;; provides various utility functions +;;; Code: + +(define (garmr?* . thing) + (if (equal? (gethostname) "garmr") + thing + '())) + +;;; utils.scm ends here |
