summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--basic.el75
-rw-r--r--bongo.el637
-rw-r--r--center-buffer.el38
-rw-r--r--comb/suffiex-tree.txt217
-rw-r--r--common.el73
-rw-r--r--dashboard.el50
-rw-r--r--desktop19
-rw-r--r--desktop-conf.el170
-rw-r--r--dired-conf.el4
-rw-r--r--elisp.el22
-rw-r--r--gnus-conf.el142
-rw-r--r--ibuffer.el56
-rw-r--r--init.el95
-rw-r--r--mail.el108
-rw-r--r--modeline.el129
-rw-r--r--modes/Concepts.txt298
-rw-r--r--modes/modes.el97
-rw-r--r--org-conf.el309
-rw-r--r--org-pdftools.el403
-rw-r--r--pdf.el2
-rw-r--r--recentf32
-rw-r--r--recentf-conf.el16
-rw-r--r--tab-conf.el54
-rw-r--r--text-conf.el89
-rw-r--r--view-functions.el90
25 files changed, 3174 insertions, 51 deletions
diff --git a/basic.el b/basic.el
index 0398073..cfa606a 100644
--- a/basic.el
+++ b/basic.el
@@ -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.
diff --git a/desktop b/desktop
new file mode 100644
index 0000000..f0d26bc
--- /dev/null
+++ b/desktop
@@ -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")
diff --git a/elisp.el b/elisp.el
index b1f1be4..507c944 100644
--- a/elisp.el
+++ b/elisp.el
@@ -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)
diff --git a/init.el b/init.el
index ed4e36a..9d94c06 100644
--- a/init.el
+++ b/init.el
@@ -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))
diff --git a/mail.el b/mail.el
new file mode 100644
index 0000000..58af042
--- /dev/null
+++ b/mail.el
@@ -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
diff --git a/pdf.el b/pdf.el
new file mode 100644
index 0000000..5ec5c58
--- /dev/null
+++ b/pdf.el
@@ -0,0 +1,2 @@
+(use-package "pdf-tools" 'pdf-view
+ )
diff --git a/recentf b/recentf
new file mode 100644
index 0000000..7715881
--- /dev/null
+++ b/recentf
@@ -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))))