summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--basic.el34
-rw-r--r--bookmark-conf.el7
-rw-r--r--count.el161
-rw-r--r--dashboard.el15
-rw-r--r--durand-align.el61
-rw-r--r--durand-bongo.el2
-rw-r--r--durand-dict.el1061
-rw-r--r--elisp.el16
-rw-r--r--eshell-conf.el92
-rw-r--r--gnus-conf.el2
-rw-r--r--ibuffer.el75
-rw-r--r--init.el10
-rw-r--r--input-conf.el118
-rw-r--r--ithkuil.el67
-rw-r--r--mail.el18
-rw-r--r--modeline.el52
-rw-r--r--org-conf.el67
-rw-r--r--pdf.el31
-rw-r--r--tex-conf.el1
-rw-r--r--theme.el2
-rw-r--r--view-conf.el4
21 files changed, 1831 insertions, 65 deletions
diff --git a/basic.el b/basic.el
index 6e1d7fd..54fb768 100644
--- a/basic.el
+++ b/basic.el
@@ -74,9 +74,9 @@
(set 'initial-major-mode 'emacs-lisp-mode)
-;;; echo quickly
+;;; echo slowly
-(setq echo-keystrokes 0.002)
+(setq echo-keystrokes 1)
;;; Scroll conservatively please
@@ -168,6 +168,7 @@
(add-to-list 'default-frame-alist '(width . 118))
(add-to-list 'default-frame-alist '(height . 35))
(add-to-list 'default-frame-alist '(font . "Droid Sans Mono for Powerline-20"))
+;; (add-to-list 'default-frame-alist '(font . "NotoSansCuneiform-Regular-20"))
(add-to-list 'default-frame-alist '(ns-transparent-titlebar . t))
(add-to-list 'default-frame-alist '(ns-appearance . dark))
(add-to-list 'default-frame-alist '(fullscreen . maximized))
@@ -175,6 +176,19 @@
(setq revert-without-query '(".*"))
(set-face-attribute 'variable-pitch nil :family "Avenir" :height 1.0)
+;;; Font for Cuneiform
+
+;; NOTE: Remember to install the font on the computer system so that
+;; Emacs can access the font, and remember that the name of the font
+;; is not necessarily equal to the name of the font file.
+
+;; (set-fontset-font
+;; t
+;; 'cuneiform
+;; (font-spec
+;; :size 20
+;; :name "Noto Sans Cuneiform"))
+
;;; Adjust default size
;;;###autoload
@@ -641,6 +655,13 @@ buffers that I do not want to kill automatically.")
(setq xref-search-program 'ripgrep)
+;;; DOC and SOURCE directory
+
+(setq doc-directory
+ (file-name-as-directory
+ "/Users/durand/w.emacs.d/emacs/etc/"))
+(setq source-directory "/Users/durand/w.emacs.d/emacs/")
+
;;; Package management
;;;###autoload
@@ -657,6 +678,15 @@ The remaining CONFIGS are evaluated after the package is loaded."
(require ,package-name)
,@configs))
+;;; UUID generation
+
+(defun durand-uuid ()
+ "Generate a kind of unique string."
+ (format
+ "<%s.%s@durand-emacs.local>"
+ (substring (secure-hash 'md5 (format-time-string "%x%X-%z")) 0 8)
+ (substring (secure-hash 'sha256 (format-time-string "%s%N")) 0 8)))
+
;;; Test internet connection
(defun durand-internet-on (&optional host)
diff --git a/bookmark-conf.el b/bookmark-conf.el
index ff9983b..e747373 100644
--- a/bookmark-conf.el
+++ b/bookmark-conf.el
@@ -100,6 +100,7 @@
(cons "PDF" #'blist-pdf-p)
(cons "C" #'blist-c-p)
(cons "Gnus" #'blist-gnus-p)
+ (cons "EWW" #'blist-eww-p)
(cons "ELisp" #'blist-elisp-p)
(cons "Eshell" #'blist-eshell-p)
(cons "Dired" #'blist-dired-p)))
@@ -401,6 +402,12 @@ BOOKMARK should be set by `durand-set-external-bookmark'."
(cons
"https://wmail1.cc.ntu.edu.tw/rc/?_task=mail&_mbox=INBOX"
"(External) NTU mail")
+ (cons
+ "https://www.brhvid.com/upanisad"
+ "(External) उपनिषदः")
+ (cons
+ "https://share1.chaoxing.com/share/mobile/mooc/tocourse/93004733?appId="
+ "(External) अन्या उपनिषदः")
))
;;; A much quicker alternative to `bookmark-write-file'
diff --git a/count.el b/count.el
new file mode 100644
index 0000000..0be7b82
--- /dev/null
+++ b/count.el
@@ -0,0 +1,161 @@
+;;; count.el --- Easy counting facility -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2024 Jean Sévère Durand
+
+;; Author: Jean Sévère Durand <durand@jsdurand.xyz>
+;; Keywords: emulations, games
+
+;; This program 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.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Counting mode
+
+;;; Code:
+
+;;; Variables
+
+;;;; Buffer name
+
+(defvar counting-buffer-name "*Count*"
+ "The name of the buffer within which to count.")
+
+;;;; Font-scaling factor
+
+(defvar counting-font-step 10
+ "The proportion by which the counting value font size is \
+increased.")
+
+;;;; Counted value
+
+(defvar-local count-mode-value 0
+ "The value of the current count.")
+
+;;; Major mode
+
+(define-derived-mode count-mode special-mode "Count"
+ "Major mode for counting."
+ (count-refresh)
+ (set 'cursor-type nil))
+
+(let ((map count-mode-map))
+ (define-key map (vector 'up) #'count-up)
+ (define-key map (vector 'down) #'count-down)
+ (define-key map (vector ?r) #'count-refresh)
+ (define-key map (vector ?o) #'count-reset)
+ (define-key map (vector ?=) #'count-enlarge)
+ (define-key map (vector ?-) #'count-shrink))
+
+;;; Functions to start counting
+
+;;;; Count in an old buffer if possible
+
+(defun count-start-or-switch ()
+ "Start counting in an old buffer if possible."
+ (interactive)
+ (let ((buffer (get-buffer-create counting-buffer-name)))
+ (with-current-buffer buffer
+ (count-mode))
+ (switch-to-buffer buffer)))
+
+;;;; Count in a new buffer always
+
+(defun count-start ()
+ "Start counting in a new buffer."
+ (interactive)
+ (let* ((name (generate-new-buffer-name counting-buffer-name))
+ (buffer (get-buffer-create name)))
+ (with-current-buffer buffer
+ (count-mode))
+ (switch-to-buffer buffer)))
+
+;;; Auxiliary functions
+
+;;;; Format the counted value
+
+(defvar text-scale-mode-step)
+
+(defun count-make-pad-string (number)
+ "Make a padding string that centers the NUMBER."
+ (declare (pure t) (side-effect-free t))
+ (let* ((number-str (format "%d" number))
+ (number-str-width (* (string-pixel-width number-str)
+ ;; account for the font-size scales
+ (expt
+ text-scale-mode-step
+ counting-font-step)))
+ (space-width (string-pixel-width (string #x20)))
+ (padding (/ (- (window-pixel-width) (* 2 space-width)
+ number-str-width)
+ 2.0))
+ (height (window-body-height nil 'remap))
+ (half (floor height 2)))
+ (concat
+ (make-string half #xa)
+ (propertize
+ (string #x20)
+ 'display (list 'space :width (list padding)))
+ number-str)))
+
+(defun count-refresh ()
+ "Refresh the counting buffer."
+ (interactive)
+ (cond
+ ((derived-mode-p 'count-mode)
+ (let ((inhibit-read-only t))
+ (setq text-scale-mode-amount counting-font-step)
+ (text-scale-mode 1)
+ (delete-region (point-min) (point-max))
+ (insert (count-make-pad-string count-mode-value))))
+ ((user-error
+ "This function needs to be in the count-mode"))))
+
+(defun count-up (&optional arg)
+ "Increase the count by ARG."
+ (interactive "P")
+ (setq arg (cond ((null arg) 1) ((prefix-numeric-value arg))))
+ (setq count-mode-value (+ arg count-mode-value))
+ (count-refresh))
+
+(defun count-down (&optional arg)
+ "Decrease the count by ARG."
+ (interactive "P")
+ (setq arg (cond ((null arg) 1) ((prefix-numeric-value arg))))
+ (setq count-mode-value (- count-mode-value arg))
+ (count-refresh))
+
+(defun count-reset ()
+ "Reset `count-mode-value' to zero."
+ (interactive)
+ (setq count-mode-value 0)
+ (count-refresh))
+
+(defun count-enlarge (&optional arg)
+ "Increase the font size by ARG many times.
+The size of one step is defined by `text-scale-mode-step'."
+ (interactive "p")
+ (setq arg (cond ((null arg) 1) ((prefix-numeric-value arg))))
+ (setq counting-font-step (+ counting-font-step arg))
+ (count-refresh))
+
+(defun count-shrink (&optional arg)
+ "Decrease the font size by ARG many times.
+The size of one step is defined by `text-scale-mode-step'."
+ (interactive "p")
+ (setq arg (cond ((null arg) 1) ((prefix-numeric-value arg))))
+ (setq counting-font-step (- counting-font-step arg))
+ (count-refresh))
+
+(provide 'count)
+;;; count.el ends here
diff --git a/dashboard.el b/dashboard.el
index 393df59..ba2468d 100644
--- a/dashboard.el
+++ b/dashboard.el
@@ -131,7 +131,7 @@ If FORCE is non-nil, re-gerenate the dashboard buffer."
(insert
(dashboard-center-string
(propertize
- "ॐ मणिपद्मे हूम्"
+ "ॐ अरपचनधीः"
'face (list :height 600))))
(goto-char (point-min))
(set-buffer-modified-p nil)
@@ -167,8 +167,9 @@ common functionalities more conveniently."
(define-key m (vector ?T) #'modeline-toggle)
(define-key m (vector ?t) #'durand-view-timers-or-temps)
(define-key m (vector ?o) #'durand-open-object)
- (define-key m (vector ?g) #'gnus)
+ (define-key m (vector ?g) #'gnus-unplugged)
(define-key m (vector ?h) #'durand-ibuffer)
+ (define-key m (vector ?e) #'eshell)
(define-key m (vector ?f) #'find-file)
(define-key m (vector ?F) #'find-file-other-tab)
(define-key m (vector ?a) #'dashboard-org-agenda)
@@ -176,8 +177,18 @@ common functionalities more conveniently."
(define-key m (vector ?C) #'dashboard-org-capture)
(define-key m (vector ?p) #'project-switch-project)
(define-key m (vector ?x) #'execute-extended-command)
+ (define-key m (vector ?w) #'durand-wifi-toggle)
+ (define-key m (vector ?v) #'dashboard-load-view-map)
(define-key m (vector ?n) #'novel))
+;;; Define a wrapper for loading view-conf if needed.
+
+(defun dashboard-load-view-map ()
+ "Load view-conf.el and then change the binding in dashboard mode."
+ (interactive)
+ (load-config "view-conf.el")
+ (define-key dashboard-mode-map (vector ?v) durand-view-map))
+
;;; Define novel command as a wrapper, if not already loaded
(cond
diff --git a/durand-align.el b/durand-align.el
new file mode 100644
index 0000000..079f421
--- /dev/null
+++ b/durand-align.el
@@ -0,0 +1,61 @@
+;;; durand-align.el --- Pixel alignment -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2024 Jean Sévère Durand
+
+;; Author: Jean Sévère Durand <durand@jsdurand.xyz>
+;; Keywords: wp, faces
+
+;; This program 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.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Some little functions to center buffer texts at pixel level
+;; precision.
+
+;;; Code:
+
+(defun durand-center (&optional pixels)
+ "Center the buffer.
+If PIXELS is not-nil, use that as body width in pixels."
+ (let* ((body-width (cond ((and pixels (numberp pixels) (> pixels 0))
+ pixels)
+ ((car (window-text-pixel-size
+ nil
+ (cons (window-start) 0)
+ (window-end))))))
+ (len (floor (- (window-body-width nil t) body-width) 2))
+ (prop (list 'space :width (list len)))
+ (str (propertize (string 32) 'display prop 'durand-center t)))
+ (save-excursion
+ (goto-char (point-min))
+ (while (not (eobp))
+ (cond
+ ((get-text-property (point) 'durand-center)
+ (put-text-property (point) (1+ (point)) 'display prop))
+ ((insert str)))
+ (forward-line 1)))))
+
+(defun durand-cancel-center ()
+ "Cancel the inserted characters."
+ (save-excursion
+ (goto-char (point-min))
+ (while (not (eobp))
+ (cond
+ ((get-text-property (point) 'durand-center)
+ (delete-char 1)))
+ (forward-line 1))))
+
+
+(provide 'durand-align)
+;;; durand-align.el ends here
diff --git a/durand-bongo.el b/durand-bongo.el
index b183fba..2165081 100644
--- a/durand-bongo.el
+++ b/durand-bongo.el
@@ -104,7 +104,7 @@
(setq bongo-enabled-backends (list 'mpv))
(setq bongo-custom-backend-matchers
- '((mpv local-file "webm" "m4a")
+ '((mpv local-file "webm" "m4a" "opus")
;; NOTE
;;
;; For a regular expression as a matcher, it is supposed to be
diff --git a/durand-dict.el b/durand-dict.el
new file mode 100644
index 0000000..0eb98e4
--- /dev/null
+++ b/durand-dict.el
@@ -0,0 +1,1061 @@
+;;; durand-dict.el --- An Emacs interface to dictionaries -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2025 Jean Sévère Durand
+
+;; Author: Jean Sévère Durand <durand@jsdurand.xyz>
+;; Keywords: convenience, emulations
+
+;; This program 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.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This aims to provide a little interface to work with dictionaries
+;; of the choice. One can customize the dictionaries used and how we
+;; parse them.
+;;
+;; In summary, this package lets the user send a request to some
+;; specified dictionary website and parse the output into some
+;; customized format, so that Emacs can function as an interface to
+;; multiple dictionaries at once. The supposed benefit is to check
+;; the dictionaries without opening the browser.
+
+;;; Code:
+
+;;;; Requirements
+
+;; structure library
+(require 'cl-lib)
+
+;; parsing library
+(require 'dom)
+
+;; regular expression building library
+(require 'rx)
+
+;; URL fetching library
+(require 'url)
+
+;; obtaining word at point
+(require 'thingatpt)
+
+;; Multilingually reading command
+;;
+;; For some reason mule-cmds does not provide a package, so we simply
+;; ignore errors here.
+(ignore-errors (require 'mule-cmds))
+
+;;;; Convenient key-bindings
+
+(defvar durand-dictionary-keymap (make-sparse-keymap "dictionary")
+ "A keymapp for dictionary-related functionaties.")
+
+(define-key durand-dictionary-keymap (vector ?t) #'dudict-quick-tamil)
+
+(define-key global-map (vector 3 ?d) durand-dictionary-keymap)
+(define-key global-map (vector ?\H-d) durand-dictionary-keymap)
+
+;;;;; A history variable
+
+(defvar dudict-tamil-history nil
+ "History variable for the Tamil search.")
+
+;;;;; Quick search
+
+(defun dudict-quick-tamil (word include-tamilverb)
+ "Quickly search a Tamil WORD.
+Asks the user what word to search.
+
+If the cursor is over a word, that word is offered as the
+default.
+
+If INCLUDE-TAMILVERB is non-nil, also search for the Tamil Verb
+website."
+ (interactive
+ (let ((def (thing-at-point 'word)))
+ (list
+ (read-multilingual-string "Word to search: " def "tamil99")
+ current-prefix-arg)))
+ (let ((methods
+ (cons
+ dudict-search-agarathi
+ (cond (include-tamilverb (list dudict-search-tamilverb))))))
+ (dudict-search methods word #'dudict-tamil-buffer-name)))
+
+;;;; Derived mode
+
+(define-derived-mode dudict-mode org-mode "DUDICT"
+ "Major mode for viewing my custom dictionaries."
+ (setq truncate-lines nil)
+ (view-mode t))
+
+;;;; Framework
+
+;;;;; Struct
+
+(cl-defstruct dudict-search
+ "Provides methods to (optionally) pre-process, to search, to
+parse, and to present the search results to the user."
+ (pre
+ nil
+ :documentation "Preprocessing function, optional"
+ :type function)
+ (search
+ nil
+ :documentation "Searching function, required.
+This should be a function that receives a word and returns the
+URL to fetch."
+ :type function)
+ (parse
+ nil
+ :documentation "Parsing function, required"
+ :type function)
+ (present
+ nil
+ :documentation "Function to print the search result to the user."
+ :type function)
+ (name
+ "dudict"
+ :documentation
+ "Search name that is used to make the presentation buffer."
+ :type string))
+
+;;;;; Main framework function
+;; Main framework function
+(defun dudict-search (search-method word present-fun)
+ "Search for the definition of WORD by means of SEARCH-METHOD.
+SEARCH-METHOD should be a struct `dudict-search' that provides
+methods to pre-process, to search, and to post-process the search
+results. All this does is to integrate various methods provided.
+
+PRESENT-FUN should be a function that accepts the WORD and
+returns the buffer name to contain the search results."
+ (cond
+ ((dudict-search-p search-method)
+ (setq search-method (list search-method)))
+ ((and (listp search-method)
+ (eval
+ (cons
+ 'and
+ (mapcar #'dudict-search-p search-method)))))
+ ((error "Requires a `dudict-search' struct or a list of \
+them, but found %S"
+ search-method)))
+ (cond
+ ((and (functionp present-fun)
+ (equal (func-arity present-fun) (cons 1 1))))
+ ((error "Requires a function with one argument for PRESENT-FUN, \
+but got %S"
+ present-fun)))
+ (let ((present-name (funcall present-fun word))
+ (ls search-method)
+ temp-buffer method)
+ (cond
+ ((setq temp-buffer (get-buffer present-name))
+ ;; already searched
+ (switch-to-buffer temp-buffer))
+ (t
+ ;; must be new buffer
+ (setq temp-buffer (get-buffer-create present-name))
+ (while (consp ls)
+ (setq method (car ls))
+ (setq ls (cdr ls))
+ (let* ((name (dudict-search-name method))
+ (preprocess (dudict-search-pre method))
+ (search (dudict-search-search method))
+ (parse (dudict-search-parse method))
+ (present (dudict-search-present method))
+ temp-buffer parse-result)
+ (cond
+ ((functionp preprocess)
+ (setq word (funcall preprocess word))))
+ (cond
+ ((and
+ (functionp search)
+ (equal (func-arity search) (cons 1 1))))
+ ((error
+ "Requires a function with one argument, but found %S"
+ search)))
+ (setq search (funcall search word))
+ (setq
+ temp-buffer
+ (url-retrieve-synchronously
+ search t t 20))
+ (cond
+ ((functionp parse))
+ (error "Requires a function to parse, but found %S"
+ parse))
+ (with-current-buffer temp-buffer
+ (setq parse-result (funcall parse)))
+ (kill-buffer temp-buffer)
+ (cond
+ ((and (functionp present)
+ (equal (func-arity present) (cons 1 1))))
+ ((error
+ "Requires a function with one argument, but found %S"
+ present)))
+ ;; already created
+ (setq temp-buffer (get-buffer present-name))
+ (with-current-buffer temp-buffer
+ (goto-char (point-max))
+ (newline)
+ (insert "* " name)
+ (newline)
+ (funcall present parse-result))))
+ (switch-to-buffer temp-buffer)
+ (dudict-mode)
+ (goto-char (point-min))))))
+
+;;;; Tamil dictionary buffer name
+
+(defun dudict-tamil-buffer-name (word)
+ "Return the buffer name for holding Tamil WORD searches."
+ (declare (side-effect-free t) (pure t))
+ (concat "தமிழ் - " word))
+
+;;;; agarathi dictionary
+;; For searching the agarathi dictionary, we for now do not need to
+;; preprocess the search term, but in the future it might be useful to
+;; add some preprocessing so that we do not need to enter in the Tamil
+;; script (some sources do not always use the Tamil scripts).
+;;
+;; The search function just queries the website and returns the
+;; buffer.
+;;
+;; The parsing function converts from the Document Object Model to our
+;; custom structs: This is for the ease and the convenience of
+;; presentation.
+;;
+;; Then the present function can iterate through the parse result
+;; easily and present the search result to the user in a
+;; well-structured format that is easy to read and understand.
+;;
+;; The name is surely the string "அகராதி" (अकरादि).
+
+;;;;; Search Struct
+
+(defvar dudict-search-agarathi nil
+ "The search struct that is used to search the agarathi dictionary.")
+
+(setq dudict-search-agarathi
+ (make-dudict-search
+ :name "அகராதி"
+ :pre nil
+ :search (function
+ (lambda (word)
+ (concat "https://agarathi.com/word/" word)))
+ :parse #'dudict-parse-agarathi
+ :present #'dudict-present-agarathi))
+
+;;;;; Short-cut
+
+(defun dudict-search-agarathi (word)
+ "A short-cut that passes `dudict-search-agarathi' and WORD to
+`dudict-search'."
+ (interactive
+ (read-string "Enter search term: " nil 'dudict-tamil-history))
+ (dudict-search
+ dudict-search-agarathi word #'dudict-tamil-buffer-name))
+
+;;;;; Structures of the dictionary website
+
+;;;;;; The entire time line
+(cl-defstruct agarathi-timeline
+ "An entire agarathi search result is called a timeline.
+It contains a list of panels."
+ (panels
+ nil
+ :documentation "The list of panels contained in the timeline."
+ :type list))
+
+;; verifying function
+(defun agarathi-check-valid-timeline (timeline)
+ "Check that an object is a valid timeline structure."
+ (declare (side-effect-free t) (pure t))
+ (and
+ (agarathi-timeline-p timeline)
+ (let ((ls (agarathi-timeline-panels timeline))
+ (result t)
+ temp)
+ (and
+ (listp ls)
+ (progn
+ (while (consp ls)
+ (setq temp (car-safe ls))
+ (setq ls (cdr-safe ls))
+ (cond
+ ((agarathi-check-valid-panel temp))
+ (t
+ (setq result nil)
+ (setq ls nil))))
+ result)))))
+
+;;;;;; A panel
+(cl-defstruct agarathi-panel
+ "A panel contains the search results from some single source.
+It contains a title and a list of descriptions, where each
+description corresponds to a set of definitions, roughly
+speaking."
+ (title
+ ""
+ :documentation "The title of the panel.
+Usually this is the source of the definition. When this is a
+pure advertisement panel, its title would be \"Sponsored Links\"."
+ :type string)
+ (descriptions
+ nil
+ :documentation "The list of descriptions contained in the panel."
+ :type list))
+
+;; verifying function
+(defun agarathi-check-valid-panel (panel)
+ "Check that an object is a valid panel structure."
+ (declare (side-effect-free t) (pure t))
+ (and
+ (agarathi-panel-p panel)
+ (let ((title (agarathi-panel-title panel))
+ (ls (agarathi-panel-descriptions panel))
+ (result t)
+ temp)
+ (and
+ (stringp title)
+ (listp ls)
+ (progn
+ (while (consp ls)
+ (setq temp (car-safe ls))
+ (setq ls (cdr-safe ls))
+ (cond
+ ((agarathi-check-valid-description temp))
+ (t
+ (setq result nil)
+ (setq ls nil))))
+ result)))))
+
+;;;;;; A Description
+(cl-defstruct agarathi-description
+ "A description contains some definitions along with some optional
+examples.
+
+It contains a title along with a list of definitions and a list
+of examples.
+
+Definitions and examples are basically strings."
+ (title
+ ""
+ :documentation "The title of a description.
+This in the convention of the dictionary website means the word
+that this description is describing. Since the dictionary can
+return descriptions that are not exactly equal to the searched
+term, it is necessary to keep this information for every
+description."
+ :type string)
+ (definitions
+ nil
+ :documentation "The list of definitions contained in the description."
+ :type list)
+ (examples
+ nil
+ :documentation "The list of examples contained in the description."
+ :type list))
+
+;; verifying function
+(defun agarathi-check-valid-description (description)
+ "Check that an object is a valid description structure."
+ (declare (side-effect-free t) (pure t))
+ (and
+ (agarathi-description-p description)
+ ;; check definitions
+ (let ((title (agarathi-description-title description))
+ (ls (agarathi-description-definitions description))
+ (result t)
+ temp)
+ (and
+ (stringp title)
+ (listp ls)
+ (progn
+ (while (consp ls)
+ (setq temp (car-safe ls))
+ (setq ls (cdr-safe ls))
+ (cond ((stringp temp)) (t (setq result nil) (setq ls nil))))
+ result)))
+ ;; check examples
+ (let ((ls (agarathi-description-examples description))
+ (result t)
+ temp)
+ (and
+ (listp ls)
+ (progn
+ (while (consp ls)
+ (setq temp (car-safe ls))
+ (setq ls (cdr-safe ls))
+ (cond ((stringp temp)) (t (setq result nil) (setq ls nil))))
+ result)))))
+
+;;;;; main function
+
+(defun dudict-parse-agarathi ()
+ "Parse the search result from the agarathi website.
+The current buffer is assumed to contain the search results already."
+ (let* ((dom (libxml-parse-html-region (point-min) (point-max)))
+ (timeline-ul
+ (car-safe
+ (delq
+ nil
+ (mapcar
+ (lambda (node)
+ (cond ((string= (dom-attr node 'class)
+ "timeline")
+ node)))
+ (dom-by-tag dom 'ul))))))
+ (cond
+ ((null timeline-ul)
+ (message "No timeline is found.")
+ nil)
+ ((dudict-parse-agarathi-timeline timeline-ul)))))
+
+;;;;; Archived code
+;; (defun dudict-search-agarathi (word)
+;; "Request for the definition of Tamil WORD from the dictionary
+;; website agarathi.
+
+;; WORD should be acceptable by agarathi: no processing is done to
+;; convert from some transliteration to the Tamil script."
+;; (let* ((name (concat "dudict - " word))
+;; (buffer-found (get-buffer name))
+;; (buffer
+;; (cond
+;; (buffer-found)
+;; ((url-retrieve-synchronously
+;; (concat "https://agarathi.com/word/" word)
+;; t t 20))))
+;; result titles count)
+;; (cond
+;; ((not buffer-found)
+;; (with-current-buffer buffer
+;; (let* ((dom (libxml-parse-html-region
+;; (point-min) (point-max)))
+;; (timeline-ul (delq
+;; nil
+;; (mapcar
+;; (lambda (node)
+;; (cond ((string= (dom-attr node 'class)
+;; "timeline")
+;; node)))
+;; (dom-by-tag dom 'ul))))
+;; (timelines (delq
+;; nil
+;; (mapcar
+;; (lambda (node)
+;; (let ((class (dom-attr node 'class)))
+;; (cond
+;; ((or
+;; (string= class "timeline-normal")
+;; (string=
+;; class "timeline-inverted"))
+;; node))))
+;; (dom-by-tag timeline-ul 'li))))
+;; (timeline-panels
+;; (mapcar
+;; (lambda (node) (dom-by-class node "timeline-panel"))
+;; timelines))
+;; (timeline-panels
+;; (delq
+;; nil
+;; (mapcar (lambda (node)
+;; (let ((result
+;; (dudict-parse-agarathi-panel node)))
+;; (cond
+;; ((string=
+;; (cadr result)
+;; "Sponsored Links")
+;; nil)
+;; (result))))
+;; timeline-panels))))
+;; (setq result timeline-panels)
+;; (kill-buffer buffer)))
+;; (setq buffer (get-buffer-create name))
+;; (with-current-buffer buffer
+;; (delete-region (point-min) (point-max))
+;; (goto-char (point-min))
+;; (mapc
+;; (lambda (panel)
+;; (setq titles (car panel))
+;; (setq panel (cdr panel))
+;; ;; insert panel source
+;; (insert "* " (car panel))
+;; (setq panel (cdr panel))
+;; (setq count 0)
+;; (mapc
+;; (lambda (def)
+;; (newline)
+;; (insert
+;; (format
+;; "** %s\n\n"
+;; (dom-text (nth count titles))))
+;; (setq count (1+ count))
+;; (mapc
+;; (lambda (def)
+;; (insert
+;; (mapconcat
+;; #'identity
+;; (split-string def "\n" t "\\s-+")
+;; " ")
+;; " ")
+;; ;; (newline)
+;; )
+;; def)
+;; (newline))
+;; panel)
+;; (newline 2))
+;; result))))
+;; (switch-to-buffer buffer)
+;; (dudict-mode)
+;; (goto-char (point-min))))
+
+;;;;; Parse a timeline
+(defun dudict-parse-agarathi-timeline (dom)
+ "Convert a DOM object into a timeline structure.
+See the documentation for the cl-type 'agarathi-timeline' to know more
+about the timeline structure."
+ (let* ((panels (dom-by-class dom "timeline-panel"))
+ (parsed-panels (mapcar #'dudict-parse-agarathi-panel panels))
+ (filtered-panels
+ (delq
+ nil
+ (mapcar
+ (lambda (panel)
+ (cond
+ ((dudict-agarathi-is-ad-panel panel) nil)
+ (panel)))
+ parsed-panels))))
+ (make-agarathi-timeline :panels filtered-panels)))
+
+;;;;; Filter out ads
+(defun dudict-agarathi-is-ad-panel (panel)
+ "If PANEL is a pure advertisement panel, return t, else return
+nil."
+ (declare (side-effect-free t) (pure t))
+ (and
+ ;; just in case
+ (agarathi-panel-p panel)
+ (string= (agarathi-panel-title panel) "Sponsored Links")))
+
+;;;;; Parse a panel
+
+(defun dudict-parse-agarathi-panel (dom)
+ "Convert a DOM object into a panel structure.
+See the documentation for the cl-type 'agarathi-panel' to know more
+about the panel structure."
+ (declare (side-effect-free t) (pure t))
+ (let* ((title
+ (cond
+ ((car-safe (dom-by-class dom "timeline-title")))
+ ("No title found")))
+ (title
+ (cond
+ ((listp title) (dom-texts title))
+ (title)))
+ (timeline-body (car-safe (dom-by-class dom "timeline-body")))
+ (style (cond ((string=
+ (dom-attr timeline-body 'id)
+ "winslow")
+ 'quoted)
+ ('direct)))
+ (descriptions
+ (dudict-parse-agarathi-descriptions timeline-body style)))
+ (make-agarathi-panel
+ :title title
+ :descriptions descriptions)))
+
+;; (defun dudict-parse-agarathi-panel (dom)
+;; "Convert a DOM object into a panel structure.
+;; See the documentation for the cl-type 'agarathi-panel' to know more
+;; about the panel structure."
+;; (let* ((panel (car dom))
+;; (panel-title
+;; (dom-texts (car (dom-by-class panel "timeline-title"))))
+;; (titles (delq
+;; nil
+;; (mapcar
+;; (lambda (node)
+;; (cond ((dom-attr node 'class) nil) (node)))
+;; (dom-by-tag panel 'h3))))
+;; (description
+;; (delq
+;; nil
+;; (mapcar
+;; (lambda (desc)
+;; (mapcar
+;; (lambda (node)
+;; (cond
+;; ((listp node) (dom-texts node))
+;; ((stringp node) node)))
+;; (dom-children desc)))
+;; (dom-by-class panel "description")))))
+;; (cons
+;; titles
+;; (cons panel-title (mapcar #'flatten-list description)))))
+
+;;;;; Parse descriptions
+(defun dudict-parse-agarathi-descriptions (dom style)
+ "Convert a DOM object into a list of description structures in the
+STYLE style.
+
+See the documentation of the function
+`dudict-parse-agarathi-description' for how STYLE is needed.
+
+See the documentation for the cl-type 'agarathi-description' to know
+more about the description structure."
+ (declare (side-effect-free t) (pure t))
+ ;; We walk the children of the document object model.
+ ;;
+ ;; The basic procedure is that, when we encounter a 'h3' tag, the
+ ;; text of that tag is the title of the following 'div' tag, which
+ ;; must have the class 'description'.
+ (let* ((children (dom-children dom))
+ (title "No title found")
+ child description result)
+ (while (consp children)
+ (setq child (car-safe children))
+ (setq children (cdr-safe children))
+ (cond
+ ((not (listp child)))
+ ((eq (dom-tag child) 'h3) (setq title (dom-text child)))
+ ((string= (dom-attr child 'class) "description")
+ (setq description (dudict-parse-agarathi-description
+ child style))
+ ;; Actually the parse result contains only the definitions and
+ ;; examples.
+ (setq description
+ (make-agarathi-description
+ :title title
+ :definitions (car-safe description)
+ :examples (cdr-safe description)))
+ (setq result (cons description result)))))
+ (reverse result)))
+
+;;;;; Parse one description
+(defun dudict-parse-agarathi-description (dom style)
+ "Convert a list of DOM objects into a description structure in the
+STYLE style.
+
+STYLE is either `direct' or `quoted'. Since some dictoinaries
+present the definitions as direct children of the 'description'
+tag, while some present them as the 'blockquote' children, we
+must have this information STYLE to correctly parse the
+descriptions.
+
+Note that the title is not parsed here, but in the function
+`dudict-parse-agarathi-descriptions', so we only return the cons
+of the definitions and examples contained in the description.
+
+See the documentation for the cl-type 'agarathi-description' to
+know more about the description structure."
+ (declare (side-effect-free t) (pure t))
+ (cond
+ ((listp dom))
+ ((error "DOM should be a list, but got %S: %S"
+ (type-of dom) dom)))
+ (cond
+ ((memq style (list 'direct 'quoted)))
+ ((error
+ "STYLE should be either 'direct' or 'quoted', but got %S"
+ style)))
+ (cond
+ ((eq style 'quoted)
+ (setq dom (car-safe (dom-by-tag dom 'blockquote)))))
+ ;; We walk the children of the document object model.
+ ;;
+ ;; Basically, if we encounter an element that is not a 'blockquote'
+ ;; tag, we store all of these texts into a string and later parse
+ ;; them into definitions. When we encounter 'blockquote' tags, we
+ ;; store them into examples instead.
+ (let* ((children (dom-children dom))
+ (temp-string (string))
+ definitions examples child)
+ (while (consp children)
+ (setq child (car-safe children))
+ (setq children (cdr-safe children))
+ (cond
+ ((not
+ (and
+ (listp child)
+ (eq (dom-tag child) 'blockquote)))
+ (setq temp-string
+ (concat temp-string
+ (cond
+ ((listp child) (dom-texts child))
+ ((format "%s" child))))))
+ ((cond
+ ((null definitions)
+ (setq definitions
+ (dudict-parse-agarathi-definitions temp-string))
+ (setq temp-string (string)))
+ ((setq examples (cons (dom-texts child) examples)))))))
+ (cond
+ ((and
+ (not (string-empty-p temp-string))
+ (null definitions))
+ (setq definitions
+ (dudict-parse-agarathi-definitions temp-string))))
+ (setq examples (reverse examples))
+ (cons definitions examples)))
+
+;;;;; Parse into definitions
+(defun dudict-parse-agarathi-definitions (str)
+ "Parse a string STR into a list of definitions.
+For now this just looks for the following format.
+
+SPACE NUMBER DOT SPACE
+
+More precise parsing might added in the future, if such needs
+arise."
+ (declare (side-effect-free t) (pure t))
+ (save-match-data
+ (let* ((len (length str))
+ (old-index 0)
+ (index 0)
+ result)
+ (while (< index len)
+ (cond
+ ((setq index
+ (string-match
+ (rx-to-string
+ (list 'seq
+ 'space
+ (list 'one-or-more 'digit)
+ ?. 'space)
+ t)
+ str index))
+ (setq result
+ (cons
+ (substring-no-properties
+ str old-index index)
+ result))
+ (setq old-index index)
+ (setq index (+ index 4)))
+ ((setq index len)
+ (setq result
+ (cons
+ (substring-no-properties str old-index)
+ result)))))
+ (reverse result))))
+
+;;;;; Insert the parse result into buffer
+(defun dudict-present-agarathi (timeline)
+ "Insert the TIMELINE structure into the current buffer."
+ (cond
+ ((agarathi-timeline-p timeline))
+ ((error "Requires a timeline, but found %S" timeline)))
+ (let* ((panels (agarathi-timeline-panels timeline))
+ panel
+ descriptions description
+ definitions examples)
+ (while (consp panels)
+ (setq panel (car panels))
+ (setq panels (cdr panels))
+ (insert "** " (agarathi-panel-title panel))
+ (newline)
+ (setq descriptions (agarathi-panel-descriptions panel))
+ (while (consp descriptions)
+ (setq description (car descriptions))
+ (setq descriptions (cdr descriptions))
+ (insert
+ "*** "
+ (dudict-trim (agarathi-description-title description)))
+ (newline)
+ (setq definitions
+ (agarathi-description-definitions description))
+ (mapc
+ (lambda (def) (insert "- " (dudict-trim def)) (newline))
+ definitions)
+ (newline)
+ (setq examples
+ (agarathi-description-examples description))
+ (cond
+ (examples
+ (insert "**** Examples")
+ (newline)
+ (mapc
+ (lambda (ex) (insert "+ " (dudict-trim ex)) (newline))
+ examples)))))))
+
+(defun dudict-trim (str)
+ "Replace any block of spaces from STR by one space."
+ (declare (side-effect-free t) (pure t))
+ (replace-regexp-in-string
+ (rx-to-string
+ (list 'seq (list 'one-or-more 'space))
+ t)
+ (string 32)
+ str))
+
+;;;; Tamilverb dictionary
+
+;;;;; Search Struct
+
+(defvar dudict-search-tamilverb nil
+ "The search struct that is used to search the Tamil Verb \
+dictionary.")
+
+(setq dudict-search-tamilverb
+ (make-dudict-search
+ :name "TamilVerb"
+ :pre nil
+ :search (function
+ (lambda (word)
+ (concat "https://tamilverb.com/?q=" word)))
+ :parse #'dudict-parse-tamilverb
+ :present #'dudict-present-tamilverb))
+
+;;;;; Short-cut
+
+(defun dudict-search-tamilverb (word)
+ "A short-cut that passes `dudict-search-tamilverb' and WORD to
+`dudict-search'."
+ (interactive
+ (read-string "Enter search term: " nil 'dudict-tamil-history))
+ (dudict-search
+ dudict-search-tamilverb word #'dudict-tamil-buffer-name))
+
+;;;;; Structures
+
+;;;;;; All entries
+
+(cl-defstruct tamilverb-entries
+ "A list of entries."
+ (ls
+ nil
+ :documentation "The list of contained entries.
+Each entry has the type `tamilverb-entry'."
+ :type list))
+
+(defun tamilverb-check-valid-entries (entries)
+ "Check that an object is a valid entries structure."
+ (declare (side-effect-free t) (pure t))
+ (and
+ (tamilverb-entries-p entries)
+ (let ((ls (tamilverb-entries-ls entries))
+ (result t)
+ temp)
+ (and
+ (listp ls)
+ (progn
+ (while (consp ls)
+ (setq temp (car-safe ls))
+ (setq ls (cdr-safe ls))
+ (cond
+ ((tamilverb-check-valid-entry temp))
+ (t
+ (setq result nil)
+ (setq ls nil))))
+ result)))))
+
+;;;;;; One entry
+
+(cl-defstruct tamilverb-entry
+ "An entry of the definition.
+It contains the headword, which is a short summary of the definition.
+
+Then it contains the verb class, and some \"sub-words\", which
+are alternate (spoken) spellings.
+
+Then follow the detailed definitions.
+
+Finally it contains one usage example and optionally some
+synonyms."
+ (head
+ ""
+ :documentation "A short summary."
+ :type string)
+ (class
+ 0
+ :documentation "The verb class of the verb."
+ :type integer)
+ (transitivity
+ nil
+ :documentation "The transitivity of the verb."
+ :type bool)
+ (def
+ ""
+ :documentation "Detailed definition."
+ :type string)
+ (sub
+ ""
+ :documentation "Spellings"
+ :type string)
+ (ex
+ ""
+ :documentation "A usage example"
+ :type string)
+ (synonyms
+ nil
+ :documentation "Some synonyms"
+ :type list))
+
+(defun tamilverb-check-valid-entry (entry)
+ "Check that an object is a valid entry structure."
+ (declare (side-effect-free t) (pure t))
+ (and
+ (tamilverb-entry-p entry)
+ (let ((head (tamilverb-entry-head entry))
+ (class (tamilverb-entry-class entry))
+ (trans (tamilverb-entry-transitivity entry))
+ (def (tamilverb-entry-def entry))
+ (sub (tamilverb-entry-sub entry))
+ (ex (tamilverb-entry-ex entry))
+ (synonyms (tamilverb-entry-synonyms entry)))
+ (and
+ (stringp head)
+ (integerp class)
+ (or (null trans) (equal trans t))
+ (stringp def)
+ (stringp sub)
+ (stringp ex)
+ (listp synonyms)
+ (eval (cons #'and (mapcar #'stringp synonyms)))))))
+
+;;;;; main function
+
+(defun dudict-parse-tamilverb ()
+ "Parse the search result from the Tamil Verb website.
+The current buffer is assumed to contain the search results already."
+ ;; ;; First re-insert the results, as the Tamil Verb website escapes
+ ;; ;; the characters for some reason.
+ ;; (let ((dom (libxml-parse-html-region (point-min) (point-max))))
+ ;; (delete-region (point-min) (point-max))
+ ;; (dom-print dom))
+ (let* ((dom (libxml-parse-html-region (point-min) (point-max)))
+ (entries (dom-by-tag dom 'entry))
+ (result (make-tamilverb-entries)))
+ (cond
+ ((null entries))
+ ((setq
+ result
+ (make-tamilverb-entries
+ :ls (mapcar #'dudict-parse-tamilverb-entry entries)))))
+ result))
+
+;;;;; Parse one entry
+
+(defun dudict-parse-tamilverb-entry (entry)
+ "Convert ENTRY to a `tamilverb-entry' struct."
+ (declare (side-effect-free t) (pure t))
+ (let* ((head (dom-text (car (dom-by-tag entry 'headword))))
+ (class (dom-text (car (dom-by-tag entry 'verbclass))))
+ (trans (cond
+ ((string-match-p "intr" class) nil)
+ (t)))
+ (class (string-to-number
+ (save-match-data
+ (string-match (rx-to-string (list 'seq 'digit) t)
+ class)
+ (match-string 0 class))))
+ (def (dom-text (car (dom-by-tag entry 'definition))))
+ (sub (dom-texts (car (dom-by-tag entry 'subword))))
+ (ex (dom-texts
+ (car
+ (dom-by-class
+ (car (dom-by-tag entry 'usage))
+ (rx-to-string (list 'seq 'bos "detail" 'eos) t)))))
+ (synonyms (dom-texts
+ (car
+ (dom-by-class
+ (car (dom-by-tag entry 'synonyms))
+ (rx-to-string
+ (list 'seq 'bos "detail" 'eos) t))))))
+ (make-tamilverb-entry
+ :head head
+ :class class
+ :transitivity trans
+ :def def
+ :sub sub
+ :ex ex
+ :synonyms synonyms)))
+
+;;;;; De-escaping function
+
+(defun dudict-de-escape (str)
+ "If STR contains slices of the form \"&#xNNN;\", where NNN are
+digits, replace those slices by UNICODE characters with the
+corresponding UNICODE code point.
+
+Tamil Verb website escapes the Tamil Script in this way, maybe to
+suit some legacy devices?"
+ (declare (side-effect-free t) (pure t))
+ (let ((s str)
+ (regex (rx-to-string
+ (list
+ 'seq "&#x"
+ (list 'group (list 'one-or-more 'hex))
+ ?\;)
+ t)))
+ (save-match-data
+ (while (string-match regex s)
+ (setq
+ s
+ (replace-match
+ (make-string 1 (string-to-number (match-string 1 s) 16))
+ t t s))))
+ s))
+
+;;;;; Insert the parse result
+
+(defun dudict-present-tamilverb (entries)
+ "Insert the entries into the current buffer."
+ (cond
+ ((tamilverb-entries-p entries))
+ ((error "Requires a tamilverb-entries, but found %S" entries)))
+ (let* ((entries (tamilverb-entries-ls entries))
+ entry head class trans def ex syn)
+ (cond
+ ((null entries)
+ (insert "Not found")
+ (newline)))
+ (while (consp entries)
+ (setq entry (car entries))
+ (setq entries (cdr entries))
+ (insert "** " (tamilverb-entry-head entry))
+ (newline)
+ (insert
+ (format "Class: %d" (tamilverb-entry-class entry)))
+ (newline)
+ (insert
+ (format "Transitivity: %S"
+ (tamilverb-entry-transitivity entry)))
+ (newline)
+ (insert
+ (dudict-trim (dudict-de-escape (tamilverb-entry-sub entry))))
+ (newline 2)
+ (insert (tamilverb-entry-def entry))
+ (newline)
+ (insert "*** Example Usage")
+ (newline)
+ (insert
+ (dudict-trim (dudict-de-escape (tamilverb-entry-ex entry))))
+ (newline)
+ (insert "*** Synonyms")
+ (newline)
+ (insert
+ (dudict-trim
+ (dudict-de-escape (tamilverb-entry-synonyms entry))))
+ (newline))))
+
+;;;; Wiktionary search
+
+;; TODO: Take the search from https://en.wiktionary.org/ into the
+;; considerations, as sometimes this is more reliable and includes
+;; more modern usages.
+
+(provide 'durand-dict)
+;;; durand-dict.el ends here
diff --git a/elisp.el b/elisp.el
index 415ce59..b2da685 100644
--- a/elisp.el
+++ b/elisp.el
@@ -214,17 +214,21 @@ PARSE-START is the starting position of the parse."
(any-quoted-p nil)
(point nil))
(or
- (when-let (char (char-before last))
- (or (char-equal char ?')
- (char-equal char ?`)))
+ (let ((char (char-before point)))
+ (cond
+ (char
+ (or (char-equal char ?')
+ (char-equal char ?`)))))
(progn
(while (and rest (not any-quoted-p))
(setq point (pop rest))
(setq any-quoted-p
(or
- (when-let (char (char-before point))
- (or (char-equal char ?')
- (char-equal char ?`)))
+ (let ((char (char-before point)))
+ (cond
+ (char
+ (or (char-equal char ?')
+ (char-equal char ?`)))))
(save-excursion
(goto-char (1+ point))
(looking-at-p
diff --git a/eshell-conf.el b/eshell-conf.el
index c8c2605..216b003 100644
--- a/eshell-conf.el
+++ b/eshell-conf.el
@@ -95,6 +95,7 @@
(remove-hook 'eshell-post-command-hook #'eshell-current-command-stop t)
(remove-hook 'eshell-mode-hook #'eshell-current-command-time-track))
+;; This is for GNU Emacs 30.2.50 of 2026-05-05
;;;###autoload
(defun durand-eshell-emit-prompt ()
"Emit a prompt if eshell is being used interactively.
@@ -105,29 +106,75 @@ Add a time information at the beginning. -- Modified by Durand."
(if (not eshell-prompt-function)
(set-marker eshell-last-output-end (point))
(let ((prompt (funcall eshell-prompt-function)))
- (and eshell-highlight-prompt
- (add-text-properties 0 (length prompt)
- '(read-only t
- font-lock-face eshell-prompt
- front-sticky (font-lock-face read-only)
- rear-nonsticky (font-lock-face read-only))
- prompt))
- (eshell-interactive-print
- (mapconcat #'identity
- (delq
- nil
- (list
- (cond ((> (length eshell-prompt-time-string) 0)
- (propertize eshell-prompt-time-string
- 'font-lock-face 'modus-themes-heading-1
- 'read-only t
- 'front-sticky '(font-lock-face read-only)
- 'rear-nonsticky '(font-lock-face read-only))) )
- prompt))
- " "))
+ (add-text-properties
+ 0 (length prompt)
+ (if eshell-highlight-prompt
+ '( read-only t
+ field prompt
+ font-lock-face eshell-prompt
+ front-sticky (read-only field font-lock-face)
+ rear-nonsticky (read-only field font-lock-face))
+ '( field prompt
+ front-sticky (field)
+ rear-nonsticky (field)))
+ prompt)
+ (eshell-interactive-filter
+ nil
+ (cond
+ ((not (string-empty-p eshell-prompt-time-string))
+ (concat
+ (cond
+ (eshell-highlight-prompt
+ (propertize
+ (concat eshell-prompt-time-string (string 32))
+ 'read-only t
+ 'field 'prompt
+ 'font-lock-face 'modus-themes-heading-1
+ 'front-sticky '(read-only field font-lock-face)
+ 'rear-nonsticky '(read-only field font-lock-face)))
+ ((propertize
+ (concat eshell-prompt-time-string (string 32))
+ 'field 'prompt
+ 'front-sticky '(field)
+ 'rear-nonsticky '(field))))
+ prompt))
+ (prompt)))
(setq eshell-prompt-time-string "")))
(run-hooks 'eshell-after-prompt-hook))
+;; For Emacs 29
+;; (defun durand-eshell-emit-prompt ()
+;; "Emit a prompt if eshell is being used interactively.
+;; Modified by Durand."
+;; (when (boundp 'ansi-color-context-region)
+;; (setq ansi-color-context-region nil))
+;; (run-hooks 'eshell-before-prompt-hook)
+;; (if (not eshell-prompt-function)
+;; (set-marker eshell-last-output-end (point))
+;; (let ((prompt (funcall eshell-prompt-function)))
+;; (and eshell-highlight-prompt
+;; (add-text-properties 0 (length prompt)
+;; '(read-only t
+;; font-lock-face eshell-prompt
+;; front-sticky (font-lock-face read-only)
+;; rear-nonsticky (font-lock-face read-only))
+;; prompt))
+;; (setq
+;; prompt
+;; (cond
+;; ((not (string-empty-p eshell-prompt-time-string))
+;; (concat
+;; (propertize
+;; (concat eshell-prompt-time-string (string 32))
+;; 'read-only t
+;; 'font-lock-face 'modus-themes-heading-1
+;; 'front-sticky '(font-lock-face read-only)
+;; 'rear-nonsticky '(font-lock-face read-only))
+;; prompt))
+;; (prompt)))
+;; (eshell-interactive-print prompt)))
+;; (run-hooks 'eshell-after-prompt-hook))
+
(advice-add #'eshell-emit-prompt :override #'durand-eshell-emit-prompt)
;;; Eshell sets the keymap in the major mode function
@@ -179,7 +226,10 @@ Do NUM times `eshell-previous-prompt' before deleting."
(interactive
(list (cond ((null current-prefix-arg) 0)
((prefix-numeric-value current-prefix-arg)))))
- (let ((inhibit-read-only t))
+ ;; We have to set this to obtain the true line-beginning position,
+ ;; instead of the prompt start position.
+ (let ((inhibit-field-text-motion t)
+ (inhibit-read-only t))
(delete-region
(point-min)
(save-excursion
diff --git a/gnus-conf.el b/gnus-conf.el
index 3c8f7fe..fa73360 100644
--- a/gnus-conf.el
+++ b/gnus-conf.el
@@ -153,7 +153,7 @@
(require 'notmuch)
-(add-hook 'durand-mail-update-hook #'notmuch-poll)
+;; (add-hook 'durand-mail-update-hook #'notmuch-poll)
(defun durand-gnus-expire ()
"Expire all articles."
diff --git a/ibuffer.el b/ibuffer.el
index 2fdd3dc..f09aa7b 100644
--- a/ibuffer.el
+++ b/ibuffer.el
@@ -99,11 +99,14 @@ automatically.")
;;;###autoload
(defun durand-reset-clearlist (&optional arg)
"Remove killed buffers from `durand-clear-passlist'.
-If ARG is non-nil and not '(16), reset `durand-clear-passlist' to
-`durand-default-clear-passlist'.
+If ARG is non-nil, not '(64), and not '(16), reset
+`durand-clear-passlist' to `durand-default-clear-passlist'.
If ARG is '(16), show the current contents of
-`durand-clear-passlist'."
+`durand-clear-passlist'.
+
+If ARG is '(64), for each buffer in `durand-clear-passlist', show
+whether it is a live buffer and its name as a list of cons cells."
(interactive "P")
(cond
((equal arg (cons 16 nil))
@@ -115,7 +118,33 @@ If ARG is '(16), show the current contents of
(e)))
durand-clear-passlist
", ")))
-
+ ((equal arg (cons 64 nil))
+ (let ((result (string)))
+ (mapc
+ (lambda (b)
+ (cond
+ ((bufferp b)
+ (setq
+ result
+ (format
+ "%s\n%s: %s"
+ result
+ (buffer-name b)
+ (cond ((buffer-live-p b) "live") ("not live")))))
+ ((stringp b)
+ (setq
+ result
+ (format
+ "%s\n%s: %s"
+ result b
+ (cond ((buffer-live-p (get-buffer b)) "live")
+ ("not live")))))
+ ((setq
+ result
+ (format "%s\n%S: %s" result b "unknown")))))
+ durand-clear-passlist)
+ (with-temp-buffer-window "*durand clear list*" nil nil
+ (princ result))))
((setq
durand-clear-passlist
(cond
@@ -420,14 +449,34 @@ value of `default-directory' in that buffer."
(:description "directory name"
:reader (read-from-minibuffer
"Filter by directory name (regex): "))
- (ibuffer-aif (with-current-buffer buf (ibuffer-buffer-file-name))
- (let ((dirname (expand-file-name (file-name-directory it))))
- (cond (dirname (string-match-p qualifier dirname))))
- (when (buffer-local-value default-directory buf)
- (string-match-p
- qualifier
- (expand-file-name
- (buffer-local-value buf default-directory))))))
+ (let ((buf-name (with-current-buffer buf (ibuffer-buffer-file-name))))
+ (cond (buf-name
+ (let ((dirname
+ (expand-file-name (file-name-directory buf-name))))
+ (cond (dirname (string-match-p qualifier dirname)))))
+ ((buffer-local-value default-directory buf)
+ (string-match-p
+ qualifier
+ (expand-file-name
+ (buffer-local-value buf default-directory)))))))
+
+;;; For ITHKUIL
+(define-ibuffer-filter durand-ithkuil
+ "Matches ITHKUIL buffers.
+These are EWW buffers whose URL starts with www.ithkuil.net,
+along with the buffers of files in a dedicated Ithkuil directory."
+ (:description "ITHKUIL" :reader (read-string "no effect"))
+ (with-current-buffer buf
+ (let ((buf-name default-directory))
+ (ignore-errors
+ (cond
+ ((derived-mode-p 'eww-mode)
+ (string-prefix-p
+ "https://www.ithkuil.net" (plist-get eww-data :url)))
+ (buf-name
+ (string-prefix-p
+ "/Users/durand/Desktop/Centre/Ithkuil/"
+ (expand-file-name buf-name))))))))
;;;###autoload
(defun durand-bongo-set-filter ()
@@ -439,10 +488,12 @@ value of `default-directory' in that buffer."
(mode . rustic-mode)
(mode . rust-mode))))
(cons "TeX" '((derived-mode . tex-mode)))
+ (cons "ITHKUIL" '((durand-ithkuil)))
(cons "C" '((mode . c-mode)))
(cons "ELisp" '((mode . emacs-lisp-mode)))
(cons "EWW" '((mode . eww-mode)))
(cons "PDF" '((mode . pdf-view-mode)))
+ (cons "DICT" '((mode . dudict-mode)))
(cons "Eshell" '((mode . eshell-mode)))
(cons "Org" '((mode . org-mode)))
(cons "Roman" '((mode . novel-read-mode)))))
diff --git a/init.el b/init.el
index 293abc7..3e4b3d6 100644
--- a/init.el
+++ b/init.el
@@ -240,11 +240,11 @@ no effect."
;;; gnus
-(load-after-function gnus "gnus-conf.el"
- "Fake function to load gnus." nil (gnus))
+(load-after-function gnus-unplugged "gnus-conf.el"
+ "Fake function to load gnus." nil (gnus-unplugged))
-(define-key global-map (vector 3 ?g) #'gnus)
-(define-key global-map (vector ?\H-g) #'gnus)
+(define-key global-map (vector 3 ?g) #'gnus-unplugged)
+(define-key global-map (vector ?\H-g) #'gnus-unplugged)
;;; Completion framework configurations
@@ -312,6 +312,8 @@ no effect."
;;; Input method configuration
+(define-key global-map (vector 3 ?i) #'toggle-input-method)
+
(load-after-function toggle-input-method "input-conf.el"
"Load my configurations of input methods." nil)
diff --git a/input-conf.el b/input-conf.el
index 986286a..10cc6da 100644
--- a/input-conf.el
+++ b/input-conf.el
@@ -25,6 +25,9 @@
;;; Code:
+;; core package
+(require 'quail)
+
;;; Chinese-zozy
;; This does not work. I shall find another way to do this.
@@ -35,7 +38,122 @@
(remove-hook 'quail-activate-hook #'durand-zozy-remap-keys)
+;;; Default input method
+
(setq-default default-input-method "devanagari-kyoto-harvard")
+;;; Short-cut headlong selection of input methods.
+
+(defvar durand-input-method-list nil
+ "The list of input methods that I oft use.")
+
+(setq durand-input-method-list
+ (list "devanagari-kyoto-harvard"
+ "tamil99"
+ "chinese-zozy"
+ "ithkuil"
+ "hebrew-full"))
+
+(defun durand-toggle-input ()
+ "Toggle input method with my customizations."
+ (interactive)
+ (cond
+ ((null current-input-method)
+ (let ((input-method
+ (minibuffer-with-setup-hook
+ #'durand-headlong-minibuffer-setup-hook
+ (completing-read
+ "Input method: " durand-input-method-list
+ nil t nil nil "devanagari-kyoto-harvard"))))
+ (activate-input-method input-method)))
+ ((deactivate-input-method))))
+
+(define-key global-map (vector ?\C-\\) #'durand-toggle-input)
+(define-key global-map (vector 3 ?i) #'durand-toggle-input)
+
+;;; Custom french keyboard layout
+
+;; I am used to the french keyboard, so it would be most convenient if
+;; the quail packages can automatically translate the keys according
+;; to this layout.
+
+(cond
+ ((assoc "durand-fr" quail-keyboard-layout-alist #'string=)
+ (setcdr
+ (assoc "durand-fr" quail-keyboard-layout-alist #'string=)
+ "\
+ \
+ &1é2\"3'4(5§6è7!8ç9à0)°-_<> \
+ aAzZeErRtTyYuUiIoOpP^¨$* \
+ qQsSdDfFgGhHjJkKlLmMù%`£ \
+ wWxXcCvVbBnN,?;.:/=+ \
+ "))
+ (t
+ (setq
+ quail-keyboard-layout-alist
+ (cons
+ (cons
+ "durand-fr"
+ "\
+ \
+ &1é2\"3'4(5§6è7!8ç9à0)°-_<> \
+ aAzZeErRtTyYuUiIoOpP^¨$* \
+ qQsSdDfFgGhHjJkKlLmMù%`£ \
+ wWxXcCvVbBnN,?;.:/=+ \
+ ")
+ quail-keyboard-layout-alist))))
+
+(quail-set-keyboard-layout "durand-fr")
+
+;;; Convert a string to its equivalent under an input-method
+
+(defun durand-convert-string-by-input-method (str method)
+ "Convert the string STR to its equivalent under the input-method \
+METHOD.
+
+Basically, this functions activates the input method METHOD and
+then enters the string STR, and returns the inputted string."
+ (let ((prev-input-method current-input-method)
+ (temp-buffer (generate-new-buffer " *temp*" t))
+ result)
+ (switch-to-buffer temp-buffer)
+ (activate-input-method method)
+ (execute-kbd-macro (vconcat str))
+ (activate-input-method prev-input-method)
+ (setq
+ result
+ (buffer-substring-no-properties (point-min) (point-max)))
+ (kill-buffer temp-buffer)
+ result))
+
+(defun durand-convert-region-by-input-method (start end method)
+ "Convert the string in the region between START and END by the
+input-method METHOD.
+
+See the function `durand-convert-string-by-input-method' for
+more."
+ (interactive
+ (append
+ (cond ((region-active-p)
+ (list (region-beginning) (region-end)))
+ ((list (point) (point))))
+ (list (read-input-method-name "By which input method: "))))
+ (let* ((str (buffer-substring-no-properties start end))
+ (converted
+ (durand-convert-string-by-input-method str method)))
+ (delete-region start end)
+ (goto-char start)
+ (insert converted)))
+
+;;; Chinese punctuation input
+
+(defun durand-transient-punct ()
+ "Switch the input method to chinese punctuation transiently."
+ (interactive)
+ (let ((default-transient-input-method "chinese-punct-b5"))
+ (activate-transient-input-method)))
+
+(define-key global-map (vector ?\C-,) #'durand-transient-punct)
+
(provide 'input-conf)
;;; input-conf.el ends here
diff --git a/ithkuil.el b/ithkuil.el
new file mode 100644
index 0000000..e409a91
--- /dev/null
+++ b/ithkuil.el
@@ -0,0 +1,67 @@
+;;; ithkuil.el --- Input-method for The New Ithkuil Language -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2026 Jean Sévère Durand
+
+;; Author: Jean Sévère Durand <durand@jsdurand.xyz>
+;; Keywords: emulations, wp, abbrev
+
+;; This program 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.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; My input-method for TNIL.
+
+;;; Code:
+
+(quail-define-package
+ "ithkuil" "TNIL" "TNIL" t "TODO")
+
+(quail-defrule ":a" ?ä)
+(quail-defrule ":e" ?ë)
+(quail-defrule ":o" ?ö)
+(quail-defrule ":u" ?ü)
+
+(quail-defrule ";a" ?â)
+(quail-defrule ";e" ?ê)
+(quail-defrule ";o" ?ô)
+(quail-defrule ";u" ?û)
+
+(quail-defrule "/a" ?á)
+(quail-defrule "/e" ?é)
+(quail-defrule "/i" ?í)
+(quail-defrule "/o" ?ó)
+(quail-defrule "/u" ?ú)
+
+(quail-defrule "\\i" ?ì)
+(quail-defrule "\\u" ?ù)
+
+(quail-defrule ",'" ?\’)
+(quail-defrule ",t" ?ţ)
+(quail-defrule ",d" ?ḑ)
+(quail-defrule ",c" ?ç)
+(quail-defrule ",l" ?ļ)
+
+(quail-defrule ">d" (vector "d͕"))
+(quail-defrule ">l" (vector "l͕"))
+
+(quail-defrule ";s" ?š)
+(quail-defrule ";z" ?ž)
+(quail-defrule ";c" ?č)
+(quail-defrule ";n" ?ň)
+(quail-defrule ";r" ?ř)
+
+(quail-defrule ".z" ?ẓ)
+
+(provide 'ithkuil)
+;;; ithkuil.el ends here
diff --git a/mail.el b/mail.el
index 0e2ecdb..61414bc 100644
--- a/mail.el
+++ b/mail.el
@@ -268,6 +268,14 @@ mails."
(defvar durand-mail-update-hook nil
"The hook run after the process that updates mails is finished.")
+;; Update notmuch index
+
+(defun notmuch-new ()
+ "Run notmuch new."
+ (call-process "notmuch" nil nil nil "new"))
+
+(add-hook 'durand-mail-update-hook #'notmuch-new)
+
(defun durand-mail-update-sentinel (process status)
"Handle STATUS changes of the PROCESS for updating mails.
This funciton runs the hook `durand-mail-update-hook' after the
@@ -283,7 +291,8 @@ PROCESS is finished."
(defvar durand-mail-update-command
(list "mbsync"
"mymail-inbox" "mymail-sent"
- "gmail-inbox" "gmail-sent")
+ "gmail-inbox" "gmail-sent"
+ "myaccount-inbox")
"Command to update mails.")
(defvar durand-mail-update-buffer "*mail*"
@@ -330,8 +339,11 @@ If FOREGROUND-P is `0', do not fetch mails, but just run
durand-mail-update-buffer)))
(buffer-disable-undo buffer)
buffer)))))
- ((not (or process-found internet-on))
- (message "MAIL: There is no internet connection.")))))
+ ;; I do not want to be notified of this when it runs in the
+ ;; background.
+ ((and foreground-p (not (or process-found internet-on)))
+ (message "MAIL: There is no internet connection.")
+ ))))
(defvar durand-mail-update-timer nil
"A timer to automatically update mail in the background.")
diff --git a/modeline.el b/modeline.el
index ee2c0fd..3af386b 100644
--- a/modeline.el
+++ b/modeline.el
@@ -24,7 +24,7 @@
;;; Code:
-(defvar modeline-right-offset 6
+(defvar modeline-right-offset 15
"An offset to adjust the modeline alignment.")
;;;###autoload
@@ -34,15 +34,17 @@
(right (string-trim-right (modeline-format-right)))
(left-len (string-pixel-width left))
(right-len (string-pixel-width right))
+ (el-doc-len (string-pixel-width eldoc-mode-line-string))
+ (middle-len (max (- (window-pixel-width)
+ left-len right-len el-doc-len
+ (- modeline-right-offset))
+ 0))
(middle (propertize
(string 32)
'display
(list
'space
- :width
- (list
- (- (window-pixel-width) left-len right-len
- (- modeline-right-offset)))))))
+ :width (list middle-len)))))
(concat left middle right)))
(setq-default mode-line-format '("%e" (:eval (modeline-format-main))))
@@ -54,15 +56,18 @@
(right (string-trim-right (modeline-dashboard-format-right)))
(left-len (string-pixel-width left))
(right-len (string-pixel-width right))
+ (el-doc-len (string-pixel-width eldoc-mode-line-string))
+ (middle-len (max (- (window-pixel-width)
+ left-len right-len el-doc-len
+ (- modeline-right-offset))
+ 0))
(middle (propertize
(string 32)
'display
(list
'space
:width
- (list
- (- (window-pixel-width) left-len right-len
- (- modeline-right-offset)))))))
+ (list middle-len)))))
(concat left middle right)))
;;;###autoload
@@ -90,6 +95,35 @@
(format-mode-line global-mode-string face)))))
;;;###autoload
+(defun modeline-format-gnus ()
+ "The mode line format for GNUS."
+ (let* ((left (modeline-gnus-format-left))
+ (right (string-trim-right (modeline-format-right)))
+ (left-len (string-pixel-width left))
+ (right-len (string-pixel-width right))
+ (middle (propertize
+ (string 32)
+ 'display
+ (list
+ 'space
+ :width
+ (list
+ (- (window-pixel-width) left-len right-len
+ (- modeline-right-offset)))))))
+ (concat left middle right)))
+
+(defun modeline-gnus-format-left ()
+ "The left part of the mode line for GNUS."
+ (declare (side-effect-free t) (pure t))
+ (concat
+ (modeline-spc)
+ (modeline-format-buffer-name)
+ (modeline-spc)
+ (modeline-format-keycast)
+ (modeline-spc)
+ (modeline-format-minor-modes)))
+
+;;;###autoload
(defun modeline-format-left ()
"The left mode line format."
(concat
@@ -578,7 +612,7 @@ string in the mode line.")
('mode-line-inactive))))
(concat
(modeline-propertize
- (format-mode-line '("%m") face)
+ (format-mode-line (list mode-name) face)
nil
"Major mode\nmouse-1: Display major mode menu\nmouse-2:\
Show help for major mode\nmouse-3: Toggle minor modes"
diff --git a/org-conf.el b/org-conf.el
index 6f00728..95b4150 100644
--- a/org-conf.el
+++ b/org-conf.el
@@ -277,6 +277,10 @@ in Lisp code use `org-set-tags' instead."
:empty-lines 1
:kill-buffer t
:immediate-finish t)
+ ("e" "Store electric degrees" entry
+ (file+headline "/Users/durand/org/notes.org" "विद्युद्देयकः")
+ "* %? - %<%Y-%m-%d %H:%M:%S %Z>\n"
+ :jump-to-captured t)
("t" "TODO" entry
(file "~/org/aujourdhui.org")
"* TODO %? %^{Date to do:}t\n :PROPERTIES:\n :RECORD_TIME: %U\n :END:\n\n"
@@ -377,7 +381,7 @@ in Lisp code use `org-set-tags' instead."
;;; Accounts
-(load-file "account.el")
+;; (load-file "account.el")
;; ;;;###autoload
;; (defvar durand-org-capture-account-which-list
@@ -1159,6 +1163,67 @@ title."
(advice-add #'org-html-publish-to-html :filter-return #'durand-org-publish-html-advice)
+;;;; Author element in quotes
+
+;; I want to note the author in quotes, and have the authors stand out
+;; a little.
+
+(defun durand-org-quote-export-filter (text backend _info)
+ "Turn ending lines beginning with two dashes into footer elements.
+The parameters TEXT, BACKEND, and INFO are subject to the rules of
+`org-export-filter-quote-block-functions'."
+ (cond
+ ((org-export-derived-backend-p backend 'html)
+ (message "text: %s" text)
+ (replace-regexp-in-string
+ (rx-to-string
+ (list 'seq 'bol "-#- "
+ (list 'group-n 1 (list 'one-or-more 'anychar))
+ "</p>")
+ t)
+ "<footer><cite>\\1</cite></footer>"
+ text))))
+
+(add-to-list 'org-export-filter-quote-block-functions
+ #'durand-org-quote-export-filter)
+
+;;;; Remove spaces between Chinese characters
+
+(defun durand-org-no-chinese-spaces (text backend _info)
+ "Remove extra spaces caused by line breaks between Chinese
+characters.
+
+The parameters TEXT, BACKEND, and INFO are subject to the rules of
+`org-export-filter-quote-block-functions'."
+ (cond
+ ((org-export-derived-backend-p backend 'html)
+ (let ((regex (rx-to-string
+ (list
+ 'seq
+ (list
+ 'or
+ (list 'category 'korean-hangul-two-byte)
+ (list 'category 'chinese)
+ (list 'category 'korean)
+ (list 'category 'japanese)
+ (list 'category 'japanese-katakana)))
+ t)))
+ (setq text (replace-regexp-in-string
+ (format "\\(%s\\) *\n *\\(%s\\)" regex regex)
+ "\\1\\2" text))
+ ;; Handle extra spaces at boundaries between Chinese and
+ ;; non-Chinese.
+ (setq text (replace-regexp-in-string
+ (format "\\(%s\\) *\n" regex)
+ "\\1" text))
+ (setq text (replace-regexp-in-string
+ (format "\n *\\(%s\\)" regex)
+ "\\1" text))))
+ text))
+
+(add-to-list 'org-export-filter-paragraph-functions
+ #'durand-org-no-chinese-spaces)
+
;;;; Atom feed
;;;;; Fixed pre-amble, template, and post-amble.
diff --git a/pdf.el b/pdf.el
index dac65ee..da0d146 100644
--- a/pdf.el
+++ b/pdf.el
@@ -1,4 +1,29 @@
-;;; Dependency
+;;; pdf.el --- PDF configurations -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2026 Jean Sévère Durand
+
+;; Author: Jean Sévère Durand;;; Dependency <durand@jsdurand.xyz>
+;; Keywords: data, convenience
+
+;; This program 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.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Just my configurations for PDF viewing.
+
+;;; Code:
+
(use-package "tablist" 'tablist)
(use-package "pdf-tools/lisp" 'pdf-view)
@@ -95,6 +120,10 @@ Modifed by Durand 2021-07-27 10:42:02.828266."
(define-key pdf-view-mode-map (vector ?\C->) #'image-scroll-right)
(define-key pdf-view-mode-map (vector ?>) #'image-eob)
(define-key pdf-view-mode-map (vector ?<) #'image-bob)
+(define-key pdf-view-mode-map (vector ?J) #'jump-to-register)
(define-key pdf-history-minor-mode-map (vector ?l) nil)
(pdf-tools-install)
+
+(provide 'pdf)
+;;; pdf.el ends here
diff --git a/tex-conf.el b/tex-conf.el
index f1b9029..eb8f0c5 100644
--- a/tex-conf.el
+++ b/tex-conf.el
@@ -297,6 +297,7 @@ where the macro part is without the backslash.")
(cons "o" "circ")
(list "{" "{" "}")
(list "(" "(" ")")
+ (list "[" "[" "]")
(list "<" "langle" "rangle")
(list "b" "lvert" "rvert")))
diff --git a/theme.el b/theme.el
index 1033e46..096342d 100644
--- a/theme.el
+++ b/theme.el
@@ -1,4 +1,4 @@
-;;; theme
+;;; theme -*- lexical-binding: t; -*-
(use-package "protesilaos/modus-themes" 'modus-themes)
diff --git a/view-conf.el b/view-conf.el
index 2726526..f339c27 100644
--- a/view-conf.el
+++ b/view-conf.el
@@ -240,7 +240,9 @@ targets.")
"/Users/durand/Desktop/Centre/Vidéos/"
"/Users/durand/Desktop/Centre/Musique/"
"/Users/durand/Downloads/"))
- (list "messenger" "open" "-a" "Messenger")
+ ;; (list "messenger" "open" "-a" "Messenger")
+ ;; FACEBOOK disables this application now.
+ (list "discord" "open" "-a" "Discord")
(list "temp d'écran" "open" "-b"
"com.apple.systempreferences"
"/System/Library/PreferencePanes/ScreenTime.prefPane")))