summaryrefslogtreecommitdiff
path: root/.config/emacs
diff options
context:
space:
mode:
Diffstat (limited to '.config/emacs')
-rw-r--r--.config/emacs/images/raven.pngbin99488 -> 134324 bytes
-rw-r--r--.config/emacs/images/wolf.pngbin0 -> 117636 bytes
-rw-r--r--.config/emacs/init.el29
-rw-r--r--.config/emacs/libraries/exwm-outer-gaps.el77
-rw-r--r--.config/emacs/libraries/powerthesaurus.el940
-rw-r--r--.config/emacs/libraries/selector.el7
-rw-r--r--.config/emacs/modules/bd--browse.el46
-rw-r--r--.config/emacs/modules/bd--buffer.el4
-rw-r--r--.config/emacs/modules/bd--chat.el118
-rw-r--r--.config/emacs/modules/bd--devel.el46
-rw-r--r--.config/emacs/modules/bd--dictionary.el6
-rw-r--r--.config/emacs/modules/bd--emms.el2
-rw-r--r--.config/emacs/modules/bd--exwm.el52
-rw-r--r--.config/emacs/modules/bd--files.el15
-rw-r--r--.config/emacs/modules/bd--irc.el29
-rw-r--r--.config/emacs/modules/bd--minibuffer.el2
-rw-r--r--.config/emacs/modules/bd--modeline.el10
-rw-r--r--.config/emacs/modules/bd--notes.el5
-rw-r--r--.config/emacs/modules/bd--org.el16
-rw-r--r--.config/emacs/modules/bd--shells.el4
-rw-r--r--.config/emacs/modules/bd--tabs.el26
-rw-r--r--.config/emacs/modules/bd--themes.el137
-rw-r--r--.config/emacs/modules/bd--utility.el25
-rw-r--r--.config/emacs/modules/bd--window.el5
24 files changed, 1391 insertions, 210 deletions
diff --git a/.config/emacs/images/raven.png b/.config/emacs/images/raven.png
index e2900c1..6f27c08 100644
--- a/.config/emacs/images/raven.png
+++ b/.config/emacs/images/raven.png
Binary files differ
diff --git a/.config/emacs/images/wolf.png b/.config/emacs/images/wolf.png
new file mode 100644
index 0000000..fabad74
--- /dev/null
+++ b/.config/emacs/images/wolf.png
Binary files differ
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)