diff options
Diffstat (limited to '.config/emacs')
24 files changed, 1391 insertions, 210 deletions
diff --git a/.config/emacs/images/raven.png b/.config/emacs/images/raven.png Binary files differindex e2900c1..6f27c08 100644 --- a/.config/emacs/images/raven.png +++ b/.config/emacs/images/raven.png diff --git a/.config/emacs/images/wolf.png b/.config/emacs/images/wolf.png Binary files differnew file mode 100644 index 0000000..fabad74 --- /dev/null +++ b/.config/emacs/images/wolf.png diff --git a/.config/emacs/init.el b/.config/emacs/init.el index ad498c8..8deff07 100644 --- a/.config/emacs/init.el +++ b/.config/emacs/init.el @@ -46,6 +46,7 @@ use-short-answers t vc-follow-symlinks t completion-ignore-case t + save-place-mode t read-buffer-completion-ignore-case t) (setq-default tab-width 8) (add-to-list 'default-frame-alist '(alpha . (92 . 92))) @@ -73,15 +74,18 @@ gnus-read-newsrc-file nil) -;; packages installed via guix -(when (file-directory-p "~/.guix-profile") - (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")) +(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 @@ -100,7 +104,7 @@ (require 'bd--project) (require 'bd--files) (require 'bd--dictionary) -(require 'bd--irc) +(require 'bd--chat) (require 'bd--shells) (require 'bd--minibuffer) (require 'bd--buffer) @@ -110,10 +114,9 @@ (require 'bd--notes) (require 'bd--emms) (require 'bd--modeline) -(require 'bd--themes) - -(if (string= (system-name) "garm") +(if (not (string= (system-name) "surt")) (require 'bd--exwm)) +(require 'bd--themes) ;;; init.el ends here diff --git a/.config/emacs/libraries/exwm-outer-gaps.el b/.config/emacs/libraries/exwm-outer-gaps.el new file mode 100644 index 0000000..c315e8b --- /dev/null +++ b/.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/.config/emacs/libraries/powerthesaurus.el b/.config/emacs/libraries/powerthesaurus.el new file mode 100644 index 0000000..2c76df0 --- /dev/null +++ b/.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/.config/emacs/libraries/selector.el b/.config/emacs/libraries/selector.el index c541572..3b77190 100644 --- a/.config/emacs/libraries/selector.el +++ b/.config/emacs/libraries/selector.el @@ -58,10 +58,6 @@ (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 (str) - "Write STR to the minibuffer." - (goto-char (point-max)) - (insert (concat "\n" str))) (defun selector-minibuffer-line-face (str face) "Write STR to the minibuffer in FACE." @@ -70,7 +66,8 @@ ;; are active. the real fix probably should live in selector-nearby? (when (< selector--drawn-this-frame selector-minibuffer-lines) (let ((before (point))) - (selector-minibuffer-line str) + (goto-char (point-max)) + (insert (concat "\n" str)) (goto-char before) (forward-line) (put-text-property (line-beginning-position) (point-max) 'face face)))) diff --git a/.config/emacs/modules/bd--browse.el b/.config/emacs/modules/bd--browse.el index c5e409f..7d0b740 100644 --- a/.config/emacs/modules/bd--browse.el +++ b/.config/emacs/modules/bd--browse.el @@ -7,13 +7,13 @@ (require 'fill-column) (defun bd/browse (url &optional pref &rest _) - "Given PREF, launches URL in one of librewolf, torbrowser, -icecat, or eww." + "Given PREF, launches URL in an external browser or eww." (interactive) (pcase pref - (0 (eww url)) - (_ (start-process "librewolf" nil "librewolf" "--new-window" url)))) -(setopt browse-url-browser-function 'bd/browse) + ('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." @@ -64,14 +64,19 @@ icecat, or eww." (selector-source-create "Browser" :candidates - (list (bd/search-candidate "SearXNG" "https://searx.operationnull.com/searxng/search?q=" 0) - (bd/search-candidate "Wikipedia" "https://en.wikipedia.org/w/index.php?search=" 0) - (bd/search-candidate "Invidious" "https://inv.nadeko.net/search?q=" 0) - (bd/search-candidate "Urban Dictionary" "https://www.urbandictionary.com/define.php?term=" 0) - (bd/search-candidate "Archwiki" "https://wiki.archlinux.org/index.php?title=Special%3ASearch&search=" 0) + (list (bd/search-candidate "SearXNG" "https://searx.operationnull.com/searxng/search?q=" 'wolf) + (bd/search-candidate "DuckDuckGo" "https://duckduckgo.com/html/?q=" 'eww) + (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 "Web" "" 1)))) + (bd/search-candidate "Torbrowser" "" 'tor) + (bd/search-candidate "Librewolf" "" 'wolf)))) (defun bd/browse-dispatcher () "Select and `browse-url' a bookmark or search feature." @@ -99,10 +104,10 @@ icecat, or eww." ("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)))) + "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 @@ -114,12 +119,19 @@ icecat, or eww." :bind (:map eww-mode-map ("i" . eww-toggle-images) - ("o" . (lambda () (interactive) (rip-html (eww-current-url))))) + ("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-secondary-browser-function #'bd/browse + browse-url-browser-function 'bd/browse + browse-url-secondary-browser-function #'browse-url-default-browser eww-header-line-format nil eww-use-browse-url (regexp-opt '("mailto:" "youtube.com" diff --git a/.config/emacs/modules/bd--buffer.el b/.config/emacs/modules/bd--buffer.el index ea433b0..4a09805 100644 --- a/.config/emacs/modules/bd--buffer.el +++ b/.config/emacs/modules/bd--buffer.el @@ -23,6 +23,10 @@ (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/.config/emacs/modules/bd--chat.el b/.config/emacs/modules/bd--chat.el new file mode 100644 index 0000000..5fa0c2d --- /dev/null +++ b/.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/.config/emacs/modules/bd--devel.el b/.config/emacs/modules/bd--devel.el index 2c6ef02..dc68b4b 100644 --- a/.config/emacs/modules/bd--devel.el +++ b/.config/emacs/modules/bd--devel.el @@ -145,32 +145,7 @@ Otherwise, open the repository's main page." (require 'geiser-mode) (require 'geiser-guile) -(defcustom doc-dirs '() - "Defines a buffer-local list of directories to find -documentation." - :type 'list - :group 'docs - :safe 'listp - :local t) - -(defun bd/selector-doc (dir) - "List all HTML files in a directory (recursive), and -display for opening with browser." - (selector-source-create - dir - :candidates - (-map - (lambda (d) (selector-candidate-create (file-relative-name d dir) :value d)) - (directory-files-recursively dir ".html")) - :actions - (list (lambda (x) (eww-open-file x))))) - -(defun bd/doc-finder () - (interactive) - (unwind-protect - (selector - (append (-map (lambda (x) (bd/selector-doc x)) doc-dirs) - (list (bd/selector-search)))))) +(use-package cider) (use-package gdb-mi :config @@ -178,8 +153,6 @@ display for opening with browser." (use-package eglot :defer t - :hook ((c-mode . eglot-ensure) - (c++-mode . eglot-ensure)) :bind (:map eglot-mode-map ("C-c C-f" . eglot-format) ("C-c C-e" . eglot-rename)) @@ -190,12 +163,13 @@ display for opening with browser." (add-to-list 'eglot-server-programs '(c-mode . ("ccls" "--init={\"clang\": {\"extraArgs\": [\"-std=c++20\"]}}")))) -(use-package cc-mode - :hook (((c-mode c++-mode) . (lambda () (setq-local doc-dirs '("~/dc/cppreference")))))) - (use-package rainbow-mode :hook css-mode) +(use-package lua-mode) + +(use-package clojure-mode) + (use-package slime :defer t :commands slime @@ -205,6 +179,11 @@ display for opening with browser." ;; 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 @@ -214,7 +193,6 @@ display for opening with browser." show-paren-when-point-in-periphery t show-paren-when-point-inside-paren t)) - (use-package rainbow-delimiters :hook prog-mode) @@ -223,6 +201,9 @@ display for opening with browser." emacs-lisp-mode eshell-mode geiser-repl-mode + clojure-mode + cider-repl-mode + lisp-mode scheme-mode slime-repl-mode @@ -234,6 +215,7 @@ display for opening with browser." ('(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) diff --git a/.config/emacs/modules/bd--dictionary.el b/.config/emacs/modules/bd--dictionary.el index bf83544..e032837 100644 --- a/.config/emacs/modules/bd--dictionary.el +++ b/.config/emacs/modules/bd--dictionary.el @@ -9,6 +9,12 @@ (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/.config/emacs/modules/bd--emms.el b/.config/emacs/modules/bd--emms.el index 456d83a..f4e5064 100644 --- a/.config/emacs/modules/bd--emms.el +++ b/.config/emacs/modules/bd--emms.el @@ -18,7 +18,7 @@ playback." (emms-stop) (when (bufferp emms-playlist-buffer-name) (kill-buffer emms-playlist-buffer-name)) - (emms-play-directory-tree (expand-file-name "~/ik/music/")) + (emms-play-directory-tree (expand-file-name "~/ik/")) (emms-shuffle)) (defun switch-to-emms () (interactive) diff --git a/.config/emacs/modules/bd--exwm.el b/.config/emacs/modules/bd--exwm.el index 8316b0f..1738ebe 100644 --- a/.config/emacs/modules/bd--exwm.el +++ b/.config/emacs/modules/bd--exwm.el @@ -3,20 +3,30 @@ ;;; Code: -(bd/set-bg) - (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] @@ -28,12 +38,13 @@ that buffer." [?\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-n] . other-window) ([?\s-p] . (lambda () (interactive) (other-window -1))) @@ -47,15 +58,21 @@ that buffer." ([f10] . emms-next) ([print] . bd/shoot-part) ([S-print] . bd/shoot-full) - ([?\s-I] . bd/doc-finder) ([?\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)))) + (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]) @@ -78,6 +95,13 @@ that buffer." ([?\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 @@ -87,21 +111,5 @@ that buffer." (setopt tab-bar-select-tab-modifiers '(super)) -(defvar new-mode-line nil) -(defun set-new-mode-line () - (setq new-mode-line - (replace-regexp-in-string - "%" "%%" - (format "[%s] [%s]" - (shell-command-to-string "/home/bdunahu/.local/bin/mail-string 2>/dev/null") - (shell-command-to-string "/home/bdunahu/.local/bin/t1-string 2>/dev/null"))))) - -(defvar-local bd/external-mode-line - '(:eval (when new-mode-line - new-mode-line))) - -(run-with-timer t 30 #'set-new-mode-line) -(add-to-list 'global-mode-string bd/external-mode-line) - (provide 'bd--exwm) ;;; bd--exwm.el ends here diff --git a/.config/emacs/modules/bd--files.el b/.config/emacs/modules/bd--files.el index f4c4f4f..c2f3df8 100644 --- a/.config/emacs/modules/bd--files.el +++ b/.config/emacs/modules/bd--files.el @@ -3,6 +3,11 @@ ;;; Code: +(use-package files + :config + (setopt safe-local-variable-directories + '("/home/bdunahu/pt/guix"))) + (use-package recentf :demand t :bind @@ -19,6 +24,9 @@ (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))) @@ -37,6 +45,7 @@ '(("gba" . "mgba") ("z64" . "mupen64plus") ("iso" . "dolphin-emu") + ("ciso" . "dolphin-emu") ("n64" . "mupen64plus") ("sfc" . "bsnes")))))) (start-process command nil command (expand-file-name file)))) @@ -53,14 +62,16 @@ (bd/open-with-function #'bd/zathura)) ((string-match (regexp-opt '("mkv" "mov" "mp4" "webm" "m4v" "wav" "mp3" "opus" "ogv" "flac" - "m4a")) ext) + "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")) ext) + ((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) diff --git a/.config/emacs/modules/bd--irc.el b/.config/emacs/modules/bd--irc.el deleted file mode 100644 index 99b1a49..0000000 --- a/.config/emacs/modules/bd--irc.el +++ /dev/null @@ -1,29 +0,0 @@ -;;; -*- lexical-binding: t; -*- -;;; Commentary: -;;; Code: - - -(require 'fill-column) -(use-package rcirc - :hook - ((rcirc-mode . (lambda () - (setq-local fill-column-desired-width 80) - (fill-column-mode) - (rcirc-omit-mode)))) - :config - (setopt rcirc-fill-column 80 - rcirc-omit-threshold 10 - 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)))) - - -(provide 'bd--irc) -;;; bd--irc.el ends here diff --git a/.config/emacs/modules/bd--minibuffer.el b/.config/emacs/modules/bd--minibuffer.el index 66d14de..cf5641b 100644 --- a/.config/emacs/modules/bd--minibuffer.el +++ b/.config/emacs/modules/bd--minibuffer.el @@ -18,7 +18,7 @@ flex) icomplete-delay-completions-threshold 0 icomplete-compute-delay 0.10 - icomplete-show-matches-on-no-input t + icomplete-show-matches-on-no-input nil icomplete-separator " | " completions-max-height '30 completions-detailed t) diff --git a/.config/emacs/modules/bd--modeline.el b/.config/emacs/modules/bd--modeline.el index 5d2af9e..2ca7ccb 100644 --- a/.config/emacs/modules/bd--modeline.el +++ b/.config/emacs/modules/bd--modeline.el @@ -22,7 +22,7 @@ (defvar-local bd/buffer-identification-mode-line '(:eval (format "%s" (propertize (buffer-name) 'face (if (mode-line-window-selected-p) - 'font-lock-keyword-face + 'modus-themes-fg-cyan-intense 'mode-line-inactive)))) "Formats the modeline-buffer-name.") @@ -39,6 +39,11 @@ '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) @@ -63,6 +68,7 @@ (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)) @@ -84,6 +90,8 @@ mode-line-mule-info mode-line-modified mode-line-front-space + bd/global-mode-string + mode-line-front-space )) diff --git a/.config/emacs/modules/bd--notes.el b/.config/emacs/modules/bd--notes.el index 70bc3f8..13f80f4 100644 --- a/.config/emacs/modules/bd--notes.el +++ b/.config/emacs/modules/bd--notes.el @@ -23,7 +23,8 @@ then pastes the active region." (when contents (insert (format "\n\n%s" contents))) (current-buffer))))) -(keymap-global-set "C-c s" #'bd/send-to-scratch) +(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 () @@ -62,7 +63,7 @@ KEYWORDS is a list of strings." "csu" "umass" "cs" "guix" "emacs" "programs" "mem") denote-directory (expand-file-name "~/dc/") - denote-prompts '(title file-type keywords) + denote-prompts '(title file-type keywords subdirectory) denote-dired-directories (list denote-directory))) (use-package denote-journal diff --git a/.config/emacs/modules/bd--org.el b/.config/emacs/modules/bd--org.el index 79a3de1..17790a0 100644 --- a/.config/emacs/modules/bd--org.el +++ b/.config/emacs/modules/bd--org.el @@ -51,7 +51,7 @@ (setopt org-latex-toc-command "\\tableofcontents \\clearpage" org-latex-src-block-backend 'listings org-latex-image-default-width ".6\\linewidth" - org-latex-compiler "pdflatex" + org-latex-compiler "xelatex" org-export-with-toc nil org-export-preserve-breaks nil org-latex-classes @@ -76,7 +76,6 @@ keepspaces=true} \\lstset{columns=fullflexible,basicstyle=\\ttfamily} \\setlength{\\headsep}{0.75 in} -\\setlength{\\parindent}{0 in} \\setlength{\\parskip}{0.1 in} \\makeatletter @@ -110,6 +109,15 @@ ("\\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) @@ -121,9 +129,7 @@ (advice-add 'org-refile :after 'org-save-all-org-buffers) (defvar-local bd/course-list - '(("501" . ?0) - ("535" . ?3) - ("590" . ?9)) + '(("598" . ?0)) "Courses for tagging, capturing, and various agenda views.") diff --git a/.config/emacs/modules/bd--shells.el b/.config/emacs/modules/bd--shells.el index 6fff9e6..1072694 100644 --- a/.config/emacs/modules/bd--shells.el +++ b/.config/emacs/modules/bd--shells.el @@ -48,7 +48,7 @@ allowed." (use-package em-banner :config - (setopt eshell-banner-message (concat "\n" (propertize " " 'display (create-image (expand-file-name "images/raven.png" user-emacs-directory) 'png nil :scale 0.8 :align-to "center")) "\n"))) + (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 @@ -96,6 +96,8 @@ allowed." (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)) diff --git a/.config/emacs/modules/bd--tabs.el b/.config/emacs/modules/bd--tabs.el index 49549f7..6d4f12f 100644 --- a/.config/emacs/modules/bd--tabs.el +++ b/.config/emacs/modules/bd--tabs.el @@ -3,21 +3,6 @@ ;;; Code: -(use-package time - :demand t - :init - (display-time) - :config - (setopt display-time-format " [%m/%d %H:%M] " - display-time-default-load-average nil)) - -(use-package battery - :demand t - :init - (display-battery-mode) - :config - (setopt battery-update-interval 90)) - (use-package tab-bar :demand t :config @@ -28,6 +13,13 @@ (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) @@ -39,9 +31,7 @@ ;; remove useless gui elements tab-bar-format - '(tab-bar-format-tabs - tab-bar-format-align-right - tab-bar-format-global) + '(tab-bar-format-tabs) tab-bar-close-button-show nil tab-bar-auto-width-max nil diff --git a/.config/emacs/modules/bd--themes.el b/.config/emacs/modules/bd--themes.el index ddcfcf2..cd24cab 100644 --- a/.config/emacs/modules/bd--themes.el +++ b/.config/emacs/modules/bd--themes.el @@ -3,76 +3,113 @@ ;;; Code: -(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 Math TeX Gyre" - :height 110) -(set-face-attribute 'fixed-pitch nil - :family "Terminus" - :height 110) -(set-face-attribute 'default nil - :family "Terminus" - :height 140) - - (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 - ;; Disable all other themes to avoid awkward blending: - (mapc #'disable-theme custom-enabled-themes) (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 - `(mode-line ((,c :overline ,keyword))) - `(mode-line-inactive ((,c :overline ,bg-button-inactive))) - `(eshell-prompt ((,c :foreground ,fg-main :background ,bg-dim :height 1.1 :extend t)))))) - (add-hook 'modus-themes-post-load-hook #'bd/modus-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 nil + modus-themes-variable-pitch-ui t + modus-themes-prompts '(bold) modus-themes-headings - '((0 variable-pitch bold 1.5) - (1 variable-pitch bold 1.4) + '((0 variable-pitch regular 1.4) + (1 variable-pitch regular 1.4) (2 variable-pitch regular 1.3) - (3 variable-pitch regular 1.1) - (t variable-pitch regular 1.0)) - + (3 variable-pitch regular 1.2) + (t variable-pitch regular 1.2)) modus-themes-common-palette-overrides - '((bg-mode-line-active bg-main) - (bg-mode-line-inactive bg-main) - (border-mode-line-active bg-main) - (border-mode-line-inactive bg-main) - (bg-line-number-active bg-dim) - (bg-line-number-inactive bg-dim) - (fg-heading-1 fg-term-blue-bright) - (fg-heading-2 fg-term-magenta-bright) + '((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 bg-main) - (bg-tab-other bg-button-inactive)))) + (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") -(load-theme 'modus-vivendi-tinted :no-confirm) + (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/.config/emacs/modules/bd--utility.el b/.config/emacs/modules/bd--utility.el index d48ff02..ee74f58 100644 --- a/.config/emacs/modules/bd--utility.el +++ b/.config/emacs/modules/bd--utility.el @@ -7,10 +7,12 @@ (defun bd/set-frame-alpha (value) - "Set the transparency of the frame background to VALUE. 0=transparent/100=opaque." + "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))) - (set-frame-parameter (selected-frame) 'alpha `(,value . ,value)) + (mapc (lambda (f) + (set-frame-parameter f 'alpha `(,value . ,value))) + (frame-list)) (message "Alpha set to %d" value)) (defun bd/set-bg (&optional arg) @@ -19,10 +21,11 @@ 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 - -TODO default folder" - (interactive "f") +- 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 @@ -99,10 +102,12 @@ TODO default folder" '(eww-mode))) (defun bd/buffer-exwm-p (buf) - "Return non-nil if BUF is an `exwm-mode' buffer." - (member - (buffer-local-value 'major-mode (get-buffer buf)) - '(exwm-mode))) + "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." diff --git a/.config/emacs/modules/bd--window.el b/.config/emacs/modules/bd--window.el index 59f7dbc..bdc173b 100644 --- a/.config/emacs/modules/bd--window.el +++ b/.config/emacs/modules/bd--window.el @@ -48,7 +48,10 @@ ["" ("a" "alpha" bd/set-frame-alpha) ("w" "wallpaper" bd/set-bg) - ("t" "theme" load-theme)]]) + ("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) |
