diff options
author | JSDurand <mmemmew@gmail.com> | 2021-01-09 14:22:00 +0800 |
---|---|---|
committer | JSDurand <mmemmew@gmail.com> | 2021-01-09 14:22:00 +0800 |
commit | dc206ebe9397d656971ba7fc3a092009ef4e797a (patch) | |
tree | d963873011122fdf0eafeba89afd487115994bc5 | |
parent | a2f7f2bf9077ba8acfc550575b9e21aa9ffe7bae (diff) |
temporary state
-rw-r--r-- | basic.el | 75 | ||||
-rw-r--r-- | bongo.el | 637 | ||||
-rw-r--r-- | center-buffer.el | 38 | ||||
-rw-r--r-- | comb/suffiex-tree.txt | 217 | ||||
-rw-r--r-- | common.el | 73 | ||||
-rw-r--r-- | dashboard.el | 50 | ||||
-rw-r--r-- | desktop | 19 | ||||
-rw-r--r-- | desktop-conf.el | 170 | ||||
-rw-r--r-- | dired-conf.el | 4 | ||||
-rw-r--r-- | elisp.el | 22 | ||||
-rw-r--r-- | gnus-conf.el | 142 | ||||
-rw-r--r-- | ibuffer.el | 56 | ||||
-rw-r--r-- | init.el | 95 | ||||
-rw-r--r-- | mail.el | 108 | ||||
-rw-r--r-- | modeline.el | 129 | ||||
-rw-r--r-- | modes/Concepts.txt | 298 | ||||
-rw-r--r-- | modes/modes.el | 97 | ||||
-rw-r--r-- | org-conf.el | 309 | ||||
-rw-r--r-- | org-pdftools.el | 403 | ||||
-rw-r--r-- | pdf.el | 2 | ||||
-rw-r--r-- | recentf | 32 | ||||
-rw-r--r-- | recentf-conf.el | 16 | ||||
-rw-r--r-- | tab-conf.el | 54 | ||||
-rw-r--r-- | text-conf.el | 89 | ||||
-rw-r--r-- | view-functions.el | 90 |
25 files changed, 3174 insertions, 51 deletions
@@ -1,5 +1,9 @@ ;;; -*- lexical-binding: t; -*- +;;; Important in order to read passwords + +(setq epg-pinentry-mode 'loopback) + ;;; disable some default modes (tool-bar-mode -1) @@ -7,9 +11,21 @@ (scroll-bar-mode -1) (blink-cursor-mode -1) +;;; I use one single space to end a sentence. + +(set 'sentence-end-double-space nil) + +;;; Say y instead of yes + +(fset 'yes-or-no-p 'y-or-n-p) + +;;; Recursive minibuffers is almost indispensable for me. + +(set 'enable-recursive-minibuffers t) + ;;; Use spaces instead of tabs -(set 'indent-tabs-mode nil) +(set-default 'indent-tabs-mode nil) ;;; Don't make noise when saving files @@ -32,9 +48,20 @@ (setq scroll-conservatively 30) -;;; don't make backup files +;;; remember my minibuffer + +(require 'savehist) + +(set 'savehist-file (expand-file-name "savehist" load-file-directory)) +(set 'history-length 1024) +(set 'history-delete-duplicates t) +(set 'savehist-save-minibuffer-history t) + +(savehist-mode) + +;;; a large file threshold -(setq make-backup-files nil) +(set 'large-file-warning-threshold (* 1024 1024 1024)) ;;; don't use a GUI dialog box as that is distracting to me @@ -77,7 +104,47 @@ (setq-default display-line-numbers-type nil) (global-display-line-numbers-mode -1) -;;; package management +;;; display-buffer-alist + +(setq display-buffer-alist + `((,(rx (seq bos "*Help*" eos)) + (display-buffer-in-side-window) + (side . bottom) + (slot . 1) + (window-height . 0.37)) + (,(rx (seq bos "*Messages*" eos)) + (display-buffer-in-side-window) + (side . bottom) + (slot . -1) + (window-height . 0.37)))) + +;;; auto-fill for texts + +(set 'adaptive-fill-mode t) +(add-hook 'text-mode-hook #'auto-fill-mode) + +;;; enable all commands + +(set 'disabled-command-function nil) + +;;; Comments relateed + +(require 'newcomment) + +(set 'comment-empty-lines nil) +(set 'comment-fill-column nil) +(set 'comment-multi-line t) +(set 'comment-style 'multi-line) + +;;; Windows + +(define-key global-map (vector ?\s-o) #'other-window) +(define-key global-map (vector ?\s-&) #'delete-other-windows) +(define-key global-map (vector ?\s-à) #'delete-window) +(define-key global-map (vector ?\s-f) #'find-file) +(define-key global-map (vector ?\s-v) #'durand-focus-completion-or-minibuffer) + +;;; Package management ;;;###autoload (defvar package-dir "/Users/durand/elisp_packages/" diff --git a/bongo.el b/bongo.el new file mode 100644 index 0000000..f5ccd8c --- /dev/null +++ b/bongo.el @@ -0,0 +1,637 @@ +;;; -*- lexical-binding: t; -*- + +(use-package "bongo" 'bongo + + (require 'json) + (setq volume-electric-mode nil) + (setq bongo-default-directory (expand-file-name "~/Desktop/Centre/Musique")) + (setq bongo-prefer-library-buffers nil) + (setq bongo-insert-whole-directory-trees t) + (setq bongo-logo nil) + (setq bongo-action-track-icon nil) + (setq bongo-display-track-icons nil) + (setq bongo-display-track-lengths nil) + (setq bongo-display-header-icons nil) + (setq bongo-display-playback-mode-indicator t) + (setq bongo-display-inline-playback-progress nil) + (setq bongo-mark-played-tracks nil) + (setq bongo-header-line-mode nil) + (setq bongo-header-line-function nil) + (setq bongo-mode-line-indicator-mode nil) + (setq bongo-enabled-backends '(mpv)) + (setq bongo-seek-electric-mode nil) + (setf bongo-custom-backend-matchers + '((mpv local-file "webm" "m4a"))) + (setq-default bongo-next-action 'durand-bongo-play-next-or-first) + +;;;###autoload + (defvar durand-bongo-music-dir nil + "Directories to store my songs. +This is used since my music directories used to contain symbolic links.") + + (setq durand-bongo-music-dir + (cons bongo-default-directory + (delq + nil + (mapcar + (lambda (file) + (cond + ((let ((attr (car (file-attributes file)))) + (and (stringp attr) + (file-directory-p attr))) + file))) + (directory-files-recursively + bongo-default-directory + ".*" t nil t))) + ;; (cl-loop for file in (directory-files-recursively + ;; bongo-default-directory + ;; ".*" t nil t) + ;; for attr = (car (file-attributes file)) + ;; if (and (stringp attr) + ;; (file-directory-p attr)) + ;; collect attr) + )) + + (define-key bongo-playlist-mode-map [?n] #'bongo-next-object-line) + (define-key bongo-playlist-mode-map [?p] #'bongo-previous-object-line) + (define-key bongo-playlist-mode-map [?j] #'durand-bongo-save-playlist) + (define-key bongo-playlist-mode-map [tab] #'bongo-show) + (define-key bongo-playlist-mode-map [?\C-c ?n] #'durand-bongo-play-next-or-first) + (define-key bongo-playlist-mode-map [?\C-c ?p] #'durand-bongo-play-previous-or-last) + (define-key bongo-dired-library-mode-map [?\C-j] #'durand-bongo-dired-ivy-find-to-add) + (define-key bongo-dired-library-mode-map [?\C-c ?n] #'durand-bongo-play-next-or-first) + (define-key bongo-dired-library-mode-map [?\C-c ?p] #'durand-bongo-play-previous-or-last) + (define-key bongo-playlist-mode-map [?\C-d] #'prot/bongo-clear-playlist-and-stop) + (define-key bongo-playlist-mode-map [?I] #'durand-bongo-insert-delete-playlist) + (define-key bongo-dired-library-mode-map [C-return] #'prot/bongo-library-insert-and-play-random) + + (add-hook 'dired-mode-hook #'durand-bongo-dired-library) + + ;; (map! :map durand-view-map + ;; [?m] 'bongo + ;; :map bongo-dired-library-mode-map + ;; [?\C-j] 'durand-bongo-dired-ivy-find-to-add + ;; [?\C-c ?n] 'durand-bongo-play-next-or-first + ;; [?\C-c ?p] 'durand-bongo-play-previous-or-last + ;; :map bongo-playlist-mode-map + ;; [?n] 'bongo-next-object-line + ;; [?p] 'bongo-previous-object-line + ;; [?j] 'durand-bongo-save-playlist + ;; "TAB" #'bongo-show + ;; [?\C-c ?n] 'durand-bongo-play-next-or-first + ;; [?\C-c ?p] 'durand-bongo-play-previous-or-last) + + ;; seek mode map additions + + (define-key bongo-seek-mode-map [?t] 'bongo-seek-to) + + ;;; functions + +;;;###autoload + (defun contrib/bongo-add-dired-files () + "Add marked files inside of a Dired buffer to the Bongo library." + (interactive) + (require 'dired) + (let (file-point file files) + (dired-map-over-marks + (setq file-point (dired-move-to-filename) + file (dired-get-filename) + files (append files (list file))) + nil t) + (ignore file-point) + (with-current-buffer (bongo-playlist-buffer) + (let ((beg (point))) + (mapc 'bongo-insert-file files) + (bongo-maybe-join-inserted-tracks beg (point)))))) + +;;;###autoload + (defun durand-bongo-dired-library () + "Set `bongo-dired-library-mode' when accessing bongo-default-directory. +This is meant to be hooked to `dired-mode'. + +Upon activation, the directory and all its sub-directories become +a valid library buffer for Bongo, from where we can, among +others, add tracks to playlists. + +The added benefit is that Dired will continue to behave as +normal, making this a superior alternative to a purpose-specific +library buffer. + +Adapted from Protesilaos' dotemacs." + (cond + ((let ((temp durand-bongo-music-dir) dir found) + (while (and (consp temp) (not found)) + (setq dir (car temp) + temp (cdr temp)) + (cond + ((file-in-directory-p default-directory dir) + (setq found t)))) + found) + (set (make-local-variable 'bongo-dired-library-mode) 't)))) + +;;;###autoload + (defun prot/bongo-clear-playlist-and-stop () + "Stop playback and clear the entire `bongo' playlist buffer. +Contrary to the standard `bongo-erase-buffer', this also removes +the currently-playing track. + +Modified by Durand so that this also runs while not in a bongo +buffer." + (interactive) + (with-bongo-playlist-buffer + (bongo-stop) + (bongo-erase-buffer))) + +;;;###autoload + (defun prot/bongo-play-random () + "Play a random track with `bongo' and set random playback." + (interactive) + (when (or (bongo-playlist-buffer-p) + (bongo-library-buffer-p)) + (bongo-play-random) + (setf bongo-next-action 'durand-bongo-play-next-or-first) + ;; (bongo-random-playback-mode 1) + )) + +;;;###autoload + (defun prot/bongo-library-insert-and-play-random () + "Add directory tree or marked items to the `bongo' playlist. +Create the playlist buffer if necessary. +This is meant to work while inside a `dired' buffer that doubles +as a library buffer (see `prot/bongo-dired-library')." + (interactive) + (when (bongo-library-buffer-p) + (unless (bongo-playlist-buffer-p) + (bongo-playlist-buffer)) + (contrib/bongo-add-dired-files) + ;; (prot/bongo-play-random) + )) + +;;;###autoload + (defun durand-bongo-insert-delete-playlist () + "Insert or delete a `bongo' playlist. +The files are stored in a predetermined path inside the Music +directory. Upon insertion, playback starts immediately, in +accordance with `prot/bongo-play-random'. + +Adapted from Protesilaos' dotemacs by Durand." + (interactive) + (let* ((path (file-name-as-directory + (expand-file-name + "playlists" + bongo-default-directory))) + (dotless directory-files-no-dot-files-regexp) + (playlist (directory-files path t dotless))) + (with-bongo-playlist-buffer + (bongo-insert-playlist-contents + (completing-read "Select playlist: " playlist nil t path)) + ;; (ivy-read "Choose a playlist file: " playlist + ;; :require-match t + ;; :caller 'durand-bongo-insert-delete-playlist + ;; :action '(1 + ;; ("i" bongo-insert-playlist-contents "insert playlist") + ;; ("d" (lambda (file) + ;; (delete-file file) + ;; (setf (ivy-state-collection ivy-last) + ;; (directory-files + ;; (file-name-as-directory + ;; (expand-file-name + ;; "playlists" + ;; bongo-default-directory)) + ;; t directory-files-no-dot-files-regexp)) + ;; (ivy--reset-state ivy-last)) + ;; "delete playlist") + ;; ("e" find-file "edit"))) + ;; (prot/bongo-play-random) + ))) + +;;;###autoload + ;; (defun durand-bongo-dired-ivy-find-to-add () + ;; "Use `durand-choose-list' to find files to add to bongo." + ;; (interactive) + ;; ;; (require 'counsel) + ;; (require 'grep) + ;; ;; (counsel-require-program find-program) + ;; ;; (cl-assert + ;; ;; (and (derived-mode-p 'dired-mode) + ;; ;; (file-in-directory-p default-directory bongo-default-directory))) + ;; (let* ((default-directory + ;; (cond + ;; ((and (derived-mode-p 'dired-mode) + ;; (file-in-directory-p default-directory bongo-default-directory)) + ;; default-directory) + ;; (t + ;; bongo-default-directory))) + ;; (all-files (counsel--find-return-list counsel-file-jump-args)) + ;; (base default-directory) + ;; (chosen-files (durand-choose-list (mapcar 'list all-files) nil "Choose music to add: " t + ;; nil nil t nil t))) + ;; (cl-loop for song in chosen-files + ;; do + ;; (with-bongo-playlist-buffer + ;; (bongo-insert-file + ;; (file-truename (expand-file-name song base))))) + ;; ;; (ivy-read "Choose music to add: " all-files + ;; ;; :require-match t + ;; ;; :action (lambda (f) + ;; ;; (with-current-buffer bongo-default-playlist-buffer-name + ;; ;; (bongo-insert-file + ;; ;; (file-truename (expand-file-name f base)))))) + ;; )) + + ;; REVIEW: This is oft not overriding the original function, to the effect that + ;; the first time bongo starts, this function does not work, and I have to + ;; define this function again, in order to play the music. So I decided to make + ;; this into an overriding advice. +;;;###autoload + (defun durand-bongo-compose-remote-option (socket-file) + "Get the command line argument for starting mpv's remote interface at SOCKET-FILE. +This has to be fixed for mpv to work, since its argument parsing +convention is changed." + ;; :override 'bongo-compose-remote-option + (when (equal bongo-mpv-remote-option 'unknown) + (setq bongo-mpv-remote-option (bongo--mpv-get-remote-option))) + (list (concat bongo-mpv-remote-option "=" socket-file))) + + (advice-add #'bongo-compose-remote-option :override 'durand-bongo-compose-remote-option) + +;;;###autoload + (defvar durand-bongo-save-playlist-hist nil + "A variable that holds the history values for saving playlist names.") + +;;;###autoload + (defun durand-bongo-save-playlist () + "Save the current playlist into a file." + (interactive) + (let ((playlist-name + (expand-file-name + (read-string "Playlist name:" nil 'durand-bongo-save-playlist-hist) + (expand-file-name "playlists" + bongo-default-directory))) + (append-p (y-or-n-p "Append? ")) + files end) + (with-current-buffer bongo-default-playlist-buffer-name + (save-excursion + (goto-char (or (bongo-point-at-first-track-line) + (user-error + "No tracks in the playlist!"))) + (push (bongo-line-file-name) files) + (while (not end) + (if-let ((next-pos (bongo-point-at-next-track-line))) + (progn + (goto-char next-pos) + (push (bongo-line-file-name) files)) + (setf end t))))) + (with-temp-buffer + (cl-loop for file in files + do (progn + (insert file) + (newline))) + (write-region nil nil playlist-name append-p)))) + +;;;###autoload + (defun durand-bongo-next-or-first (&optional n) + "Make the next track current in the nearest playlist buffer. +If there is no next track, go to the first track. +With prefix argument N, skip that many tracks." + (interactive "P") + (if (bongo-playing-p) + (durand-bongo-play-next-or-first n) + (with-bongo-playlist-buffer + (let ((line-move-ignore-invisible nil)) + (save-excursion + (goto-char (or (bongo-point-at-current-track-line) + (bongo-point-at-first-track-line) + (user-error "No tracks in playlist"))) + (dotimes (_dummy (prefix-numeric-value n)) + (goto-char (or (bongo-point-at-next-track-line) + (bongo-point-at-first-track-line)))) + (bongo-set-current-track-position)))))) + +;;;###autoload + (defun durand-bongo-play-next-or-first (&optional n) + "Start playing the next track in the nearest Bongo playlist buffer. +If there is no next track to play, signal an error. +With numerical prefix argument N, skip that many tracks. +With \\[universal-argument] as prefix argument, just switch to \ +progressive playback mode. +With \\[universal-argument] \\[universal-argument] as prefix argument, \ +insert an action track at point." + (interactive "P") + (cond + ((equal n '(16)) + (bongo-insert-line 'bongo-action '(bongo-progressive-playback-mode))) + ((equal n '(4)) + (bongo-progressive-playback-mode)) + ((consp n) + (user-error "This prefix argument %S is not supported." + n)) + ((< (prefix-numeric-value n) 0) + (durand-bongo-play-previous-or-last (- (prefix-numeric-value n)))) + (t + (with-imminent-bongo-player-start + (bongo-stop) + (when bongo-mark-played-tracks + (bongo-mark-current-track-line-as-played)) + (durand-bongo-next-or-first n) + (bongo-start))))) + +;;;###autoload + (defun durand-bongo-previous-or-last (&optional n) + "Make the previous track current in the nearest playlist buffer. +If there is no previous track, go to the last track. +With prefix argument N, skip that many tracks." + (interactive "p") + (if (bongo-playing-p) + (durand-bongo-play-previous-or-last n) + (with-bongo-playlist-buffer + (let ((line-move-ignore-invisible nil)) + (save-excursion + (goto-char (or (bongo-point-at-current-track-line) + (bongo-point-at-last-track-line) + (user-error "No tracks in playlist"))) + (dotimes (_dummy (prefix-numeric-value n)) + (goto-char (or (bongo-point-at-previous-track-line) + (bongo-point-at-last-track-line)))) + (bongo-set-current-track-position)))))) + +;;;###autoload + (defun durand-bongo-play-previous-or-last (&optional n) + "Start playing the previous track in the nearest playlist buffer. +If there is no previous track to play, play the last track. +With numerical prefix argument N, skip that many tracks. +With \\[universal-argument] as prefix argument, just switch to \ +regressive playback mode. +With \\[universal-argument] \\[universal-argument] as prefix argument, \ +insert an action track at point." + (interactive "P") + (cond + ((equal n '(16)) + (bongo-insert-line 'bongo-action '(bongo-regressive-playback-mode))) + ((equal n '(4)) + (bongo-regressive-playback-mode)) + ((consp n) + (user-error "This prefix argument %S is not supported." + n)) + ((< (prefix-numeric-value n) 0) + (durand-bongo-play-next-or-first (- (prefix-numeric-value n)))) + (t + (with-imminent-bongo-player-start + (bongo-stop) + (when bongo-mark-played-tracks + (bongo-mark-current-track-line-as-played)) + (durand-bongo-previous-or-last n) + (bongo-start))))) + +;;;###autoload + (defun durand-bongo-play-first () + "Play the first song." + (interactive) + (with-bongo-playlist-buffer + (with-imminent-bongo-player-start + (bongo-stop) + (when bongo-mark-played-tracks + (bongo-mark-current-track-line-as-played)) + (goto-char (or (bongo-point-at-first-track-line) + (prog1 (point) + (message "No track in the playlist buffer.")))) + (bongo-set-current-track-position) + (bongo-start)))) + +;;;###autoload + (defun durand-bongo-play-last () + "Play the first song." + (interactive) + (with-bongo-playlist-buffer + (with-imminent-bongo-player-start + (bongo-stop) + (when bongo-mark-played-tracks + (bongo-mark-current-track-line-as-played)) + (goto-char (or (bongo-point-at-last-track-line) + (prog1 (point) + (message "No track in the playlist buffer.")))) + (bongo-set-current-track-position) + (bongo-start)))) + + ;; NOTE: Fix a bug: there is no face called `modeline'; it should be + ;; `mode-line'. +;;;###autoload + (defun durand-bongo-seek () + "Interactively seek in the current Bongo track." + ;; :override 'bongo-seek + (interactive) + (setq bongo-seek-buffer (get-buffer-create "*Bongo Seek*")) + (if bongo-seek-electric-mode + (unwind-protect + (save-window-excursion + (require 'electric) + (message nil) + (let ((garbage-collection-messages nil) + (bongo-seeking-electrically t)) + (ignore bongo-seeking-electrically) + (set-window-buffer (minibuffer-window) bongo-seek-buffer) + (select-window (minibuffer-window)) + (let ((old-local-map (current-local-map)) + (old-global-map (current-global-map))) + (use-local-map nil) + (use-global-map bongo-seek-mode-map) + (setq major-mode 'bongo-seek-mode) + (unwind-protect + (progn + (bongo-seek-redisplay) + (run-hooks 'bongo-seek-mode-hook) + (catch 'bongo-seek-done + (Electric-command-loop + 'bongo-seek-done + ;; Avoid `noprompt' due to + ;; a bug in electric.el. + '(lambda () 'noprompt) + nil + (lambda (_x _y) (bongo-seek-redisplay))))) + (use-local-map old-local-map) + (use-global-map old-global-map))))) + (when bongo-seek-buffer + (kill-buffer bongo-seek-buffer) + (setq bongo-seek-buffer nil))) + (cond + ((null (get-buffer-window bongo-seek-buffer)) + (let ((window-min-height 2) + (split-window-keep-point nil)) + (select-window + (split-window-vertically + (if (and (fboundp 'face-attr-construct) + ;; NOTE: bug occurs here. + (plist-get (face-attr-construct 'mode-line) :box)) + -3 -2))) + (switch-to-buffer bongo-seek-buffer))) + ((not (eq (current-buffer) bongo-seek-buffer)) + (select-window (get-buffer-window bongo-seek-buffer)))) + (bongo-seek-mode) + ;; NOTE: added by Durand to start always in evil-emacs-state + (setq buffer-read-only t) + (bongo-seek-redisplay))) + + (advice-add 'bongo-seek :override #'durand-bongo-seek) + +;;; HACK: Redefine a function to go to the bongo-default-directory when no track +;;; is under point. +;;; +;;;###autoload + (defun durand-bongo-dired-line (&optional point) + "Open a Dired buffer containing the track at POINT. +Modified by Durand." + ;; :override 'bongo-dired-line + (interactive) + ;;; NOTE: The body-form inside condition-case is the original function body. + (condition-case nil + (save-excursion + (bongo-goto-point point) + (bongo-snap-to-object-line) + (dired (file-name-directory + (save-excursion + (while (bongo-header-line-p) + (bongo-down-section)) + (if (bongo-local-file-track-line-p) + (bongo-line-file-name) + (error "No local file track here"))))) + (bongo-dired-library-mode 1)) + ('error (dired bongo-default-directory)))) + + (advice-add 'bongo-dired-line :override #'durand-bongo-dired-line) + +;;; NOTE: I would like bongo to jump to bongo-playlist-buffer immediately, +;;; otherwise sometimes it jumps to the dired buffer, which is annoying. + +;;;###autoload + (defun durand-bongo-buffer () + "Return the buffer (bongo-playlist-buffer)." + :override 'bongo-buffer + (interactive) + (bongo-playlist-buffer)) + + (advice-add #'bongo-buffer :override #'durand-bongo-buffer) + +;;; hydra + + ;; NOTE: I would like to have a hydra to do some basic bongo commands, like go + ;; to the next song, or control the volume. + +;;;###autoload + (defun durand-bongo-next-song (&optional n) + "Play the next N song." + (interactive "p") + (with-bongo-playlist-buffer + (durand-bongo-play-next-or-first n))) + +;;;###autoload + (defun durand-bongo-previous-song (&optional n) + "Play the previous N song." + (interactive "p") + (with-bongo-playlist-buffer + (durand-bongo-play-previous-or-last n))) + +;;;###autoload + (defun durand-bongo-seek-anywhere () + "A wrapper around `durand-bongo-seek'." + (interactive) + (with-bongo-playlist-buffer + (durand-bongo-seek) + (setf durand-bongo-hydra-volume-return-p t))) + +;;;###autoload + (defun bongo-seek-forward-5 (&optional n) + "Seek 5 N seconds forward in the currently playing track." + (interactive "p") + (bongo-seek-forward (* 5 (or n 1)))) + +;;;###autoload + (defun bongo-seek-backward-5 (&optional n) + "Seek 5 N seconds backward in the currently playing track." + (interactive "p") + (bongo-seek-backward (* 5 (or n 1)))) + +;;;###autoload + (defun durand-bongo-kill-line () + "Kill the currently playing bongo line." + (interactive) + (with-bongo-playlist-buffer + (bongo-recenter) + (bongo-kill-line))) + + ;; NOTE: I would like to stay in my hydra after setting the volume, so I wrote + ;; this hacky workaround. + +;;;###autoload + ;; (defvar durand-bongo-hydra-volume-return-p nil + ;; "Whether to return to the hydra after quitting the volume buffer.") + + ;; ;;;###autoload + ;; (defun durand-bongo-volume () + ;; "Stay in the hydra after adjusting the volume." + ;; (interactive) + ;; (volume) + ;; (setf durand-bongo-hydra-volume-return-p t)) + + ;; ;;;###autoload + ;; (defadvice! durand-bongo-volume-call-hydra-a (&rest _args) + ;; "Call `durand-bongo-hydra/body' if `durand-bongo-hydra-volume-return-p' is non-nil." + ;; :after '(volume-quit bongo-seek-quit) + ;; (when durand-bongo-hydra-volume-return-p + ;; (durand-bongo-hydra/body))) + + ;; ;;;###autoload + ;; (defhydra durand-bongo-hydra (nil + ;; nil + ;; :hint nil + ;; :color blue + ;; :pre (setf durand-bongo-hydra-volume-return-p nil)) + ;; " + ;; _q_: quit _n_: next song _f_ : forward 5 _F_: forward 10 _<tab>_: show + ;; _v_: volume _p_: previous song _b_ : backward 5 _B_: backward 10 + ;; _s_: seek _d_: clear _SPC_: pause / resume _<_: first + ;; _m_: bongo _i_: insert _I_ : playlist _>_: last + ;; " + ;; ("q" nil) + ;; ("v" durand-bongo-volume) + ;; ("s" durand-bongo-seek-anywhere) + ;; ("m" bongo) + ;; ("n" durand-bongo-next-song :color amaranth) + ;; ("p" durand-bongo-previous-song :color amaranth) + ;; ("d" prot/bongo-clear-playlist-and-stop :color amaranth) + ;; ("i" durand-bongo-dired-ivy-find-to-add :color amaranth) + ;; ("f" bongo-seek-forward-5 :color amaranth) + ;; ("b" bongo-seek-backward-5 :color amaranth) + ;; ("SPC" bongo-pause/resume :color amaranth) + ;; ("I" durand-bongo-insert-delete-playlist :color amaranth) + ;; ("F" bongo-seek-forward-10 :color amaranth) + ;; ("B" bongo-seek-backward-10 :color amaranth) + ;; ("<" durand-bongo-play-first :color amaranth) + ;; (">" durand-bongo-play-last :color amaranth) + ;; ("<tab>" bongo-show :color amaranth)) + + ;; ;;; NOTE: volume-set does not refresh the display, so let's fix that. + + (defun durand-bongo-refresh-after-set-a (&rest _args) + "Refresh the display after we set the volume." + ;; :after 'volume-set + (volume-redisplay)) + + (advice-add #'volume-set :after #'durand-bongo-refresh-after-set-a) + +;;; Don't insert text in the playlist buffer. + +;;;###autoload + (defun durand-bongo-default-playlist-buffer-a () + "Don't insert text in the playlist buffer." + ;; :override #'bongo-default-playlist-buffer + (or (get-buffer bongo-default-playlist-buffer-name) + (let ((buffer (get-buffer-create bongo-default-playlist-buffer-name))) + (prog1 buffer + (with-current-buffer buffer + (bongo-playlist-mode)))))) + + (advice-add #'bongo-default-playlist-buffer :override #'durand-bongo-default-playlist-buffer-a) + ) + +(use-package "volume" 'volume + (define-key volume-mode-map [?s] #'volume-set)) diff --git a/center-buffer.el b/center-buffer.el new file mode 100644 index 0000000..69d4a90 --- /dev/null +++ b/center-buffer.el @@ -0,0 +1,38 @@ +;;; center-buffer.el --- Center the buffer -*- lexical-binding: t; -*- + +;;; Commentary: + +;;; This is some code I extracted from "olivetti" as a lightweight +;;; version of that package to center my buffer, only temporarily, +;;; unfortunately. + +;;; Code: + +;;;###autoload +(defvar center-buffer-width 80 + "The width of the body.") + +;;;###autoload +(defun center-buffer-on () + "Center the buffer." + (interactive) + (let* ((mt (/ (- (window-total-width) 80) 2)) + (fringes (window-fringes)) + (lf (/ (car fringes) (float (frame-char-width)))) + (rf (/ (cadr fringes) (float (frame-char-width)))) + (lm (max (round (- mt lf)) 0)) + (rm (max (round (- mt rf)) 0))) + (set-window-margins (selected-window) lm rm))) + +;;;###autoload +(defun center-buffer-off () + "Reset buffer." + (interactive) + (set-window-margins (selected-window) 0 0)) + + + + + +(provide 'center-bufrfer) +;;; center-bufrfer.el ends here. diff --git a/comb/suffiex-tree.txt b/comb/suffiex-tree.txt new file mode 100644 index 0000000..51908a3 --- /dev/null +++ b/comb/suffiex-tree.txt @@ -0,0 +1,217 @@ +Title: Suffix Trees +Author: JSDurand +Created: 2020-01-03 +------------------- + +====================================================================== + Motivation to implement this algorithm in Emacs +====================================================================== + +The reason I want to implement this algorithm is a problem I +encountered in using the package "orderless", which provides a +completion-style for the built-in completion system in Emacs. The +problem is that the function "orderless-try-completion" does not +handle completion aggressively in a way that conforms to the +documentation of "try-completion". To be more precise, if there is +only one match for the current text input, then this function returns +that match (rather than comforming to the requirement in the +documentation of "try-completion" by returning t, since it wants to +highlight the matches by itself). This isn't a problem from the +perspective of the user, and if there are no matches, then this +correctly returns nil. But in any other cases, this function returns +the original string, instead of the longest common substring, as a +user might desire. + +Initially, this does not seem like a serious concern: the user could +still select a completion from the "*Completions*" buffer once the +list of candidates becomes small enough to easily manage. But as time +goes by, this starts to frustrate me. For example, when there are only +two candidates left, but one is a substring of another, then I cannot +use the completion feature to quickly select (or "complete to") the +shorter candidate, unless I type out the full candidate string, or to +choose from the "*Completions*" buffer. For me this kind of defeats +the main purpose of the built-in completion system. + +So I start wondering, is it possible to fix the problem by finding the +longest common substring in all the matches? From a naïve first +impression, this seems to be what the user might expect in most cases. + + + +====================================================================== + Choice of the algorithm +====================================================================== + +After some thinking and searching through the internet, I found that +perhaps the most flexible and performant solution to the problem of +finding the longest common substring(s) of multiple strings is to +build a "generalized suffix tree" of them, and then use a tree +traversal to find the longest common substring(s). Well, this is all +fun and great. The only problem is that it is difficult to build a +suffix tree (or a generalized one). + +So I decide to implement the seemingly fastest algorithm to construct +a suffix tree of strings and hope that this can not only solve my +problem but also help others out in some other problems in the future. + + + +====================================================================== + Definitions +====================================================================== + +I describe the basic definition of a suffix tree briefly below. + +In this document a string is a sequence of alphabets. In particular, +for the case of Emacs, these alphabets are just numbers. We begin by +considering a string S of length n. A suffix of S is a substring of S +of the form S[i..n] for some i from 1 to n. And we also say the empty +string is a suffix of S. A suffix tree of S is defined as a rooted +tree T (so it has a node called "root" that is the ancestor of every +other node) whose every edge has a label which is a substring of S +that satisfies the following conditions: + +- Starting from the root of T, walking down any path to a leaf, and + concatenating the labels along the way, then we will get a suffix of + S. And every suffix of S is obtained in this way as well. +- Every node has at least two out-going edges. +- For every node, every two out-going edges cannot have labels that + start with the same letter. (So two edges with labels both starting + with 'a' cannot emanate from the same node.) + +Intuitively speaking, this is to list all suffixes of S as an edge +from the root to a leaf, and then "merge" these suffixes so that any +common prefix among some of them is in only one edge. + + + +====================================================================== + Description of the algorithm +====================================================================== + +Below is a breif description of the algorithm. For a description in +"plain English", see the accepted answer to this Stack Overflow post. + +https://stackoverflow.com/questions/9452701/ + +For a more detailed survey on the principle behind the algorithm and +on many other related topics, see the book "Algorithms on Strings, +Trees, and Sequences: Computer Science and Computational Biology" by +Dan Gusfield, or if you prefer reading the original paper, then the +original paper by Ukkonen is as follows. + +https://link.springer.com/article/10.1007/BF01206331 + +(I am fortunate enough to be able to access the article. If you want +to read that PDF and don't want to pay Springer, let me know and I can +send you the file.) + +Given a string S of length n, we will first append a symbol that is +not present anywhere in S, in order to ensure that no suffix of S is +also the prefix of another suffix of S; otherwise S cannot have a +suffix tree. I refer to this terminating symbol as $. + +Also an edge of the tree is not labelled explicitly by strings. To do +so would violate already the linear time constraint. Instead, we +represent each edge with a pair of integers, interpreted as the +indices of the starting and the ending points of the associated +substring in T. + +The algorithm has n + 1 iterations. We start with the following +variables: + +- s = root +- k = 1 +- i = 0 +# - A root node. +# - An "active point" with value (root, nil, 0). +# - "remainder" with value 1. + +Then we want to add n + 1 symbols to the tree iteratively. + +In the i-th iteration we look to add the i-th letter S (i) of S. In +Emacs Lisp this is expressed as (aref S i). + +# substring +# S[(i-remainder+1)..i] + +And in each iteration we do the following things: + +- (setq i (+ i 1)) +- (let ((result (update s k i))) + (setq s (car result)) + (setq k (cadr result))) + We update by adding the i-th letter S(i) to the current active point + indicated by (s, k, i - 1), see below. +- (let ((result (canonize s k i))) + (setq s (car result)) + (setq k (cadr result))) + We canonize the new active point returned by the update function. + The process of canonization is to find the closest node to the + point. + +Then we repeat until S(i) equals the terminating symbol (this way we +avoid calculating the length of the string beforehand, since in Emacs +Lisp the string does not have the length pre-calculated. Though this +does not affect the overall time complexity, it might affect the +practical performance. + +The function "update is described below. + +It taks three arguments: s, k, and i. First let oldr = root. Then let +(end-p, r) be the result of (test-and-split s k (- i 1) S(i)). + + + + + + + + + + + + + +# begin a "remainder loop". Whenever the remainder +# loop ends, we go to the next iteration. + +We compare the letter S(i) with the labels of edges going out from the +active point. That is, if the active point is (node, edge_label, m), +then this is the length m point in the edge going out from node with +the first letter of label given as edge_label. + +If the letter is the prefix of some edge label, then we set the +active point to (node, edge_label, m+1) and increment remainder by 1. +If m+1 is greater than or equal to the length of the current edge, +then set the active point to follow that edge to the new point. + +Then we end the remainder loop and skip to the next iteration. + +--- + +If the letter is not the prefix of any edge label emanating from the +active point, and m > 0, then we split the point (node, edge_label, m) +into a node and add a new leaf to that node, with label S(i). And then +we decrement remainder by 1. + +If this is not the first time we split a node in the current +iteration, then we add a "suffix link" from the previously created +node to the newly created node. + +If the "node" in the specification of the active point is the root, +then we set the active point to (root, S(i-remainder+1), m-1). + +If the "node" is not the root, then if the node has a suffix link to +other_node, then we set the active point to the following: +(other_node, S(i-remainder+1), m-1) + +If the node has no suffix link, then we set the active point to the +following: (root, S(i-remainder+1), m-1) + +--- + +If the letter is not the prefix of any edge label emanating from the +active point, and if m = 0, then we add a new leaf with label S(i) to +node, and decrement remainder by 1. Then we follow the same rules to +reset the active point. diff --git a/common.el b/common.el new file mode 100644 index 0000000..dd12539 --- /dev/null +++ b/common.el @@ -0,0 +1,73 @@ +;;; common.el --- Some common functions -*- lexical-binding: t; -*- + +;;;###autoload +(defun center-string-in-width (str width) + "Add spaces to STR so that it is centered in a box which is WIDTH wide." + (let ((len (length str))) + (cond + ((> len width) + (error "String %s longer than %d" str width)) + (t (format "%s%s" + (make-string (round (- width len) 2) + 32) + str))))) + +;;; jump between the completions buffer and the minibuffer + +;;;###autoload +(defvar durand-completion-buffer-names (list "Completions" + "Embark Live Occur" + "comb") + "The list of names that match the names of \"completion buffers\".") + +;;;###autoload +(defun durand-focus-completion-or-minibuffer (&optional arg) + "Jump between the completions buffer and the minibuffer." + (interactive "P") + (let* ((completion-windows + (delq nil + (mapcar + (lambda (w) + (and (consp + (delq nil + (mapcar (lambda (name) + (string-match-p + name + (buffer-name (window-buffer w)))) + durand-completion-buffer-names))) + w)) + (window-list nil 'nomini)))) + (in-completion-p (consp + (delq nil + (mapcar + (lambda (name) + (string-match-p name (buffer-name))) + durand-completion-buffer-names)))) + (minibuffer-active-p (active-minibuffer-window)) + (in-minibuffer-p (minibuffer-window-active-p (selected-window)))) + (cond + ((and minibuffer-active-p + (not in-minibuffer-p)) + (select-window (active-minibuffer-window))) + ((and (consp completion-windows) + (not in-completion-p)) + (select-window (car completion-windows))) + (t + (other-window 1))))) + +;;; Intentionally disable some key-bindings. + +;;;###autoload +(defun intentionally-disabled-bind () + "Warn the user that this key-binding is intentionally disabled." + (interactive) + (user-error "You pressed an intentionally disabled key-binding: %s" + (key-description (this-command-keys-vector)))) + + + +(provide 'common) +;;; common.el ends here. + + + diff --git a/dashboard.el b/dashboard.el new file mode 100644 index 0000000..a8f753f --- /dev/null +++ b/dashboard.el @@ -0,0 +1,50 @@ +;;; dashboard.el --- My daashboard -*- lexical-binding: t; -*- + +;;;###autoload +(defvar dashboard-buffer-name "durand" + "The name of the buffer for the dashboard.") + +;;;###autoload +(defun dashboard () + "Create the dashboard buffer." + (interactive) + (let ((dashboard-exists-p (get-buffer dashboard-buffer-name)) + (dashboard (get-buffer-create dashboard-buffer-name))) + (cond + (dashboard-exists-p + (switch-to-buffer dashboard)) + (t + (with-current-buffer dashboard + (let ((image (create-image "~/.doom.d/banners/default.png"))) + (insert + (center-string-in-width + (propertize " " 'display image 'rear-nonsticky '(display)) + (round (- (window-body-width) + (* (car (image-size image)) 0.6)))))) + (newline 5) + (insert + (center-string-in-width + "Dashboard" + (window-body-width))) + (read-only-mode 1) + (set 'mode-line-format + '("%e" (:eval (modeline-format-dashboard))))))) + dashboard)) + +(set 'initial-buffer-choice #'dashboard) + +;;; Modify killing buffers + +;;;###autoload +(defun dont-kill-dashboard-fn () + "Don't kill the dashboard buffer." + (cond + ((eq (current-buffer) (get-buffer dashboard-buffer-name)) + (message "Don't kill the dashboard buffer.") + nil) + (t))) + +(add-hook 'kill-buffer-query-functions 'dont-kill-dashboard-fn) + +(provide 'dashboard) +;;; dashboard.el ends here. @@ -0,0 +1,19 @@ +;; -*- mode: emacs-lisp; lexical-binding:t; coding: utf-8-emacs; -*- +;; -------------------------------------------------------------------------- +;; Desktop File for Emacs +;; -------------------------------------------------------------------------- +;; Created Sat Jan 9 12:10:19 2021 +;; Desktop file format version 208 +;; Emacs version 27.1 + +;; Global section: +(setq desktop-saved-frameset nil) +(setq desktop-missing-file-warning nil) +(setq tags-file-name nil) +(setq tags-table-list nil) +(setq search-ring '(#("gnus-" 0 5 (isearch-regexp-function nil isearch-case-fold-search t)) #("en" 0 2 (isearch-case-fold-search t isearch-regexp-function nil)) #("gnu" 0 3 (isearch-regexp-function nil isearch-case-fold-search t)) #("mu" 0 2 (isearch-regexp-function nil isearch-case-fold-search t)) #("curr" 0 4 (isearch-regexp-function nil isearch-case-fold-search t)) #("mu4e-" 0 5 (isearch-regexp-function nil isearch-case-fold-search t)) #("gnus" 0 4 (isearch-regexp-function nil isearch-case-fold-search t)) #("mu4e" 0 4 (isearch-regexp-function nil isearch-case-fold-search t)) #("mem" 0 3 (isearch-regexp-function nil isearch-case-fold-search t)) #("that" 0 4 (isearch-regexp-function nil isearch-case-fold-search t)) #("pap" 0 3 (isearch-regexp-function nil isearch-case-fold-search t)) #("int" 0 3 (isearch-regexp-function nil isearch-case-fold-search t)) #("great" 0 5 (isearch-regexp-function nil isearch-case-fold-search t)) #("s," 0 2 (isearch-case-fold-search t isearch-regexp-function nil)) #("much" 0 4 (isearch-regexp-function nil isearch-case-fold-search t)) #("art" 0 3 (isearch-regexp-function nil isearch-case-fold-search t)))) +(setq regexp-search-ring '(#("emacs.*bug" 0 10 (isearch-case-fold-search t)) #("emacs.*deve" 0 11 (isearch-case-fold-search t)) #("emacs.*bugs" 0 11 (isearch-case-fold-search t)) #("emacs.*devel" 0 12 (isearch-case-fold-search t)))) +(setq register-alist (list '(101 #("#'embark-export" 0 2 (fontified t face font-lock-keyword-face) 2 15 (fontified t face font-lock-constant-face)) #("#'embark-export" 0 2 (fontified t face font-lock-keyword-face) 2 15 (fontified t face font-lock-constant-face))) '(107 . #("(define-key embark-occur-mode-map (vector ?\\ ) )" 0 1 (fontified t) 1 11 (fontified t face font-lock-constant-face) 11 12 (fontified t) 12 33 (fontified t face font-lock-variable-name-face) 33 34 (fontified t) 34 35 (fontified t) 35 41 (fontified t face font-lock-constant-face) 41 45 (fontified t) 45 47 (fontified t) 47 48 (fontified t rear-nonsticky t))) (list 115 "Unprintable entity" (let ((mk (make-marker))) (add-hook 'desktop-delay-hook (lambda nil (set-marker mk nil (get-buffer " *temp*")))) mk)) '(114 . #("(pop result)" 0 1 (fontified t) 1 4 (fontified t face font-lock-keyword-face) 4 11 (fontified t) 11 12 (fontified t))) (desktop-list* 108 (let ((mk (make-marker))) (add-hook 'desktop-delay-hook (lambda nil (set-marker mk nil (get-buffer " *temp*")))) mk)) (list 109 "Unprintable entity" (let ((mk (make-marker))) (add-hook 'desktop-delay-hook (lambda nil (set-marker mk nil (get-buffer " *temp*")))) mk)) '(100 . #(";;;###autoload\n(defun )" 0 3 (face font-lock-comment-delimiter-face fontified t) 3 6 (face font-lock-comment-face fontified t) 6 13 (face (font-lock-warning-face font-lock-warning-face) fontified t) 13 14 (face (font-lock-warning-face font-lock-warning-face) rear-nonsticky t fontified t) 14 15 (face font-lock-comment-face fontified t) 15 16 (fontified t) 16 21 (face font-lock-keyword-face fontified t) 21 22 (fontified t) 22 23 (fontified t))) '(118 . #(";;;###autoload\n(defvar )" 0 3 (face font-lock-comment-delimiter-face fontified t) 3 6 (face font-lock-comment-face fontified t) 6 13 (face (font-lock-warning-face font-lock-warning-face) fontified t) 13 14 (face (font-lock-warning-face font-lock-warning-face) rear-nonsticky t fontified t) 14 15 (face font-lock-comment-face fontified t) 15 16 (fontified t) 16 22 (face font-lock-keyword-face fontified t) 22 23 (fontified t) 23 24 (fontified t))) '(97 . #(";;;###autoload" 0 3 (face font-lock-comment-delimiter-face fontified t) 3 6 (face font-lock-comment-face fontified t) 6 14 (face (font-lock-warning-face font-lock-warning-face) fontified t))))) +(setq file-name-history '("~/Desktop/emacs.d/comb" "~/Desktop/emacs.d/" "~/Downloads/documents intéressants/Algorithms/Algorithms on Strings, Trees, and Sequences Computer Science and Computational Biology by Dan Gusfield (z-lib.org).pdf" "~/Desktop/emacs.d/comb/pdf reading progress.txt" "~/Desktop/emacs.d/view-functions.el" "~/Desktop/emacs.d/center-buffer.el" "~/Desktop/emacs.d/gnus-conf.el" "~/Desktop/emacs.d/org-conf.el" "~/Desktop/emacs.d/ibuffer.el" "~/Desktop/emacs.d/comb/" "suffix-tree.el" "~/Desktop/emacs.d/comb/suffix-tree.el" "~/elisp_packages/hierarchy/hierarchy.el" "~/org/notes.org" "~/Desktop/emacs.d/init.el" "~/Desktop/emacs.d/embark-conf.el" "~/elisp_packages" "~/elisp_packages/embark/embark.el" "~/elisp_packages/embark" "~/elisp_packages/" "~/Desktop/nnmaildir+private:private" "~/Desktop/" "~/Desktop/emacs.d/basic.el" "~/.doom.d/modules/lang/durand-org/config.el" "~/.doom.d/modules/email/durand-gnus/README.org" "~/.doom.d/modules/email/durand-gnus/config.el" "~/Desktop/emacs.d/comb/*Summary nntp+news.gmane.io:gmane.emacs.devel*.ps" "~/Desktop/emacs.d/comb/ST.cpp" "~/Desktop/emacs.d/bongo.el" "~/elisp_packages/hierarchy" "~/.doom.d/modules/emacs/durand-ibuffer/config.el" "~/.doom.d/init.el" "~/.doom.d/modules/app/durand-bongo/autoload.el" "~/.doom.d/modules/app/durand-bongo/config.el" "~/Desktop/emacs.d/comb/comb.el" "~/Desktop/emacs.d/backups/" "~/" "~/.newsrc.eld" "~/.newsrc" "~/.nnmaildir/private" "~/.nnmaildir/" "~/.nnmaildir" "~/Desktop" "~/.gnus.el" "~/.mbsyncrc" "~/Desktop/emacs.d/GNU Emacs integrated computing environment | Protesilaos Stavrou.pdf" "/Users/durand/.gnus.el" "~/Desktop/Centre/Mes notes/casual notes/links.txt" "~/Desktop/Centre/Mes notes/casual notes" "~/Desktop/Centre/Mes notes/" "~/.authinfo.gpg" "~/.doom.d/modules/editor/durand-evil/autoload.el" "~/.doom.d/modules/editor/durand-evil/config.el" "~/.doom.d/modules/editor/durand-evil/evil-setting.el" "~/.doom.d/" "~/.doom.d/autoload.el" "~/.doom.d/modules/email/durand-mu/" "~/.doom.d/modules/email/durand-mu/autoload.el" "/Users/durand/.doom.d/modules/email/durand-mu/config.el" "~/Desktop/emacs.d/mail.el" "~/mbsync" "~/Desktop/emacs.d/text-conf.el" "~/Desktop/emacs.d/modes/Concepts.txt" "~/Desktop/emacs.d/dashboard.el" "~/Desktop/emacs.d/desktop-conf.el" "~/Desktop/emacs.d/backups" "~/Downloads/documents intéressants/Algorithms/On-line Construction Of Suffix Tree by Ukkonen in 1995.pdf" "~/Downloads/documents intéressants/Algorithms/algorithm 2.png" "~/Downloads/documents intéressants/Algorithms/" "~/Downloads/documents intéressants/Algorithms/overall algorithm in Ukkonen paper.png" "~/Desktop/emacs.d/comb/suffix-tree.txt" "/Users/durand/Downloads/documents intéressants/Algorithms/update procedure in Ukkonen paper.png" "/Users/durand/Downloads/documents intéressants/Algorithms/overall algorithm in Ukkonen paper.png" "/Users/durand/Downloads/documents intéressants/Algorithms/Algorithm 1 from Ukkonen paper.png" "~/Downloads/documents intéressants/Algorithms/overall algorithm in Ukkonen pdf.png" "~/Downloads/documents intéressants/Algorithms/update procedure in Ukkonen pdf.png" "~/Downloads/documents intéressants/Algorithms/Algorithm 1 from Ukkonen pdf.png" "~/Desktop/emacs.d/tab-conf.el" "~/Downloads/documents intéressants/Algorithms/Ukkonen power point.pdf" "~/Downloads" "~/Desktop/emacs.d/comb/suffiex-tree.txt" "~/Desktop/emacs.d/comb/reference geeks for geeks.txt" "~/Desktop/Centre/Musique/Chansons/Blama/文殊師利菩薩祈請文・多識仁波切 譯 ᴴᴰ དཔེ་སྐྲུན་ཁང་། ・Praise of Manjushri Bodhisattva.mp3" "/stackoverflow.com/questions/9452701/" "~/w.emacs.d/emacs/lisp/minibuffer.el" "~/Downloads/" "~/Desktop/screen shot.png" "~/Desktop/Centre/Musique/Chansons/Chinois/辞洛 - Cover 一生獨一 -GY8130qPqW8.mkv" "~/Desktop/Centre/Musique/Chansons/Chinois/程響 - 世界這麼大還是遇見你 -wRmedql89Ro.webm" "~/Desktop/emacs.d/dired-conf.el" "~/Desktop/emacs.d/common.el" "~/Desktop/emacs.d/comb/orderless-conf.el" "~/Desktop/emacs.d/recentf-conf.el" "~/Desktop/emacs.d/modeline.el" "~/Desktop/test.png" "~/Desktop/Centre/PDF/" "~/Downloads/Algorithms on Strings, Trees, and Sequences Computer Science and Computational Biology by Dan Gusfield (z-lib.org).djvu")) + +;; Buffer section -- buffers listed in same order as in buffer list: diff --git a/desktop-conf.el b/desktop-conf.el new file mode 100644 index 0000000..2439c10 --- /dev/null +++ b/desktop-conf.el @@ -0,0 +1,170 @@ +(setq desktop-auto-save-timeout 600) +(setq desktop-dirname "/Users/durand/Desktop/emacs.d/") +(setq desktop-path '("/Users/durand/Desktop/emacs.d/")) +(setq desktop-base-file-name "desktop") +(setq desktop-files-not-to-save nil) +(setq desktop-globals-to-clear nil) +(setq desktop-load-locked-desktop t) +(setq desktop-missing-file-warning nil) +(setq desktop-restore-eager t) +(setq desktop-restore-frames nil) +(setq desktop-save 'ask-if-new) + +;;;###autoload +(defun durand-desktop-save-a (dirname &optional release only-if-changed version) + "Save the state of Emacs in a desktop file in directory DIRNAME. +Optional argument RELEASE non-nil says we're done with this +desktop, in which case this function releases the lock of the +desktop file in DIRNAME. +If ONLY-IF-CHANGED is non-nil, compare the current desktop +information to that in the desktop file, and if the desktop +information has not changed since it was last saved, then do +not rewrite the file. + +To restore the desktop, use `desktop-read'. + +This function can save the desktop in either format version +208 (which only Emacs 25.1 and later can read) or version +206 (which is readable by any Emacs from version 22.1 onwards). +By default, it will use the same format the desktop file had when +it was last saved, or version 208 when writing a fresh desktop +file. + +To upgrade a version 206 file to version 208, call this command +explicitly with a prefix argument: \\[universal-argument] \\[desktop-save]. +If you are upgrading from Emacs 24 or older, we recommed to do +this once you decide you no longer need compatibility with versions +of Emacs before 25.1. + +To downgrade a version 208 file to version 206, use a double prefix +argument: \\[universal-argument] \\[universal-argument] \\[desktop-save]. + +Emacs will ask for confirmation when you upgrade or downgrade your +desktop file. + +In a non-interactive call, VERSION can be given as an integer, either +206 or 208, to specify the format version in which to save the file, +no questions asked." + (interactive (list + ;; Or should we just use (car desktop-path)? + (let ((default (car desktop-path))) + (read-directory-name "Directory to save desktop file in: " + default default t)) + nil + nil + current-prefix-arg)) + (setq desktop-dirname (file-name-as-directory (expand-file-name dirname))) + (save-excursion + (let ((eager desktop-restore-eager) + (new-modtime (file-attribute-modification-time + (file-attributes (desktop-full-file-name))))) + (when + (or (not new-modtime) ; nothing to overwrite + (equal desktop-file-modtime new-modtime) + (yes-or-no-p (if desktop-file-modtime + (if (time-less-p desktop-file-modtime + new-modtime) + "Desktop file is more recent than the one loaded. Save anyway? " + "Desktop file isn't the one loaded. Overwrite it? ") + "Current desktop was not loaded from a file. Overwrite this desktop file? ")) + (unless release (error "Desktop file conflict"))) + + ;; If we're done with it, release the lock. + ;; Otherwise, claim it if it's unclaimed or if we created it. + (if release + (desktop-release-lock) + (unless (and new-modtime (desktop-owner)) (desktop-claim-lock))) + + ;; What format are we going to write the file in? + (setq desktop-io-file-version + (cond + ((equal version '(4)) + (if (or (eq desktop-io-file-version 208) + (yes-or-no-p "Save desktop file in format 208 \ +\(Readable by Emacs 25.1 and later only)? ")) + 208 + (or desktop-io-file-version desktop-native-file-version))) + ((equal version '(16)) + (if (or (eq desktop-io-file-version 206) + (yes-or-no-p "Save desktop file in format 206 \ +\(Readable by all Emacs versions since 22.1)? ")) + 206 + (or desktop-io-file-version desktop-native-file-version))) + ((memq version '(206 208)) + version) + ((null desktop-io-file-version) ; As yet, no desktop file exists. + desktop-native-file-version) + (t + desktop-io-file-version))) + + (with-temp-buffer + (insert + ";; -*- mode: emacs-lisp; lexical-binding:t; coding: utf-8-emacs; -*-\n" + desktop-header + ";; Created " (current-time-string) "\n" + ";; Desktop file format version " (format "%d" desktop-io-file-version) "\n" + ";; Emacs version " emacs-version "\n") + (save-excursion (run-hooks 'desktop-save-hook)) + (goto-char (point-max)) + (insert "\n;; Global section:\n") + ;; Called here because we save the window/frame state as a global + ;; variable for compatibility with previous Emacsen. + (desktop-save-frameset) + (unless (memq 'desktop-saved-frameset desktop-globals-to-save) + (desktop-outvar 'desktop-saved-frameset)) + (mapc #'desktop-outvar desktop-globals-to-save) + (setq desktop-saved-frameset nil) ; after saving desktop-globals-to-save + (when (memq 'kill-ring desktop-globals-to-save) + (insert + "(setq kill-ring-yank-pointer (nthcdr " + (int-to-string (- (length kill-ring) (length kill-ring-yank-pointer))) + " kill-ring))\n")) + + (insert "\n;; Buffer section -- buffers listed in same order as in buffer list:\n") + (dolist (l (mapcar #'desktop-buffer-info (buffer-list))) + (let ((base (pop l))) + (when (apply #'desktop-save-buffer-p l) + (insert "(" + (if (or (not (integerp eager)) + (if (zerop eager) + nil + (setq eager (1- eager)))) + "desktop-create-buffer" + "desktop-append-buffer-args") + " " + (format "%d" desktop-io-file-version)) + ;; If there's a non-empty base name, we save it instead of the buffer name + (when (and base (not (string= base ""))) + (setcar (nthcdr 1 l) base)) + (dolist (e l) + (insert "\n " (desktop-value-to-string e))) + (insert ")\n\n")))) + + (setq default-directory desktop-dirname) + ;; When auto-saving, avoid writing if nothing has changed since the last write. + (let* ((beg (and only-if-changed + (save-excursion + (goto-char (point-min)) + ;; Don't check the header with changing timestamp + (and (search-forward "Global section" nil t) + ;; Also skip the timestamp in desktop-saved-frameset + ;; if it's saved in the first non-header line + (search-forward "desktop-saved-frameset" + (line-beginning-position 3) t) + ;; This is saved after the timestamp + (search-forward (format "%S" desktop--app-id) nil t)) + (point)))) + (checksum (and beg (md5 (current-buffer) beg (point-max) 'utf-8-emacs)))) + (unless (and checksum (equal checksum desktop-file-checksum)) + (let ((coding-system-for-write 'utf-8-emacs)) + (write-region (point-min) (point-max) (desktop-full-file-name) nil 'nomessage)) + (setq desktop-file-checksum checksum) + ;; We remember when it was modified (which is presumably just now). + (setq desktop-file-modtime (file-attribute-modification-time + (file-attributes + (desktop-full-file-name))))))))))) + +(advice-add 'desktop-save :override 'durand-desktop-save-a) + + +(desktop-save-mode 1) diff --git a/dired-conf.el b/dired-conf.el new file mode 100644 index 0000000..31d64fd --- /dev/null +++ b/dired-conf.el @@ -0,0 +1,4 @@ +;;; -*- lexical-binding: t; -*- + +(set 'insert-directory-program "gls") +(set 'dired-listing-switches "-alh --group-directories-first") @@ -1,10 +1,5 @@ ;;; -*- lexical-binding: t; -*- -;;; a simpler mode name - -(add-hook 'emacs-lisp-mode-hook - (lambda () (set 'mode-name "ELisp"))) - ;;; fontification of extra keywords in emacs lisp files (require 'advice) @@ -56,6 +51,23 @@ (throw 'matcher t))))))) nil)) +;;; highlight parentheses + +(require 'paren) +(set 'show-paren-style 'parenthesis) +(set 'show-paren-highlight-openparen t) +(set 'show-paren-when-point-in-periphery nil) +(set 'show-paren-when-point-inside-paren nil) + +(add-hook 'emacs-lisp-mode-hook #'show-paren-mode) + +;;; remember cursor position + +(require 'saveplace) +(set 'save-place-file (expand-file-name "saveplace" load-file-directory)) +(set 'save-place-forget-unreadable-files t) +(save-place-mode 1) + ;;; a better indentation (advice-add #'calculate-lisp-indent :override #'better-calculate-lisp-indent) diff --git a/gnus-conf.el b/gnus-conf.el new file mode 100644 index 0000000..1a5ff18 --- /dev/null +++ b/gnus-conf.el @@ -0,0 +1,142 @@ +;;; gnus-conf.el --- My Gnus configurations -*- lexical-binding: t; -*- + +(require 'gnus) + +(setq gnus-select-method '(nnnil "")) +(setq gnus-secondary-select-methods + '((nntp "news.gmane.io") + (nnmaildir "private" (directory "~/.nnmaildir")) + (nnmaildir "sent" (directory "~/.nnmaildir")))) + +(setq gnus-ignored-from-addresses "mmemmew@gmail.com") + +(set 'gnus-novice-user nil) + +(setq nnmail-expiry-wait 'immediate) + +(setq gnus-parameters + '((".*" + (posting-style + (gcc "nnmaildir+private:Sent") + (From (format "%s" user-full-name)))))) + +(require 'gnus-msg) + +(setf gnus-posting-styles + '((".*" + (signature "李俊緯") + (address "mmemmew@gmail.com") + (name "Durand")) + ((header "from" "protesilaos") + (signature "Sévère Durand")) + ((header "from" "tan\\|mlh\\|hsialc") + (name "李俊緯") + (signature "生 俊緯")))) + +(setq gnus-gcc-mark-as-read t) + +;;; Call me an expert. + +(setq gnus-expert-user t) + +(setq gnus-agent t) + +(setq gnus-check-new-newsgroups 'ask-server) +(setq gnus-read-active-file 'some) + +(setq gnus-use-dribble-file t) +(setq gnus-always-read-dribble-file nil) + +(setq gnus-treat-display-smileys nil) +(setq gnus-treat-emphasize t) +(setq gnus-treat-fill-article nil) +(setq gnus-summary-goto-unread 'never) + +(add-hook 'gnus-group-mode-hook 'gnus-topic-mode) + +(setq gnus-group-line-format "%M%S%p%P%5y:%B%(%g%)\n") + +;; (setq gnus-topic-alist +;; '(("devel" "gmane.emacs.devel") +;; ("orgmode" "gmane.emacs.orgmode") +;; ("bug" "gmane.emacs.bugs") +;; ("emacs") +;; ("Gnus" "nndraft:drafts"))) + +(setq gnus-thread-sort-functions + '(gnus-thread-sort-by-most-recent-date + gnus-thread-sort-by-most-recent-number)) +(setq gnus-activate-level 4) + +(setq gnus-subthread-sort-functions + 'gnus-thread-sort-by-date) + +(setq gnus-thread-hide-subtree nil) +(setq gnus-ignored-from-addresses "mmemmew\\.com") + +;;; move between topics + +(define-key gnus-group-mode-map [?\M-n] 'gnus-topic-goto-next-topic) +(define-key gnus-group-mode-map [?\M-p] 'gnus-topic-goto-previous-topic) + +(define-key gnus-group-mode-map (vector ?q) #'bury-buffer) + +;;; agent settings + +(require 'gnus-agent) + +(define-key gnus-agent-summary-mode-map (vector ?$) #'previous-line) +(define-key gnus-agent-summary-mode-map (vector ?ù) #'next-line) +(define-key gnus-agent-summary-mode-map (vector ?n) #'gnus-summary-next-article) +(define-key gnus-agent-summary-mode-map (vector ?p) #'gnus-summary-prev-article) +(define-key gnus-agent-summary-mode-map (vector ?N) #'gnus-summary-next-unread-article) +(define-key gnus-agent-summary-mode-map (vector ?P) #'gnus-summary-prev-unread-article) +(define-key gnus-agent-summary-mode-map (vector ?o) #'gnus-summary-save-article) +(define-key gnus-agent-summary-mode-map (vector ?y) #'gnus-summary-scroll-down) +(define-key gnus-agent-summary-mode-map (vector ?!) #'gnus-summary-mark-as-processable) +(define-key gnus-agent-summary-mode-map (vector ?\M-n) #'gnus-summary-next-thread) +(define-key gnus-agent-summary-mode-map (vector ?\M-p) #'gnus-summary-prev-thread) +(define-key gnus-agent-summary-mode-map (vector ?\C-\M-n) #'gnus-summary-next-group) +(define-key gnus-agent-summary-mode-map (vector ?\C-\M-p) #'gnus-summary-prev-group) +(define-key gnus-agent-summary-mode-map (vector ?z ?t) #'recenter-to-top) +(define-key gnus-agent-summary-mode-map (vector ?z ?b) #'recenter-to-bottom) +(define-key gnus-agent-summary-mode-map (vector ?z ?z) #'recenter-to-middle) + +(define-key gnus-agent-group-mode-map (vector ?n) #'gnus-group-next-group) +(define-key gnus-agent-group-mode-map (vector ?p) #'gnus-group-prev-group) +(define-key gnus-agent-group-mode-map (vector ?N) #'gnus-group-next-unread-group) +(define-key gnus-agent-group-mode-map (vector ?P) #'gnus-group-prev-unread-group) + +;;; article + +(require 'gnus-art) + +(define-key gnus-article-mode-map [?z ?t] 'recenter-to-top) +(define-key gnus-article-mode-map [?z ?b] 'recenter-to-bottom) +(define-key gnus-article-mode-map [?z ?z] 'recenter-to-middle) +(define-key gnus-article-mode-map [?o] 'gnus-mime-inline-part) + +(setq gnus-article-sort-functions + '((not gnus-article-sort-by-number) + (not gnus-article-sort-by-date))) +(setq gnus-html-frame-width 80) +(setq gnus-inhibit-images nil) +(setq gnus-max-image-proportion 0.7) + +;;; Summary + +(setq gnus-auto-select-first nil) +(setq gnus-summary-ignore-duplicates t) +(setq gnus-suppress-duplicates t) +(setq gnus-summary-goto-unread 'never) +(setq gnus-summary-to-prefix "To: ") +(setq gnus-summary-line-format "%U%R%z %-16,16&user-date; %4L:%-30,30f %B%s\n") +(setq gnus-summary-mode-line-format "%p") +(setq gnus-summary-make-false-root 'adopt) +(setq gnus-sum-thread-tree-false-root "─┬> ") +(setq gnus-sum-thread-tree-indent " ") +(setq gnus-sum-thread-tree-leaf-with-other "├─> ") +(setq gnus-sum-thread-tree-root "") +(setq gnus-sum-thread-tree-single-leaf "└─> ") +(setq gnus-sum-thread-tree-vertical "│") +(setq gnus-summary-thread-gathering-function 'gnus-gather-threads-by-subject) diff --git a/ibuffer.el b/ibuffer.el new file mode 100644 index 0000000..2033bba --- /dev/null +++ b/ibuffer.el @@ -0,0 +1,56 @@ +;;; -*- lexical-binding: t; -*- + +(require 'ibuffer) +(require 'ibuf-ext) + +(setq ibuffer-expert t + ibuffer-display-summary nil) + +(setq ibuffer-show-empty-filter-groups nil) + +;;; a temporary binding + +(define-key global-map (vector 24 2) #'ibuffer) +(define-key global-map (vector ?\s-b) #'ibuffer) + +(define-key ibuffer-mode-map (vector ?d) #'ibuffer-do-delete) +(define-key ibuffer-mode-map (vector ?D) #'ibuffer-mark-for-delete) + +;;; filter for bongo + +;;;###autoload +(define-ibuffer-filter durand-bongo + "Group bongo buffers together." + (:description "Bongo buffers together" + :reader (read-string "no effect: ")) + (cond + ((not (boundp 'durand-bongo-music-dir)) + (load-config "bongo.el"))) + (with-current-buffer buf + (cond + ((derived-mode-p 'dired-mode) + (let ((bongo-dirs durand-bongo-music-dir) + found) + (while (and (not found) + (consp bongo-dirs)) + (cond + ((file-in-directory-p default-directory (car bongo-dirs)) + (setq found t)) + (t (setq bongo-dirs (cdr bongo-dirs))))) + found)) + ((derived-mode-p 'bongo-playlist-mode 'bongo-library-mode))))) + +;;;###autoload +(defun durand-bongo-set-filter () + "Set my custom filters." + (interactive) + (setq ibuffer-filter-groups + (cons (cons "Bongo" '((durand-bongo))) + ibuffer-filter-groups)) + (let ((ibuf (get-buffer "*Ibuffer*"))) + (when ibuf + (with-current-buffer ibuf + ;; (pop-to-buffer ibuf) + (ibuffer-update nil t))))) + +(add-hook 'ibuffer-hook 'durand-bongo-set-filter 100) @@ -22,7 +22,7 @@ "The directory to load files") ;;;###autoload -(defun load-config (file-name) +(defsubst load-config (file-name) "Conviently load configuration files in the same directory as this file." (load-file (expand-file-name file-name load-file-directory))) @@ -40,12 +40,105 @@ (load-config ,file)) (add-hook ',hook ',entry-name))) +;;;###autoload +(defmacro load-after-function (function-name file-path doc redefine-p &rest def) + "Load FILE-PATH after FUNCTION-NAME. +After loading, execute DEF. +Finally if REDEFINE-P is non-nil, +then FUNCTION-NAME will be defined as DEF after loading." + `(defun ,function-name () + ,doc + (interactive) + (load-config ,file-path) + ,@def + ,(cond + (redefine-p + `(defun ,function-name () + ,doc + (interactive) + ,@def))))) + +(load-config "common.el") + (load-config "basic.el") +(load-config "backup-conf.el") + +(load-config "recentf-conf.el") + +(load-config "dashboard.el") + (load-config "theme.el") (load-config "modeline.el") +(add-hook 'emacs-lisp-mode-hook + (lambda () (set 'mode-name "ELisp"))) + (prepare-in-hook-once prepare-elisp emacs-lisp-mode-hook "elisp.el") +(prepare-in-hook-once prepare-org org-mode-hook "org-conf.el") + +;;;###autoload +(load-after-function durand-mu4e "mail.el" "Open mu4e." t (mu4e)) + +(add-to-list 'auto-mode-alist (cons "pdf$" #'pdf-view-mode)) + +;;;###autoload +(load-after-function pdf-view-mode "pdf.el" "Fake mode that loads the pacakge." nil + (pdf-view-mode)) + +;;; bongo + +;;;###autoload +(load-after-function bongo "bongo.el" "Listen to music in Emacs." nil + (bongo)) + +;;; gnus + +(load-config "gnus-conf.el") + +;;; comb + +;; (load-config "comb/comb.el") +;; (load-config "comb/comb-annotation.el") + +;;; orderless + +;; TODO: Write my own completion styles library +(load-config "comb/orderless-conf.el") + +;;; dired configurations + +(prepare-in-hook-once prepare-dired dired-mode-hook "dired-conf.el") +(add-hook 'dired-mode-hook 'dired-hide-details-mode) + +;;; ibuffer + +(load-config "ibuffer.el") + +;;; center buffer + +(load-config "center-buffer.el") + +;;; tab configurations + +(load-config "tab-conf.el") + +;;; Save sessions + +(load-config "desktop-conf.el") + +;;; Text Configurations + +(prepare-in-hook-once prepare-text text-mode-hook "text-conf.el") + +;;; embark + +(load-config "embark-conf.el") + +;;; Don't let s-q quit as I oft press that by accident. + +(define-key global-map (vector ?\s-q) #'window-toggle-side-windows) + (setq gc-cons-threshold (* 2 1024 1024)) @@ -0,0 +1,108 @@ + +(use-package "/usr/local/share/emacs/site-lisp/mu/mu4e" 'mu4e + (setq mu4e-maildir-list (list "/Users/durand/mbsync")) + (setq user-mail-address "mmemmew@gmail.com") + (setq mu4e-completing-read-function #'completing-read) + (setq message-confirm-send t) + (setq mu4e~update-buffer-height 5) + + (setq mu4e-context-policy 'pick-first) + (setq mu4e-attachment-dir "~/Downloads") + (setq mu4e-mu-binary "/usr/local/bin/mu") + + (setq mu4e-view-use-gnus t) + (setq mu4e-confirm-quit nil) + (setq mu4e-get-mail-command "mbsync -a") ; mbsync works a lot better! + (setq mu4e-change-filenames-when-moving t) + (setq mu4e-view-show-addresses t) ; show full addresses! + (setq mu4e-view-show-images t) + (setq mu4e-sent-messages-behavior 'delete) + (setq mu4e-use-fancy-chars t) + (setq message-send-mail-function 'smtpmail-send-it + smtpmail-stream-type 'starttls + smtpmail-default-smtp-server "smtp.gmail.com" + smtpmail-smtp-server "smtp.gmail.com" + smtpmail-smtp-service 587) + + (define-key mu4e-main-mode-map (vector ?q) #'bury-buffer) + (define-key mu4e-main-mode-map (vector ?u) #'mu4e-update-mail-and-index) + + (add-to-list + 'mu4e-bookmarks + (make-mu4e-bookmark + :name "week no trash no archive" + :query "date:7d..now AND NOT maildir:/trash AND NOT maildir:/archive" + :key ?d)) + + (add-to-list + 'mu4e-bookmarks + (make-mu4e-bookmark + :name "week starred" + :query "date:7d..now AND maildir:/suivis" + :key ?s)) + + (setq mu4e-maildir-shortcuts + '(("/INBOX" . ?i) + ("/archive" . ?a) + ("/suivis" . ?s) + ("/drafts" . ?d))) + + (setq mu4e-contexts + (list + (make-mu4e-context + :name "Student" + :enter-func (lambda () (mu4e-message "Entering Student context")) + :leave-func (lambda () (mu4e-message "Leaving Student context")) + ;; we match based on the contact-fields of the message + :match-func + (lambda (msg) + (when msg + (or + (mu4e-message-contact-field-matches msg :from "tan\\|mlh\\|hsialc\\|tingyu.lee\\|tingyulee") + (mu4e-message-contact-field-matches msg :to "tan\\|mlh\\|hsialc\\|tingyu.lee\\|tingyulee")))) + :vars '((user-mail-address . "mmemmew@gmail.com") + (user-full-name . "李俊緯") + (mu4e-compose-signature . "生 俊緯") + (mu4e-sent-folder . "/gmail/sent") + (smtpmail-smtp-user . "mmemmew") + (smtpmail-local-domain . "gmail.com") + (smtpmail-default-smtp-server . "smtp.gmail.com") + (smtpmail-smtp-server . "smtp.gmail.com") + (smtpmail-smtp-service . 587))) + (make-mu4e-context + :name "NCTS" + :enter-func (lambda () (mu4e-message "Switch to the NCTS context")) + :leave-func (lambda () (mu4e-message "Leave NCTS context")) + ;; no leave-func + ;; we match based on the maildir of the message + ;; this matches maildir /Arkham and its sub-directories + :match-func (lambda (msg) + (when msg + (or + (mu4e-message-contact-field-matches msg :to "chunweilee@ncts.ntu.edu.tw") + (mu4e-message-contact-field-matches msg :from "chunweilee@ncts.ntu.edu.tw")))) + :vars '((user-mail-address . "chunweilee@ncts.ntu.edu.tw") + (user-full-name . "李俊緯") + (mu4e-compose-signature . + (concat + "Sincerely Yours,\n" + "俊緯")))) + (make-mu4e-context + :name "Durand" + :enter-func (lambda () (mu4e-message "Entering Durand context")) + :leave-func (lambda () (mu4e-message "Leaving Durand context")) + ;; we match based on the contact-fields of the message + :match-func (lambda (msg) + (when msg + (or + (mu4e-message-contact-field-matches msg :to "mmemmew@gmail.com") + (mu4e-message-contact-field-matches msg :from "mmemmew@gmail.com")))) + :vars '((user-mail-address . "mmemmew@gmail.com") + (user-full-name . "Durand") + (mu4e-compose-signature . "Sévère Durand") + (mu4e-sent-folder . "/gmail/sent") + (smtpmail-smtp-user . "mmemmew") + (smtpmail-local-domain . "gmail.com") + (smtpmail-default-smtp-server . "smtp.gmail.com") + (smtpmail-smtp-server . "smtp.gmail.com") + (smtpmail-smtp-service . 587)))))) diff --git a/modeline.el b/modeline.el index 3fce55c..7da967e 100644 --- a/modeline.el +++ b/modeline.el @@ -8,7 +8,7 @@ (left-len (length left)) (right-len (length right)) (middle (propertize " " 'display - (make-string (- (window-width) + (make-string (- (window-total-width) left-len right-len) 32)))) @@ -17,6 +17,15 @@ (setq-default mode-line-format '("%e" (:eval (modeline-format-main)))) ;;;###autoload +(defun modeline-format-dashboard () + "The mode line format for the dashboard." + (concat + (modeline-format-bar) + (modeline-spc) + (modeline-format-directory))) + + +;;;###autoload (defun modeline-format-left () "The left mode line format." (concat @@ -131,6 +140,20 @@ MAP is the local keymap of the text." ;;; Various sections of the mode line ;;;###autoload +(defun modeline-format-directory () + "Display the default directory on the mode line." + (modeline-propertize + (propertize + default-directory + 'face (cond ((modeline-active-window-p) 'mode-line) + (t 'mode-line-inactive))) + nil "The current directory\nmouse-1: Open that directory" + (let ((map '(keymap))) + (define-key map (vector 'mode-line 'down-mouse-1) + (lambda () (interactive) (dired default-directory))) + map))) + +;;;###autoload (defun modeline-spc () "A space with the appropriate face." (format-mode-line " " @@ -285,20 +308,42 @@ W is the width, H is the height of the bar." ;;;###autoload (defun modeline-format-position () "The position of the cursor to be displayed in the mode line." - (modeline-propertize - (format-mode-line - (concat "%l:%C " - (let ((orig (format-mode-line "%p"))) - (cond - ((memq (aref orig 0) (number-sequence 48 57)) - (concat orig "%%%")) - (t (substring orig 0 3))))) - (cond - ((modeline-active-window-p) 'mode-line) - (t 'mode-line-inactive))) - nil - "Buffer position\nmouse-1: Display Line and Column Mode Menu" - mode-line-column-line-number-mode-map)) + (cond + ((derived-mode-p 'pdf-view-mode) + (modeline-propertize + (propertize + (let ((current (pdf-view-current-page)) + (total (pdf-info-number-of-pages))) + (concat + "P." + (number-to-string current) + "/" + (number-to-string total))) + 'face (cond + ((modeline-active-window-p) 'mode-line) + (t 'mode-line-inactive))) + nil "Current page / Total pages")) + (t + (modeline-propertize + (propertize + (let* ((lc (format-mode-line "%l:%C ")) + (percent (format-mode-line "%p"))) + (concat + lc + (cond + ((eq (aref percent 0) 32) + (concat (substring percent 1) "%")) + ((memq (aref percent 0) (number-sequence 48 57)) + (concat percent "%")) + ((> (length percent) 3) + (substring percent 0 3)) + (t percent)))) + 'face (cond + ((modeline-active-window-p) 'mode-line) + (t 'mode-line-inactive))) + nil + "Buffer position\nmouse-1: Display Line and Column Mode Menu" + mode-line-column-line-number-mode-map)))) ;;;###autoload (defun modeline-format-buffer-size () @@ -329,36 +374,39 @@ W is the width, H is the height of the bar." This will be displayed in the mode line." (declare (pure t) (side-effect-free t)) (modeline-propertize - (let ((orig - (format-mode-line - "%b" (cond ((modeline-active-window-p) - 'mode-line-buffer-id) - (t 'mode-line-inactive))))) - (cond - ((> (length orig) modeline-buffer-name-len-max) - (concat - (substring orig 0 (- modeline-buffer-name-len-max 3)) - "...")) - (t orig))) + (let* ((face (cond ((modeline-active-window-p) 'mode-line-buffer-id) + (t 'mode-line-inactive))) + (orig (format-mode-line "%b" face))) + (concat + (format-mode-line "%[" face) + (cond + ((> (length orig) modeline-buffer-name-len-max) + (concat + (substring orig 0 (- modeline-buffer-name-len-max 3)) + "...")) + (t orig)) + (format-mode-line "%]" face))) nil (concat (buffer-file-name) - "\n" - "mouse-1: ibuffer") + "\n" + "mouse-1: ibuffer") mode-line-buffer-identification-keymap)) ;;;###autoload (defun modeline-format-major-mode () "The major mode to display in the mode line." (declare (pure t) (side-effect-free t)) - (modeline-propertize - (format-mode-line - "%m" - (cond ((modeline-active-window-p) - 'doom-modeline-buffer-major-mode) - (t 'mode-line-inactive))) - nil - "Major mode\nmouse-1: Display major mode menu\nmouse-2: Show help for major mode\nmouse-3: Toggle minor modes" - mode-line-major-mode-keymap)) + (concat + (modeline-propertize + (format-mode-line + "%m" + (cond ((modeline-active-window-p) + 'doom-modeline-buffer-major-mode) + (t 'mode-line-inactive))) + nil + "Major mode\nmouse-1: Display major mode menu\nmouse-2: Show help for major mode\nmouse-3: Toggle minor modes" + mode-line-major-mode-keymap) + (modeline-spc))) ;;;###autoload (defvar-local modeline-vcs-str "" @@ -420,16 +468,15 @@ This will be displayed in the mode line." ;;;###autoload (defun modeline-format-vc-mode () "Display version control system information on the mode line." - (declare (pure t) (side-effect-free t)) + (declare (pure t) (side-effect-free 'error-free)) (cond ((and (stringp modeline-vcs-str) (not (string= modeline-vcs-str ""))) (concat - (modeline-spc) + ;; (modeline-spc) (modeline-propertize (cond - ((modeline-active-window-p) - modeline-vcs-str) + ((modeline-active-window-p) modeline-vcs-str) (t (propertize modeline-vcs-str 'face 'mode-line-inactive))) nil (get-text-property 1 'help-echo vc-mode) diff --git a/modes/Concepts.txt b/modes/Concepts.txt new file mode 100644 index 0000000..e9cfac4 --- /dev/null +++ b/modes/Concepts.txt @@ -0,0 +1,298 @@ +Title: Concepts and designs of modes +Author: JSDurand +Created: 2021-01-01 +------------------------------------- + +====================================================================== + Introduction +====================================================================== + +In this document, and in this document only, sometimes we refer to +Emacs as "the editor", though the situations referred to are +definitely different from those of other editors, and the editor Emacs +does not represent other editors in any way. This reference is solely +out of personal preferences. + +When we edit texts through a text editor, since there are a lot of +functionalities we would like to perform in the editor, we oft end up +with binding many keys with various functions in the editor. This +causes a problem: the keys are either too long to conveniently press +or too compactly packaged that it requires experience to remember and +use them at ease (what if we can execute the form “(require +'experience)” in Emacs ;P). + +The proposed way in this document to solve this dilemma is to make +keys behave according to the "contexts" of the editor. That is to say, +we are using the same key to perform such different tasks as to switch +buffers, to select different windows, and even to pop up a different +mail to read. + +To be honest, there is nothing new in this idea: it is the core idea +of the so-called "modal editing". And there are numerous packages that +implement similar ideas in Emacs already, such as evil, god-mode, or +even viper, just to name a few. + +The difference of my implementation with other packages is that I +would like to first push this idea to a more general level, before +specialising to some specific states. In other words, the modes should +reflect more dedicated states of the editor and the current task I am +performing. More precisely, when I am trying to switch buffers, I +shall be in a "buffer mode", that permits me to switch buffers just by +arrow keys, or whatever keys I have chosen for the concepts of "up" +and "down". Moreover, the concepts include not only four directions +but also "previous" and "next", whose functions are to switch to the +previously used and the next-to-be-used buffer respectively. + +Simply put, a mode is nothing but a correspondence from concepts to +functions. And the user should decide how to map these concepts to +keys. + +Then this document tries to record the modes that I accumulated +through the use of the editor. + + + +====================================================================== + Analogy with the languages +====================================================================== + +If we view pressing keys as the user speaking to the computer, then +these keypresses of a user form a "language", in a formal sense. The +letters are the keys on the keyboard (so each user has a potentially +different set of letters), and the words are valid key sequences, as +per the Emacs parlance. For example, in the built-in language of +Emacs, the word "C-x 4 d" means to open a directory in another window. + +There are some characteristics of this kind of languages. The most +obvious characteristics is that the verbs are all in one of two +"moods" (this term comes from Latin grammar if my memory serves me): +imperative and interrogative, since this language serves the only +purpose for the user to give the computer commands, or to query some +states. + +Another characteristics is that, there are a myriad of "tenses", +"conjugations" and "declensions". These refer to the fact that a key's +meaning depends upon the contexts. So we can view "C-x 4 d" as a +conjugation of the verb "C-x d", which is to open a directory in the +current window. + +However, as one of the reasons that the Sanskrit language is deemed +not easy to learn is that it has numerous declensions, conjugations, +liaisons, and irregularities, the same thing happens with the +key-binding language. If a key-binding language has too many tenses +and irregularities, then it is difficult to remember, to use, and to +"speak". And, from my point of view, the built-in key-binding language +of the editor is too difficult to use, however logical the design of +that language may be. + +The aim of this document is thus to solve this problem, for me and for +me only, at the same time laying some foundation upon which others may +build their own languages to solve their own problems, in the future. + + + +====================================================================== + The solution in terms of the analogy with the languages +====================================================================== + +So what does our solution mean in terms of the above analogy with the +languages? I think this is the difference between the agglutinative +languages and analytical languages. + +According to Wikipedia, "an agglutinative language is a type of +synthetic languages with morphology that primarily uses +agglutination." And agglutination is "a linguistic process pertaining +to derivational morphology in which complex words are formed by +stringing together morphemes without changing them in spelling or +phonetics." + +Basically, this is one of the characteristics of the default Emacs +language: concatenating affixes after affixes, or prefixes. + +Again according to Wikipedia, "an analytic language is a language that +primarily conveys relationships between words in sentences by way of +helper words (particles, prepositions, etc.) and word order, as +opposed to using inflections (changing the form of a word to convey +its role in the sentence)." + +In our contexts, this means we use helper words (key sequences) to +alter the meanings of keys. In addition, it is also a common oral +practice to use "persistent" contexts. For example, (I don't know +about English, so here I refer to the situation with my mother tongue +Chinese), when telling a story, after one declares this happened in +the past, we can safely use verbs without tenses and expect that the +listener understands this is a past action. Hence the effect I want to +achieve is that we can expect the editor to understand that after we +changed our contexts, the keys have a different meaning now. + + + +====================================================================== + Major modes and minor modes +====================================================================== + +One might wonder why I don't just use Emacs' built-in major modes and +minor modes, as those sound like a generalization of the ideas of +modes already. In this regard, I really think my idea of modes is just +like a minor mode, in that it is not directly relateed to the file or +the buffer being operated on. Rather it concerns the intention of the +user. And in effect we can implement the modes as depicted above using +nothing but major and minor modes. + +There is a problem though: the minor modes control the keymaps through +the variable "minor-mode-map-alist". It is a plain association list +that associates minor-mode symbols to keymaps. Wheneven the minor-mode +symbol has a non-nil value, the associated keymaps is in effect. +However, the order of priority for these maps is the same as the order +of appearance in this association list. This means we might sometimes +get unpredictable results when we try to activate certain functions in +our modes. Therefore, to avoid this problem, I decided to avail of a +higher-priority map, namely "emulation-mode-map-alists". And it +functions in the same way as the former. + + + +====================================================================== + General concepts +====================================================================== + +Some concepts are in a sense "universal" to all modes. These are the +concepts that don't concern with the specific functionalities of +modes, but rather with the abstract notion of modes. + +quit - Quit a mode, and nothing else. +quit & bury - Quit a mode and bury the current buffer. +quit & quit - Quit a mode and quit the selected window. +quit & kill - Quit a mode and kill the current buffer. + + + +====================================================================== + Buffer mode +====================================================================== + +The first mode that I desire is a mode that operates on the buffers. +As Protesilaos Stavrou rightly observed, the true power of Emacs lies +in its handling of the buffers, since this frees the limited screen +estate and leverages the power of the computer to manage the editing +resources. So naturally there are a lot of operations related to +buffers that are quite useful to us. Below is a list of the +correspondence between concepts and functions that I can think of. + +up - The previous buffer in the list of buffers. +down - The next buffer in the list of buffers. +previous - The previously used buffer. +next - The next-to-be-used buffer. + In practice this means the buffers that the user left by + going to the previous buffer. +jump/show - Either use the completion framework to select a buffer + or display an interactive list of buffers, i.e. ibuffer. + This can first call ibuffer, and the second call uses + the completion framework. +last - Whether this deserves an independent concept is still + debatable. This just switches to the last used buffer. If + called repeatedly, it switches between two buffers. +save - Save a buffer. + I am used to frequently save buffers, so it is important + to access this conveniently. +kill - Kill and save a buffer. +delete - Simply kill a buffer. +rename - Rename a buffer. +search - Search through a buffer. + + + +====================================================================== + Window mode +====================================================================== + + +To be honest I don't believe I really need to manage windows. Rather I +would like Emacs to automatically handle the windows the way I want. +But since it is too difficult to guess my mind, this mode is still +relevant. + +up - Go up a window. +down - Go down a window. +left - Go left a window. +right - Go right a window. +jump/show - Use the completion framework to choose a window to go to. + It might make sense to have a buffer list all windows that + I can jump to, just like an "iwindow". +save - Save a window configuration. +load - Load a window configuration. +delete - Kill a window. + + + +====================================================================== + Help mode +====================================================================== + +The idea is to make the help system behave more conveniently. For +example, currently if the user opens a file thruogh the help system, +then the user is put in the major mode corresponding to that file. I +think it might be more convenient if the user is still in the help +mode. When and only when the user chooses to exit the help mode, +should the user be put in the major mode corresponding to that file. + +up - Scroll "down". +down - Scroll "up". +previous - Go to the previous help buffer. +next - Go to the next help buffer. +search - Searching through the help buffer is also important. + + + +====================================================================== + Selection mode +====================================================================== + +I haven't decided yet whether this should be a separate mode or just a +concept for other different modes that turn the current "object" into +a selection. + + + +====================================================================== + View mode, or the screen mode +====================================================================== + +This mode of Emacs really surprised me when I first learned about its +existence. It hinted at endless possibilities, in some sense. But it +does not fully meet my expectations. + +I view document frequently. I believe that writing is a reflection of +thinking, and while I am thinking, I like to scroll through the +document to answer such questions as what have I written, does the +current writing follow the outline or the sketch in my mind, do the +writings hint at some directions that I didn't notice before I wrote +them down, and the rest. Consequently, it is am important part of my +editing activity to view the documents. + +Since my screen is limited, the occassion occurs frequently that I +need to scroll the document to view some parts of it. In addition, I +like to highlight things, so it is equally important to easily select +or highlight arbitrary things on the screen. Thus my primary focus in +viewing documents are scrolling, positioning the cursor, highlighting, +and (re)centering the buffer. + +To be more precise, I would like the directional concepts to be +directly (no pun intended) related to the scrolling of the documents; +this covers eight directional concepts (up, down, left, right, and +their "maximal" versions). + +In addition to the above, I would also like to have special "concepts" +to go to the top, the middle, and the bottom of the screen. + +Lastly, about the jump/show concept I shall talk a little. I used to +love the package "avy", which permits the user to jump to anywhere on +the screen by matching either a line, a character, or any character +sequence the user inputs. Upon further reflection, however, I do not +find anything this package offers that a plain old "interactive +search" does not offer. + +By the way, instead of the name "view mode" it would probably be +better to call it "screen mode", since it concerns the screens. And to +view is a verb, not a state of the editor; after all, we are always +viewing something on the editor, unless it crashes. diff --git a/modes/modes.el b/modes/modes.el new file mode 100644 index 0000000..538ab93 --- /dev/null +++ b/modes/modes.el @@ -0,0 +1,97 @@ +;;; A modal interface + +;;; Dictionary + +;; ;;;###autoload +;; (defvar modes-concepts +;; (list 'down 'up 'left 'right 'next 'previous +;; 'down-max 'up-max 'left-max 'right-max 'next-max 'previous-max +;; 'jump) +;; "The concepts that a mode can define.") + + +;;;###autoload +(defvar modes-concept-keymap + (list + (cons 'down '(?j down)) + (cons 'up '(?k up)) + (cons 'right '(?l right)) + (cons 'left '(?h left)) + (cons 'forward ?n) + (cons 'backward ?p) + (cons 'down-max '([?J] S-down)) + (cons 'up-max '([?K] S-up)) + (cons 'right-max '([?L] S-right)) + (cons 'left-max '([?H] S-left)) + (cons 'forwrad-max ?N) + (cons 'backward-max ?P) + (cons 'jump 'tab) + (cons 'other ?o) + (cons 'undo ?u) + (cons 'redo ?U)) + "An alist that maps concepts to keys.") + +;;;###autoload +(defvar modes-map-alist (cons (cons 'modes-mode '(keymap "Modes alist")) nil) + "The current mode map.") + +(push 'modes-map-alist emulation-mode-map-alists) + +;;;###autoload +(define-minor-mode modes-mode "A modal interface" nil "Modes" nil :global t) + +;;;###autoload +(defun modes-process-key (key) + "Process keys appropriately. +The return value is a list of keys acceptable by `define-key'." + (cond + ((stringp key) (list (kbd key))) + ((vectorp key) (list key)) + ((or (symbolp key) (integerp key)) (list (vector key))) + ((listp key) + (mapcar (lambda (k) + (cond + ((stringp k) (kbd k)) + ((vectorp k) k) + ((integerp k) (vector k)) + ((symbolp k) (vector k)) + (t (user-error "Unsupported key: %S" k)))) + key)) + (t (user-error "Unsupported key: %S" key)))) + +;;;###autoload +(defun modes-set-mode (alist) + "Set a mode. +A mode is just an ALIST between concepts and functions." + (let ((map (cons 'keymap "Modes"))) + (dolist (concept-to-function alist) + (let* ((key (or + (alist-get (car concept-to-function) + modes-concept-keymap) + (error "Unsupported concept: %S" (car concept-to-function)))) + (keys (modes-process-key key)) + (fun (cdr concept-to-function))) + (mapc (lambda (k) (define-key map k fun)) keys))) + (set 'modes-map-alist (list (cons 'modes-mode map))))) + +;;; Modes + +;;; buffer mode + +(defun switch-to-last-buffer () + "Switch to the last buffer." + (interactive) + (switch-to-buffer (other-buffer))) + +(set 'modes-buffer-mode + '((down . next-buffer) + (up . previous-buffer) + (other . switch-to-last-buffer) + (jump . ibuffer))) + + + + + + + diff --git a/org-conf.el b/org-conf.el new file mode 100644 index 0000000..e978e22 --- /dev/null +++ b/org-conf.el @@ -0,0 +1,309 @@ +;;; -*- lexical-binding: t; -*- + +(setq org-latex-packages-alist '(("" "amsfonts" t)) + org-format-latex-options (plist-put org-format-latex-options :scale 1.5)) + + +;; tempo + +(require 'org-tempo) + +(add-to-list 'org-structure-template-alist (cons "g" "src durand-greek")) +(add-to-list 'org-structure-template-alist (cons "el" "src emacs-lisp")) +(add-to-list 'org-modules 'ol-gnus) + +;;; TODO: To finish this configuration file... + +;;; Some variables + +(setq org-todo-keywords + '((sequence "TODO(t)" "START(s)" "WORKING(w)" "HARD-WORKING(h)" "ALMOST(a)" "|" "DONE(d)") + (sequence "TO-THINK(c)" "PENDING(p)" "HARD(r)" "IMPOSSIBLE(i)" "|" "SOLVED(v)")) + org-tags-column -110 + org-hide-emphasis-markers t + org-special-ctrl-a/e nil + org-highlight-latex-and-related '(native latex script entities) + org-agenda-files (mapcar (lambda (fn) (expand-file-name fn org-directory)) + (list "notes.org" + "agenda.org" + "aujourdhui.org" + "math_article_links.org")) + org-log-into-drawer t + org-highest-priority ?A + org-lowest-priority ?E + org-default-priority ?B + org-pretty-entities t + org-link-file-path-type 'noabbrev + + ) + +;;; open link functions + +(dolist (scheme '("ftp" "http" "https" "mailto" "news")) + (org-link-set-parameters scheme + :follow + (lambda (url &optional arg) + (browse-url (concat scheme ":" url) arg)))) + +(use-package "tablist" 'tablist) +(load-config "org-pdftools.el") +(set 'org-pdftools-link-prefix "pdfview") +(org-pdftools-setup-link) + +;;; Archive advice + +;;;###autoload +(defun durand-archive-save-and-kill (old-fun &optional find-done) + "Save and kill the buffer after archiving." + (let* ((location (org-archive--compute-location + (or (org-entry-get nil "ARCHIVE" 'inherit) + org-archive-location))) + (archive-buffer-name (file-name-nondirectory (car location))) + (opened (get-buffer archive-buffer-name))) + (funcall old-fun find-done) + (unless opened + (when (get-buffer archive-buffer-name) + (with-current-buffer archive-buffer-name + (ignore-errors (save-buffer 0))) + (kill-buffer archive-buffer-name))))) + +(advice-add 'org-archive-subtree :around 'durand-archive-save-and-kill) + +;;; Archiving + +;;;###autoload +(defun durand-org-archive-file-name (file-name) + "Produce an archive file name. +The rule is as follows: +example.org +example.org_archive +example(1).org_archive +example(2).org_archive +etc." + (cond + ((not (or (string-match "org$" file-name) + (string-match "org_archive$" file-name))) + (user-error "Not an org file."))) + (cond + ((string-match "org$" file-name) + (replace-match "org_archive" nil nil file-name)) + ((string-match "\\((\\([[:digit:]]+\\))\\).org_archive$" file-name) + (replace-match + (format "(%d)" + (1+ (string-to-number + (match-string-no-properties 2 file-name)))) + nil nil file-name 1)) + (t + (replace-regexp-in-string ".org_archive$" "(1).org_archive" file-name)))) + +;;;###autoload +(defun durand-org-goto-archive () + "Go to the archive file of the current org file, if any. +It will cycle through all archive files of the file. +The rule is as follows: +example.org +example.org_archive +example(1).org_archive +example(2).org_archive +etc." + (interactive) + (unless (derived-mode-p 'org-mode) + (user-error "Not in an org file.")) + (let* ((current-name (buffer-file-name (current-buffer))) + (base-name (cond + ((string-match "org_archive$" current-name) + (replace-match "org" nil nil current-name)) + (t current-name))) + (base-name (cond + ((string-match "\\(([[:digit:]])\\).org$" base-name) + (replace-match "" nil nil base-name 1)) + (t base-name))) + (next-name (durand-org-archive-file-name current-name)) + (next-name (cond + ((file-exists-p next-name) next-name) + (t base-name)))) + (find-file next-name))) + +;; NOTE: Modified by Durand to use `completing-read-multiple' instead of +;; `completing-read'. +;;;###autoload +(defun durand-org-set-tags-command (&optional arg) + "Set the tags for the current visible entry. + +When called with `\\[universal-argument]' prefix argument ARG, \ +realign all tags +in the current buffer. + +When called with `\\[universal-argument] \\[universal-argument]' prefix argument, \ +unconditionally do not +offer the fast tag selection interface. + +If a region is active, set tags in the region according to the +setting of `org-loop-over-headlines-in-active-region'. + +This function is for interactive use only; +in Lisp code use `org-set-tags' instead." + (interactive "P") + (let ((org-use-fast-tag-selection + (unless (equal '(16) arg) org-use-fast-tag-selection))) + (cond + ((equal '(4) arg) (org-align-tags t)) + ((and (org-region-active-p) org-loop-over-headlines-in-active-region) + (let (org-loop-over-headlines-in-active-region) ; hint: infinite recursion. + (org-map-entries + #'org-set-tags-command + nil + (if (eq org-loop-over-headlines-in-active-region 'start-level) + 'region-start-level + 'region) + (lambda () (when (org-invisible-p) (org-end-of-subtree nil t)))))) + (t + (save-excursion + (org-back-to-heading) + (let* ((all-tags (org-get-tags)) + (table (setq org-last-tags-completion-table + (org--tag-add-to-alist + (and org-complete-tags-always-offer-all-agenda-tags + (org-global-tags-completion-table + (org-agenda-files))) + (or org-current-tag-alist (org-get-buffer-tags))))) + (current-tags + (cl-remove-if (lambda (tag) (get-text-property 0 'inherited tag)) + all-tags)) + (inherited-tags + (cl-remove-if-not (lambda (tag) (get-text-property 0 'inherited tag)) + all-tags)) + (tags + (replace-regexp-in-string + ;; Ignore all forbidden characters in tags. + "[^[:alnum:]_@#%]+" ":" + (if (or (eq t org-use-fast-tag-selection) + (and org-use-fast-tag-selection + (delq nil (mapcar #'cdr table)))) + (org-fast-tag-selection + current-tags + inherited-tags + table + (and org-fast-tag-selection-include-todo org-todo-key-alist)) + (let ((org-add-colon-after-tag-completion (< 1 (length table)))) + ;; I change this part + (org-trim + (org-make-tag-string + (completing-read-multiple + "Tags: " + #'org-tags-completion-function + nil nil (replace-regexp-in-string + ":" "," + (org-make-tag-string current-tags)) + 'org-tags-history)))))))) + (org-set-tags tags))))) + ;; `save-excursion' may not replace the point at the right + ;; position. + (when (and (save-excursion (skip-chars-backward "*") (bolp)) + (looking-at-p " ")) + (forward-char)))) + +(advice-add 'org-set-tags-command :override 'durand-org-set-tags-command) + +;;; Accounts + +;;;###autoload +(defvar durand-org-capture-account-which-list + '("breakfast" "brunch" "brunverage" "lunch" "dinner" "beverage" "snack" "fruit") + "The list of purposes of accounts in the capture-template for accounting.") + +;;;###autoload +(defun durand-org-capture-account-template () + "Org capture template for account." + (let* ((shop-and-items (durand-org-complete-capture-account)) + (which (completing-read + "For what? " + durand-org-capture-account-which-list)) + (cost (number-to-string + (read-number "Cost: " 0))) + (from (completing-read "From: " '("Cash" "etique"))) + (active-time (format-time-string + (cdr org-time-stamp-formats))) + (inactive-time + (let ((temp active-time)) + (while (string-match "<\\|>" temp) + (setf temp + (replace-match + (cond + ((string= (match-string-no-properties 0 temp) "<") "[") + ((string= (match-string-no-properties 0 temp) ">") "]")) + nil nil temp))) + temp))) + (format "%s\n :PROPERTIES:\n :cost: %s\n :FROM: %s\n :RECORD_TIME: %s\n :END: \n %s%%?" + which cost from inactive-time shop-and-items))) + +(setq org-capture-templates + '(("g" "GNUS" entry + (file "~/org/notes.org") + "* TO-THINK %:subject\n :PROPERTIES:\n :RECORD_TIME: %U\n :END:\n %:from\n %:to\n %a\n %?" + :empty-lines 1 + :kill-buffer t))) + +(setq org-capture-templates-contexts + '(("g" ((in-mode . "gnus-summary-mode") + (in-mode . "gnus-article-mode"))))) + +(setq org-agenda-custom-commands + '(("o" "Custom" + ((agenda "" + (;; (org-super-agenda-groups + ;; '((:name "Progress today" + ;; :log t + ;; :order -1) + ;; (:name "Morning Tasks" + ;; :log t + ;; :tag "morning" + ;; :order 1) + ;; (:name "Afternoon Taks" + ;; :log t + ;; :tag "afternoon" + ;; :order 2) + ;; (:name "Night Taks" + ;; :log t + ;; :tag "night" + ;; :order 3) + ;; (:name "Deadlines" :deadline t) + ;; (:name "Health" + ;; :tag "santé" + ;; :log t + ;; :order 5) + ;; (:name "MATH" + ;; :tag "math" + ;; :order -1) + ;; (:name "Très Important" + ;; :priority "A" + ;; :order -1) + ;; (:name "Scheduled" + ;; :and (:scheduled t :not (:priority "A")) + ;; :order 5 + ;; :log t))) + (org-agenda-span 'day) + (org-agenda-sorting-strategy '(priority-down time-up)))) + ;; NOTE: A reading plan + (tags "a_voir+matin|a_voir+après_midi|a_voir+nuit" + ((org-agenda-files '("~/org/notes.org" + "~/org/math_article_links.org")) + (org-agenda-overriding-header "À Lire") + ;; (org-super-agenda-groups + ;; '((:name "Le Matin" :tag "matin") + ;; (:name "L'après-midi" :tag "après_midi") + ;; (:name "La Nuit" :tag "nuit"))) + )) + (todo "TO-THINK" + (;; (org-super-agenda-groups + ;; '((:name "À Voir" :tag "a_voir") + ;; (:name "Mathématiques" :tag "math") + ;; (:name "TeX" :tag "tex") + ;; (:name "Question" :tag "question"))) + (org-agenda-overriding-header "TO-THINK")))) + ((org-agenda-block-separator nil))) + ;; ("n" "test" + ;; ((durand-agenda-command-test))) + ;; ("m" "sections with time" + ;; ((durand-agenda-command-sections-time))) + )) diff --git a/org-pdftools.el b/org-pdftools.el new file mode 100644 index 0000000..9189803 --- /dev/null +++ b/org-pdftools.el @@ -0,0 +1,403 @@ +;;; org-pdftools.el --- Support for links to documents in pdfview mode -*- lexical-binding: t; -*- +;; Copyright (C) 2020 Alexander Fu Xi + +;; Author: Alexander Fu Xi <fuxialexander@gmail.com> +;; Maintainer: Alexander Fu Xi <fuxialexnader@gmail.com> +;; Homepage: https://github.com/fuxialexander/org-pdftools +;; Version: 1.0 +;; Keywords: convenience +;; Package-Requires: ((emacs "26.1") (org "9.3.6") (pdf-tools "0.8") (org-noter "1.4.1")) + +;; 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: +;; Add support for org links from pdftools buffers with more precise location control. +;; +;; https://github.com/fuxialexander/org-pdftools/ + + +;;; Code: +(require 'subr-x) +(require 'cl-lib) +(require 'org) +(require 'org-refile nil t) +;; (require 'org-noter) +(load-config "pdf.el") +(require 'pdf-tools) +(require 'pdf-view) +(require 'pdf-annot) +(require 'pdf-occur) + +(defgroup org-pdftools nil + "Tools for adding pdftools link support in Org mode." + :group 'tools) + +(defcustom org-pdftools-get-desc-function #'org-pdftools-get-desc-default + "A function that takes 3 arguments and output a link description. +- `file': basename of the PDF file +- `page': current page number converted to string +- `text' (should have optional tag): additional text infomation like highlighted text or isearch string. +See `org-pdftools-get-desc-default' as an example." + + :group 'org-pdftools + :type 'function) +(defcustom org-pdftools-path-generator #'abbreviate-file-name +"Translate your PDF file path the way you like. Take buffer-file-name as the argument." + :group 'org-pdftools + :type 'function) +(defcustom org-pdftools-path-resolver #'expand-file-name +"Resolve your translated PDF file path back to an absolute path." + :group 'org-pdftools + :type 'function) +(defcustom org-pdftools-open-custom-open nil + "Custom function to open linked pdf files." + :group 'org-pdftools + :type '(choice function nil)) +(defcustom org-pdftools-export-style 'pdftools + "Export style of org-pdftools links. +- pdftools :: export the link as is +- protocol :: export the link as a org-protocal link such that it could open pdf-tools when clicked +" + :group 'org-pdftools + :type 'symbol) +(defcustom org-pdftools-markup-pointer-function 'pdf-annot-add-underline-markup-annotation + "Color for markup pointer annotations. +Can be one of highlight/underline/strikeout/squiggly." + :group 'org-pdftools + :type 'function) +(defcustom org-pdftools-markup-pointer-color "#A9A9A9" + "Color for markup pointer annotations." + :group 'org-pdftools + :type 'string) +(defcustom org-pdftools-markup-pointer-opacity 1.0 + "Opacity for markup pointer annotations." + :group 'org-pdftools + :type 'float) +(defcustom org-pdftools-free-pointer-icon "Circle" + "Color for free pointer annotations. Refer to `pdf-annot-standard-text-icons`." + :group 'org-pdftools + :type 'string) +(defcustom org-pdftools-link-prefix "pdf" + "Prefix for org-pdftools link" + :group 'org-pdftools + :type 'string) +(defcustom org-pdftools-search-string-separator "??" + "Separator of search-string." + :group 'org-pdftools + :type 'string) +(defcustom org-pdftools-free-pointer-color "#FFFFFF" + "Color for free pointer annotations." + :group 'org-pdftools + :type 'string) +(defcustom org-pdftools-free-pointer-opacity 1.0 + "Opacity for free pointer annotations." + :group 'org-pdftools + :type 'float) + + +;; pdf://path::page++height_percent;;annot_id??isearch_string or @@occur_search_string +(defun org-pdftools-open-pdftools (link) + "Internal function to open org-pdftools LINK." + (let ((link-regexp + (concat "\\(.*\\)::\\([0-9]*\\)\\(\\+\\+\\)?\\([[0-9]\\.*[0-9]*\\)?\\(;;\\|" + (regexp-quote org-pdftools-search-string-separator) + "\\)?\\(.*\\)"))) + (cond ((string-match link-regexp link) + (let ((path (match-string 1 link)) + (page (match-string 2 link)) + (height (match-string 4 link)) + annot-id + search-string) + (cond ((string-equal + (match-string 5 link) + ";;") + (setq annot-id + (match-string 6 link))) + ((string-equal + (match-string 5 link) + org-pdftools-search-string-separator) + (setq search-string + (replace-regexp-in-string + "%20" + " " + (match-string 6 link))))) + (when (and path + (not (string-empty-p path))) + (if (bound-and-true-p org-noter--session) + (org-noter--with-valid-session + (let ((doc (with-selected-window + (org-noter--get-doc-window) + buffer-file-name)) + (fullpath (funcall org-pdftools-path-resolver path))) + (if (string-equal doc fullpath) + (select-window + (org-noter--get-doc-window)) + (let ((org-link-frame-setup + (cl-acons 'file 'find-file-other-frame org-link-frame-setup))) + (org-open-file fullpath 1))))) + (org-open-file (funcall org-pdftools-path-resolver path) 1))) + (if (and page + (not (string-empty-p page))) + (progn + (setq page (string-to-number page)) + (if (bound-and-true-p org-noter--session) + (org-noter--with-valid-session + (with-selected-window + (org-noter--get-doc-window) + (pdf-view-goto-page page))) + (pdf-view-goto-page page))) + (setq page nil)) + (when (and height + (not (string-empty-p height))) + (if (bound-and-true-p org-noter--session) + (org-noter--with-valid-session + (with-selected-window + (org-noter--get-doc-window) + (image-set-window-vscroll + (round + (/ + (* + (string-to-number height) + (cdr (pdf-view-image-size))) + (frame-char-height)))))) + (image-set-window-vscroll + (round + (/ + (* + (string-to-number height) + (cdr (pdf-view-image-size))) + (frame-char-height)))))) + (when (and annot-id + (not (string-empty-p annot-id))) + (if (bound-and-true-p org-noter--session) + (org-noter--with-valid-session + (with-selected-window + (org-noter--get-doc-window) + (pdf-annot-show-annotation + (pdf-info-getannot annot-id) + t))) + (pdf-annot-show-annotation + (pdf-info-getannot annot-id) + t))) + (when (and search-string + (not (string-empty-p search-string))) + (if (bound-and-true-p org-noter--session) + (org-noter--with-valid-session + (with-selected-window + (org-noter--get-doc-window) + (isearch-mode t) + (isearch-yank-string search-string))) + (isearch-mode t) + (isearch-yank-string search-string))))) + ((string-match + "\\(.*\\)@@\\(.*\\)" + link) + (let* ((paths (match-string 1 link)) + (occur-search-string (match-string 2 link)) + (pathlist (split-string paths "%&%"))) + (pdf-occur-search + pathlist + occur-search-string))) + ((org-open-file link 1))))) + +(defun org-pdftools-get-link () + "Get link from the active pdf buffer." + (let* ((path + (with-current-buffer (current-buffer) + (funcall org-pdftools-path-generator (buffer-file-name)))) + (page (pdf-view-current-page)) + (annot-id (if (pdf-view-active-region-p) + (pdf-annot-get-id + (funcall + org-pdftools-markup-pointer-function + (pdf-view-active-region t) + org-pdftools-markup-pointer-color + `((opacity . ,org-pdftools-markup-pointer-opacity)))) + (if (and (not (bound-and-true-p org-noter--session)) + (pdf-annot-getannots page)) + (condition-case nil + (pdf-annot-get-id + (pdf-annot-read-annotation + "Click the annotation that you want to link to.")) + (error + (if (y-or-n-p + "You can click anywhere on the page to add a link to. Do you want to do that? ") + (pdf-annot-get-id + (funcall-interactively + #'pdf-annot-add-text-annotation + (pdf-util-read-image-position + "Click where a new text annotation should be added ...") + org-pdftools-free-pointer-icon + `((color . ,org-pdftools-free-pointer-color) + (opacity . ,org-pdftools-free-pointer-opacity)))) + nil))) + (if (y-or-n-p + "You can click anywhere on the page to add a link to. Do you want to do that? ") + (pdf-annot-get-id + (funcall-interactively + #'pdf-annot-add-text-annotation + (pdf-util-read-image-position + "Click where a new text annotation should be added ...") + org-pdftools-free-pointer-icon + `((color . ,org-pdftools-free-pointer-color) + (opacity . ,org-pdftools-free-pointer-opacity)))) + nil)))) + (height (cond ((bound-and-true-p annot-id) + (nth 1 (pdf-annot-get + (pdf-info-getannot + annot-id + path) + 'edges))) + (t + (/ + (* + (or (image-mode-window-get + 'vscroll) + 0) + (frame-char-height)) + (float + (cdr (pdf-view-image-size))))))) + ;; pdf://path::page++height_percent;;annot_id\\|??search-string + (search-string (if (and (not annot-id) + (y-or-n-p + "Do you want to add a isearch link? ")) + isearch-string + "")) + (link (concat + + org-pdftools-link-prefix ":" + path + "::" + (number-to-string page) + "++" + (format "%.2f" height) + (if annot-id + (concat + ";;" + (symbol-name annot-id)) + (if (not (string-empty-p search-string)) + (concat + org-pdftools-search-string-separator + (replace-regexp-in-string + " " + "%20" + search-string)) + (message + " Reminder: You haven't performed a isearch!") ""))))) + link)) + +(defun org-pdftools-get-desc-default (file page &optional text) + (concat file ".pdf: Page " page (when text (concat "; Quoting: " text)))) + +;;;###autoload +(defun org-pdftools-open (link) + "Function to open org-pdftools LINK." + (if (and (display-graphic-p) + (featurep 'pdf-tools)) + (org-pdftools-open-pdftools + link) + (if (bound-and-true-p org-pdftools-open-custom-open) + (funcall org-pdftools-open-custom-open link) + (let* ((path (when (string-match + "\\(.+\\)::.+" link) + (match-string 1 link)))) + (org-open-file path))))) + +;;;###autoload +(defun org-pdftools-store-link () + "Store a link to a pdfview/pdfoccur buffer." + (cond ((eq major-mode 'pdf-view-mode) + ;; This buffer is in pdf-view-mode + (let* ((file (file-name-base (pdf-view-buffer-file-name))) + (quot (if (pdf-view-active-region-p) + (replace-regexp-in-string "\n" " " + (mapconcat 'identity (pdf-view-active-region-text) ? )))) + (page (number-to-string (pdf-view-current-page))) + (link (org-pdftools-get-link)) + (isearchstr (if (string-match (concat ".*" (regexp-quote org-pdftools-search-string-separator) "\\(.*\\)") link) + (match-string 1 link))) + (desc (funcall org-pdftools-get-desc-function file page (or quot isearchstr)))) + (org-link-store-props + :type org-pdftools-link-prefix + :link link + :description desc))) + ((eq major-mode 'pdf-occur-buffer-mode) + (let* ((paths (mapconcat #'identity (mapcar #'car + pdf-occur-search-documents) "%&%")) + (occur-search-string pdf-occur-search-string) + (link (concat org-pdftools-link-prefix ":" + paths "@@" occur-search-string))) + (org-link-store-props + :type org-pdftools-link-prefix + :link link + :description (concat "Search: " occur-search-string)))))) + +;;;###autoload +(defun org-pdftools-export (link description format) + "Export the pdfview LINK with DESCRIPTION for FORMAT from Org files." + (let* (path loc page) + (if (string-match "\\(.+\\)::\\(.*\\)" link) + (progn + (setq path (match-string 1 link)) + (setq loc (match-string 2 link)) + (if (string-match "\\([0-9]+\\)++\\(.*\\)" loc) + (setq page (match-string 1 loc)) + (setq page loc))) + (setq path link)) + + ;; `org-export-file-uri` expands the filename correctly + (setq path (org-export-file-uri (org-link-escape path))) + + (cond ((eq format 'html) + (format + "<a href=\"%s#page=%s\">%s</a>" + path + page + description)) + ((eq format 'latex) + (format + "\\href{%s}{%s}" + path + description)) + ((eq format 'ascii) + (format "%s (%s)" description path)) + (t path)))) + +;;;###autoload +(defun org-pdftools-setup-link (&optional prefix) + "Set up pdf: links in org-mode." + (setq org-pdftools-prefix (or prefix org-pdftools-link-prefix)) + (org-link-set-parameters org-pdftools-prefix + :follow #'org-pdftools-open + :complete #'org-pdftools-complete-link + :store #'org-pdftools-store-link + :export #'org-pdftools-export)) + +;;;###autoload +(defun org-pdftools-complete-link (&optional arg) + "Use the existing file name completion for file. +Links to get the file name, then ask the user for the page number +and append it. ARG is passed to `org-link-complete-file'." + (concat + (replace-regexp-in-string + "^file:" + (concat org-pdftools-link-prefix ":") + (org-link-complete-file arg)) + "::" + (read-from-minibuffer + "Page:" + "1"))) + +(provide 'org-pdftools) +;;; org-pdftools.el ends here @@ -0,0 +1,2 @@ +(use-package "pdf-tools" 'pdf-view + ) @@ -0,0 +1,32 @@ +;;; Automatically generated by ‘recentf’ on Fri Jan 8 20:45:28 2021. + +(setq recentf-list + '( + "/Users/durand/.newsrc.eld" + "/Users/durand/org/math_article_links.org" + "/Users/durand/org/aujourdhui.org" + "/Users/durand/org/agenda.org" + "/Users/durand/org/notes.org" + "/Users/durand/Desktop/emacs.d/gnus-conf.el" + "/usr/local/Cellar/emacs-plus@27/27.1/share/emacs/27.1/lisp/gnus/gnus-group.el.gz" + "/Users/durand/elisp_packages/hierarchy/hierarchy.el" + "/Users/durand/.emacs.d/bookmarks" + "/Users/durand/Desktop/emacs.d/init.el" + "/Users/durand/Desktop/emacs.d/comb/suffix-tree.el" + "/Users/durand/Downloads/documents intéressants/Algorithms/Algorithms on Strings, Trees, and Sequences Computer Science and Computational Biology by Dan Gusfield (z-lib.org).pdf" + "/Users/durand/Desktop/emacs.d/comb/orderless-conf.el" + "/Users/durand/Desktop/emacs.d/ibuffer.el" + "/usr/local/Cellar/emacs-plus@27/27.1/share/emacs/27.1/lisp/ibuffer.el.gz" + "/Users/durand/Desktop/emacs.d/basic.el" + "/Users/durand/Desktop/emacs.d/embark-conf.el" + "/Users/durand/Desktop/emacs.d/common.el" + "/Users/durand/elisp_packages/embark/embark.el" + "/Users/durand/Desktop/nnmaildir+private:private" + )) + +(setq recentf-filter-changer-current 'nil) + + +;; Local Variables: +;; coding: utf-8-emacs +;; End: diff --git a/recentf-conf.el b/recentf-conf.el new file mode 100644 index 0000000..3097b66 --- /dev/null +++ b/recentf-conf.el @@ -0,0 +1,16 @@ +;;; recentf-conf.el --- My configurations concerning recentf -*- lexical-binding: t; -*- + +(require 'recentf) + +(set 'recentf-save-file (expand-file-name "recentf" load-file-directory)) + +(recentf-mode 1) + +;;;###autoload +(defun choose-recent-file () + "Choose a recently visited file to visit. +This uses `completing-read' to choose a file from `recentf-list'." + (interactive) + (let ((choice (completing-read "Choose a recently visited file: " + recentf-list 'file-exists-p t))) + (find-file choice))) diff --git a/tab-conf.el b/tab-conf.el new file mode 100644 index 0000000..f55259c --- /dev/null +++ b/tab-conf.el @@ -0,0 +1,54 @@ +;;; tab-conf.el --- My configurations of the tabs -*- lexical-binding: t; -*- + +(require 'tab-bar) + +(define-key tab-switcher-mode-map (vector ?n) 'tab-switcher-next-or-first) +(define-key tab-switcher-mode-map (vector ?p) 'tab-switcher-prev-or-last) +(define-key tab-prefix-map (vector 'tab) 'tab-switcher) + +;;;###autoload +(defun tab-switcher-first () + "Go to the first window configuration line." + (interactive) + (goto-char (point-min)) + (skip-chars-forward "[:space:]\n") + (forward-char -1)) + +;;;###autoload +(defun tab-switcher-last () + "Go to the last window configuration line." + (interactive) + (goto-char (point-max)) + (skip-chars-backward "[:space:]\n") + (goto-char (line-beginning-position)) + (skip-chars-forward "[:space:]") + (forward-char -1)) + +;;;###autoload +(defun tab-switcher-next-or-first () + "Go to the next configuration line. +If the next line is not a configuration line, +then go to the first configuration line." + (interactive) + (forward-line 1) + (cond + ((looking-at "^\\s-*$") + (tab-switcher-first)) + (t (skip-chars-forward "[:space:]") + (forward-char -1)))) + +;;;###autoload +(defun tab-switcher-prev-or-last () + "Go to the previous configuration line. +If the previous line is not a configuration line, +then go to the last configuration line." + (interactive) + (forward-line -1) + (cond + ((looking-at "^\\s-*$") + (tab-switcher-last)) + (t (skip-chars-forward "[:space:]") + (forward-char -1)))) + + + diff --git a/text-conf.el b/text-conf.el new file mode 100644 index 0000000..1fe9696 --- /dev/null +++ b/text-conf.el @@ -0,0 +1,89 @@ +;;; text-conf.el --- My configurations about plain text files. -*- lexical-binding: t; -*- + +(require 'text-mode) + +;;;###autoload +(defvar insert-section-heading-history nil + "The history of inserted section heading strings") + +;;;###autoload +(defun insert-section-heading (custom-heading) + "Insert a heading line below. + +If CUSTOM-HEADING is non-nil, then use a custom heading. + +The user can input any string as a basic constituent of a +heading. The inputed string will be repeated (floor N M) times, +where N is the length of the current line and M is the lenght of +the input string. After this repeat the first (remainder N M) +characters of the input string will be inserted as well to cover +exactly the current ilne." + (interactive "P") + (let* ((current-length (- (point-at-eol) + (point-at-bol))) + (heading (cond + ((null custom-heading) "-") + (t (read-string "Enter a custom heading: " + nil insert-section-heading-history + "-" t)))) + (floor-length (floor current-length (length heading))) + (remainder (% current-length (length heading))) + (remainder-string (substring heading 0 remainder)) + (index 0)) + (save-excursion + (goto-char (line-end-position)) + (newline) + (while (< index floor-length) + (message "index: %s" index) + (message "floor: %s" floor-length) + (insert heading) + (setq index (1+ index))) + (insert remainder-string)))) + +;;;###autoload +(defvar make-block-history nil + "The history of block quote descriptions.") + +;;;###autoload +(defun make-block (&optional description) + "Surround the current line or the region in a block. + +If DESCRIPTION is non-nil, ask for a description and put the +DESCRIPTION above the block." + (interactive "P") + (let* ((beg (cond + ((use-region-p) + (region-beginning)) + ((line-beginning-position)))) + (end (cond + ((use-region-p) + (region-end)) + ((line-end-position)))) + (end-marker (set-marker (make-marker) (1+ end))) + (fill-line (make-string fill-column ?=)) + (header (cond + (description + (list fill-line + "\n" + (center-string-in-width + (read-string "Description of the block: " + nil make-block-history nil t) + fill-column) + "\n" + fill-line)) + (t (list fill-line))))) + (save-excursion + (goto-char beg) + (while (<= (point) (1- (marker-position end-marker))) + (center-line) + (forward-line 1)) + (goto-char beg) + (mapc #'insert header) + (newline) + (goto-char (1- (marker-position end-marker))) + (set-marker end-marker nil) + (newline) + (insert fill-line)))) + +(provide 'text-conf) +;;; text-conf.el ends here. diff --git a/view-functions.el b/view-functions.el new file mode 100644 index 0000000..ae5559a --- /dev/null +++ b/view-functions.el @@ -0,0 +1,90 @@ +;;; view-functions.el --- My functions to monitor system infos -*- lexical-binding: t; -*- + +;;;###autoload +(defun durand-view-timers-or-temps (&optional arg) + "View the list of timers or view the CPU temperature info. +If ARG is nil, view the list of timers. +If ARG is '(4), view the information about CPU temperature and +fans speed and some others. +If ARG is '(16), view the battery information." + (interactive "P") + (cond + ((null arg) + (let (fan-speed + cpu-die-temperature + remain + full-capacity + fullp + charging + cycle + condition + connected + battery-temp) + (with-temp-buffer +;;; NOTE: First fans information + (insert (funcall + (plist-get (car (auth-source-search :host "local-computer")) + :secret))) + (call-process-region + nil nil "sudo" + nil t nil "-S" "powermetrics" + "-i1" "-n1" "-ssmc") + (goto-char (point-min)) + (search-forward "Fan" nil t) + (setf fan-speed + (progn (re-search-forward "[[:digit:]]+" (line-end-position) t) + (string-to-number (match-string 0))) + cpu-die-temperature + (progn (re-search-forward "temperature: \\([[:digit:]]+\\.[[:digit:]]+\\)" nil t) + (string-to-number (match-string 1)))) + +;;; NOTE: Now battery charge information + (erase-buffer) + (call-process "system_profiler" nil t nil + "SPPowerDataType") + (goto-char (point-min)) + (re-search-forward "Fully Charged: \\(.+\\)$" nil t) + (setf fullp (match-string-no-properties 1)) + (re-search-forward "Charging: \\(.+\\)$" nil t) + (setf charging (match-string-no-properties 1)) + (re-search-forward "Full Charge Capacity (mAh): \\([[:digit:]]+\\)$" nil t) + (setf full-capacity (string-to-number (match-string-no-properties 1))) + (re-search-forward "State of Charge (%): \\([[:digit:]]+\\)" nil t) + (setf remain (string-to-number (match-string-no-properties 1))) + (re-search-forward "Cycle Count: \\(.+\\)$" nil t) + (setf cycle (string-to-number (match-string-no-properties 1))) + (re-search-forward "Condition: \\(.+\\)$" nil t) + (setf condition (match-string-no-properties 1)) + (re-search-forward "Connected: \\(.+\\)$" nil t) + (setf connected (match-string-no-properties 1)) + +;;; NOTE: Now battery temperature + (erase-buffer) + (call-process "ioreg" nil t nil "-n" "AppleSmartBattery" "-r") + (goto-char (point-min)) + (re-search-forward "Temperature..=." nil t) + (re-search-forward "[[:digit:]]+" nil t) + (setf battery-temp + (/ (string-to-number (match-string-no-properties 0)) + 100.0))) + (message + (concat + (format "fan: %d, temp: %s, battery temp: %.2f" + fan-speed cpu-die-temperature battery-temp) + "\n" + (format "Full: %d, remaining: %d%s, fullp: %s, charging: %s, connected: %s, cycles: %d, condition: %s" + full-capacity remain "%%" fullp charging connected cycle condition))))) + ((equal arg (list 4)) (list-timers)) + (t + (user-error "Unsupported ARG: %S" arg)))) + +(define-obsolete-function-alias 'durand-view-timers 'durand-view-timers-or-temps + "2020-09-02" "View the list of timers.") + +;;;###autoload +(defun durand-view-process (&optional arg) + "View the list of processes" + (interactive "P") + (if arg + (proced) + (message "%s" (process-list)))) |