166 KiB
- Spacemacs like setup
- Finding files functions
- Dirvish
- ORG
- ORG-ROAM
- ORG-NOTER
- GPTEL
- ORG-AGENDA
- MU4E
- Contexts
- Sending & pulling
- Get email addresses
- Folding
- Defining functions
- search-mail
- Show thread in all modes
- read-mail-mv
- Remove trash
- search without threads
- Toggle the organization of mail in threads
- Select inbox, archives, trash, concepts
- go-to-headers
- go-to-inbox
- mu4e-update-index-mv
- show-single-thread
- search-sent-mv
- show-combined-inbox
- show-archive-mv
- show-drafts-mv
- archive-mv-thread
- open-mail-no-split
- mu4e-headers-view-message-mv
- tomail
- show-archief
- execute-mark-mv
- check if source block is python
- send-mv
- mail-view-move-up/ mail-view-move-down
- Closing buffers
- Keybindings & hooks
- Defining basic variables
- Message Compose
- Attachments
- COMMENT ORG-MSG (compose and save attachment)
- Responding to outlook invites
- mu4e-goodies
- Theming
- Reveal
- Latex
- Python mode
- Yasnippet
- Org-mapping-notes
- COMMENT Nixos
- Spelling check
- Google translate
- Misc
Spacemacs like setup
Base variables
(setq mv/nixos-base-folder "/etc/nixos")
(setq mv/nextcloud-base "/home/misha/Nextcloud")
(setq org-export-with-broken-links t)
(setq filemv-download "/home/misha/Downloads")
Custom
(custom-set-variables
;; custom-set-variables was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
'(custom-safe-themes
'("cdad4e5bc718111deb1f1a2a35e9781e11724144a1eb2064732c337160946760"
"cfb0bb44259cf576124b900613628f4b589df1c3860185d24fffde6666bc88cf"
default))
'(package-selected-packages nil))
(custom-set-faces
;; custom-set-faces was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
'(org-level-1 ((t (:inherit outline-1 :height 1.3))))
'(org-level-2 ((t (:inherit outline-2 :height 1.2))))
'(org-level-3 ((t (:inherit outline-3 :height 1.1))))
'(org-level-4 ((t (:inherit outline-4 :height 1.0))))
'(org-level-5 ((t (:inherit outline-5 :height 1.0)))))
Basic tricks Daniel
(define-prefix-command 'spc-root 'spc-leader-map)
(global-set-key (kbd "M-m") 'spc-root)
;; Uncouple C-i and C-m keys
(define-key input-decode-map "\C-m" [C-m])
;; For defining keybindings Emacs provides the =define-key= command to set a single key binding at a time. If we want to define multiple key bindings at once, we must define a custom function for that.
(defun spc-define-keys (map key def &rest bindings)
"Define multiple key bindings at once."
(while key
(define-key map (kbd key) def)
(setq key (pop bindings) def (pop bindings))))
(put 'spc-define-keys 'lisp-indent-function 'defun)
Evil
(setq evil-want-integration t ;; This is optional since it's already set to t by default.
evil-want-keybinding nil
evil-want-minibuffer t
evil-want-C-i-jump t
evil-respect-visual-line-mode t
evil-undo-system 'undo-redo
evil-shift-width 2
evil-symbol-word-search t)
(evil-mode)
(global-set-key (kbd "C-u") 'evil-scroll-up)
(global-set-key (kbd "C-d") 'evil-scroll-down)
;; not needed when using evil-collection
(add-to-list 'evil-motion-state-modes 'special-mode)
(evil-global-set-key 'motion (kbd "SPC") 'spc-root)
;; Added by me
;; (package-install 'evil-surround) ;;nixos
(global-evil-surround-mode 1)
(setq evil-shift-width 2)
ivy
;; (package-install 'ivy) ;;nixos
(require 'ivy)
(ivy-mode 1)
;; (package-install 'counsel) ;;nixos
(require 'counsel)
;; (package-install 'ivy-prescient) ;;nixos
(require 'ivy-prescient)
(ivy-prescient-mode 1)
(prescient-persist-mode 1)
Work with ivy-prescient-mode
- <2023-11-20 Mon>
- Setting ivy-prescient-mode to -1 (turning it off) means that lists are shown in their natural order: recently chosen items do not get shown above.
- In general I like recently chosen things to show up first. But sometimes I want to turn this off.
- If I put this in the beginning of a function: (add-hook 'minibuffer-exit-hook 'turn-on-prescient-mode-mv) (ivy-prescient-mode -1)
- … and I turn ivy-prescient-mode on at the end of a function..
- … it works. Which makes sense.
(defun turn-on-prescient-mode-mv ()
(interactive)
(ivy-prescient-mode 1)
(remove-hook 'minibuffer-exit-hook 'turn-on-prescient-mode-mv))
Window management
;; (package-install 'winum) ;;nixos
(require 'winum)
(winum-mode)
(setq frame-title-format
(list (format "%s %%S: %%j " (system-name))
'(buffer-file-name "%f" (dired-directory dired-directory "%b"))))
;; windows
(global-set-key (kbd "M-1") 'winum-select-window-1)
(global-set-key (kbd "M-2") 'winum-select-window-2)
(global-set-key (kbd "M-3") 'winum-select-window-3)
(global-set-key (kbd "M-4") 'winum-select-window-4)
(global-set-key (kbd "M-5") 'winum-select-window-5)
(global-set-key (kbd "M-6") 'winum-select-window-6)
(global-set-key (kbd "M-7") 'winum-select-window-7)
(global-set-key (kbd "M-8") 'winum-select-window-8)
(global-set-key (kbd "M-9") 'winum-select-window-9)
Basic keybindings
(spc-define-keys spc-leader-map
;; Basics
"SPC" 'execute-extended-command
"<tab>" 'evil-switch-to-windows-last-buffer
";" 'comment-or-uncomment-region
"b" '("buffer" keymap)
"bb" 'switch-to-buffer
"bd" 'kill-current-buffer
"bm" 'pop-to-messages
"bs" 'scratch-buffer
"bt" 'find-todo
"bp" 'previous-buffer
"bn" 'next-buffer
"c" '("compile" keymap)
"cc" 'recompile
"e" '("edit" keymap)
"f" '("files" keymap)
"fe" '("emacs" keymap)
"fD" 'delete-current-buffer-file
"fed" 'find-init-file
"feR" 'load-init-file
"ff" 'find-file
"fl" 'find-library
"fL" 'counsel-locate
"fr" 'counsel-recentf
"fR" 'rename-mv
"fs" 'save-buffer
"fS" 'evil-write-all
"Fn" 'make-frame
"Fd" 'delete-frame
"g" '("git" keymap)
"h" '("help" keymap)
"hdc" 'describe-char
"hdf" 'describe-function
"hj" 'info-display-manual
"hdk" 'describe-key
"hdv" 'describe-variable
"hdK" 'describe-keymap
"hdm" 'describe-mode
"j" '("jump" keymap)
"jf" 'find-function
;;"ji" 'imenu ;might get overwritten by ivy/vertico/helm section
"jl" 'find-library
"ji" 'ji-mv
"l" '("lisp" keymap)
"ll" 'ielm
"o" '("org" keymap)
"oe" 'open-chatgtp
"p" '("projects" keymap)
"pf" 'project-find-file
"pp" 'project-switch-project
"s" '("search" keymap)
"ss" 'swiper
"si" 'swiper-thing-at-point
"sl" 'locate
"t" '("toggles" keymap)
"tl" 'display-line-numbers-mode
"u" 'universal-argument
"w" '("windows" keymap)
"w/" 'split-window-right
"w-" 'split-window-below
"wd" 'delete-window
"w1" 'delete-other-windows
"wl" 'evil-window-move-far-right
"wh" 'evil-window-move-far-left
;;"z" 'text-scale-adjust
;;"ws" 'shrink-window-horizontally
;;"wl" 'enlarge-window-horizontally
"w]" 'evil-window-increase-width
"w[" 'evil-window-decrease-width
"q" '("quit" keymap)
"qq" 'save-buffers-kill-emacs
"gs" 'magit-status
"eof" 'edebug-defun
"om" 'pdf-outline
"ew" 'google-translate-mv
"pc" 'comint-clear-buffer
"pr" 'run-region-mv
"pB" 'python-shell-send-buffer
"pb" 'run-block)
(add-hook 'custom-mode-hook
(lambda ()
(evil-define-key 'normal custom-mode-map (kbd "SPC") nil)))
(global-set-key (kbd "C-S-c") (lambda () (interactive) (insert (format-time-string "<%Y-%m-%d %a>"))))
(global-set-key (kbd "C-S-t") (lambda () (interactive) (insert (format-time-string "<%Y-%m-%d %a %z %H:%M>"))))
Font
(set-face-attribute 'default nil :height 110)
(defun text-scale-normal ()
(interactive)
(text-scale-set 0.1))
(spc-define-keys spc-leader-map
"z+" 'text-scale-increase
"z-" 'text-scale-decrease
"z0" 'text-scale-normal)
(setq org-emphasis-alist
'(("*" (bold :foreground "dim gray" ))
("/" (italic :foreground "dim gray" ))
("_" underline)
("=" (:background "wheat" :foreground "black"))
("~" (:background "wheat" :foreground "black" :weight bold))
("+" (:strike-through t))))
(defun mv/font-normal ()
(interactive)
(set-face-attribute 'default nil :height 110))
(defun mv/font-medium ()
(interactive)
(set-face-attribute 'default nil :height 150))
(defun mv/font-large ()
(interactive)
(set-face-attribute 'default nil :height 190))
(defun mv/font-huge ()
(interactive)
(set-face-attribute 'default nil :height 240))
(spc-define-keys spc-leader-map
"z0" 'mv/font-normal
"z1" 'mv/font-medium
"z2" 'mv/font-large
"z3" 'mv/font-huge
)
Finding files functions
(defun find-init-file ()
(interactive)
(find-file "~/.emacs.d/README.org"))
(defun file-search-mv (paths-mv)
(interactive)
;; this function removes itself from the hook
(add-hook 'minibuffer-exit-hook 'turn-on-prescient-mode-mv)
(ivy-prescient-mode -1)
(let* ((listfiles (split-string
(shell-command-to-string
(format "find %s -maxdepth 1 -type f -printf '%%T@ %%CY-%%Cm-%%Cd %%CH:%%CM:%%.2CS %%h %%f\n' | sort -nrk1 | awk '{$1=\"\"; print}' | grep -v pdf-view-restore | grep -Ev '[#~]$' | grep -v '.html$'" (string-join paths-mv " "))
;;(format "find %s -maxdepth 1 -type f -printf '%%T@ %%c %%h %%f\\n' | sort -nr | awk '{$1=\"\";print}'" (string-join paths-mv " "))
) "\n"))
(filenamem
(string-join
(split-string
(ivy-read "open: " listfiles) " ") " " )))
(let ((output (format "%s/%s" (nth 3 (split-string filenamem " ")) (string-join (nthcdr 4 (split-string filenamem " ")) " "))))
;; (print filenamem)
;; (print output)
(find-file output)
;;(remove-hook 'minibuffer-exit-hook 'turn-on-prescient-mode)
))
(ivy-prescient-mode 1)
)
(defun mnotessearch-simple ()
(interactive)
;; this function removes itself from the hook
(add-hook 'minibuffer-exit-hook 'turn-on-prescient-mode-mv)
(ivy-prescient-mode -1)
(let* ((listfiles (split-string
(shell-command-to-string
(format "find /home/misha/Nextcloud/mnotes/ -type f -printf '%%T@ %%CY-%%Cm-%%Cd %%CH:%%CM:%%.2CS %%h %%f\n' | sort -nrk1 | awk '{$1=\"\"; print}' | grep -v pdf-view-restore | grep -Ev '[#~]$' | grep -v '.html$' | grep -v 'images'")
;;(format "find %s -maxdepth 1 -type f -printf '%%T@ %%c %%h %%f\\n' | sort -nr | awk '{$1=\"\";print}'" (string-join paths-mv " "))
) "\n"))
(filenamem
(string-join
(split-string
(ivy-read "open: " listfiles) " ") " " )))
(let ((output (format "%s/%s" (nth 3 (split-string filenamem " ")) (string-join (nthcdr 4 (split-string filenamem " ")) " "))))
;; (print filenamem)
;; (print output)
(find-file output)
;;(remove-hook 'minibuffer-exit-hook 'turn-on-prescient-mode)
))
(ivy-prescient-mode 1)
)
(defun mnotessearch ()
(interactive)
(file-search-mv '(
(format "%s/mnotes/" mv/nextcloud-base)
(format "%s/mnotes/orgzly/" mv/nextcloud-base)
(format "%s/mnotes/org-roam/" mv/nextcloud-base)
(format "%s/mnotes/org-roam/pdf_notes/" mv/nextcloud-base)
(format "%s/mnotes/org-roam/blog/drafts" mv/nextcloud-base)
(format "%s/mnotes/org-roam/blog/posts" mv/nextcloud-base)
(format "%s/mnotes/org-roam/presentations/2024-2025/semester1/system-earth" mv/nextcloud-base)
(format "%s/mnotes/org-roam/presentations/2024-2025/semester1/intro-energy-transition" mv/nextcloud-base)
)))
(defun pdf_library_search ()
(interactive)
(file-search-mv (list (format "%s/pdf_library/" mv/nextcloud-base))))
(defun books_search ()
(interactive)
(file-search-mv (list (format "%s/pdf_library/books" mv/nextcloud-base))))
(defun extra_search ()
(interactive)
(file-search-mv (list (format "%s/pdf_library/extra" mv/nextcloud-base))))
Dirvish
https://github.com/alexluigit/dirvish/blob/main/docs/CUSTOMIZING.org
Basics
;; (package-install 'dirvish) ;;nixos
(require 'dirvish)
(dirvish-override-dired-mode)
(setq dired-listing-switches "-lta")
(add-hook 'dirvish-find-entry-hook
(lambda (&rest _) (setq-local truncate-lines t)))
;; To also disable truncated lines in the directory preview (which is in fundamental mode):
(add-hook 'after-change-major-mode-hook
(lambda ()
(if (eq major-mode 'fundamental-mode)
(setq truncate-lines t))))
(setq dirvish-reuse-session 'resume)
;; (setq dirvish-preview-dispatchers
;; (cl-substitute 'pdf-preface 'pdf dirvish-preview-dispatchers))
;; (package-install 'all-the-icons) ;;nixos
(require 'all-the-icons)
(setq dirvish-attributes
'(file-time file-size))
(setq dirvish-default-layout '(1 0.11 0.35))
(setq dirvish-yank-overwrite-existing-files 'backup)
(setq dirvish-yank-new-name-style 'append-to-filename)
Functions
(defun mv/open-external-application ()
(interactive)
(let* ((file (dired-get-file-for-visit))
(applications (directory-files "/usr/bin/" t))
(chosen-app (ivy-read "Choose application: " applications)))
(start-process "dirvish-open-with" nil chosen-app file)))
(defun mv/open-external-application ()
(interactive)
(let* ((file (dired-get-file-for-visit))
(applications (directory-files (file-name-directory (executable-find "env")) t))
(chosen-app (ivy-read "Choose application: " applications)))
(start-process "dirvish-open-with" nil chosen-app file)))
(defun mv/check-mail-buffer ()
(if (eq major-mode 'mu4e-compose-mode)
(setq compose-buffer (buffer-name))
(setq compose-buffer nil)))
(defun dirvish-nix-home ()
(interactive)
(mv/check-mail-buffer)
(dirvish "/etc/nixos/"))
(defun dirvish-home ()
(interactive)
(mv/check-mail-buffer)
(dirvish "/home/misha/"))
(defun dirvish-other-config ()
(interactive)
(mv/check-mail-buffer)
(dirvish "/etc/nixos/other-config/"))
(defun dirvish-nextcloud ()
(interactive)
(mv/check-mail-buffer)
(dirvish "/home/misha/Nextcloud/"))
(defun dirvish-presentations ()
(interactive)
(mv/check-mail-buffer)
(dirvish "/home/misha/Nextcloud/mnotes/org-roam/presentations/2024-2025/semester2"))
(defun dirvish-website ()
(interactive)
(mv/check-mail-buffer)
(dirvish "/home/misha/Nextcloud/mishathings-website/content"))
(defun dirvish-images ()
(interactive)
(mv/check-mail-buffer)
(dirvish "/home/misha/Nextcloud/mnotes/org-roam/presentations/images"))
(defun dirvish-auc ()
(interactive)
(mv/check-mail-buffer)
(dirvish "/home/misha/Nextcloud/UvA/AUC/2024-2025/semester2/"))
(defun dirvish-mnotes ()
(interactive)
(mv/check-mail-buffer)
(dirvish "/home/misha/Nextcloud/mnotes/"))
(defun dirvish-pdf-library ()
(interactive)
(mv/check-mail-buffer)
(dirvish "/home/misha/Nextcloud/pdf_library/"))
(defun dirvish-git ()
(interactive)
(mv/check-mail-buffer)
(dirvish "/home/misha/git/"))
(defun dirvish-books ()
(interactive)
(mv/check-mail-buffer)
(dirvish "/home/misha/Nextcloud/pdf_library/books"))
(defun dirvish-extra ()
(interactive)
(mv/check-mail-buffer)
(dirvish "/home/misha/Nextcloud/pdf_library/extra"))
(defun dirvish-download ()
(interactive)
(mv/check-mail-buffer)
(dirvish "/home/misha/Downloads"))
(defun dirvish-send-attach ()
(interactive)
(mv/check-mail-buffer)
(dirvish "/home/misha/Documents/attach"))
(defun dirvish-any-dir-Nextcloud ()
(interactive)
(mv/check-mail-buffer)
(dirvish (ivy-read "Pick dir: " (split-string (shell-command-to-string "find /home/misha/Nextcloud -type d") "\n"))))
;; (defun dirvish-fd-ask-nextcloud ()
;; (interactive)
;; (dirvish-fd-ask "/home/misha/Nextcloud/" (read-from-minibuffer "Pattern: ")))
(defun dirvish-resume ()
(interactive)
(mv/check-mail-buffer)
(setq dirvish-reuse-session 'resume)
(dirvish))
(defun dirvish-open-folder-of-file ()
(interactive)
(setq dirvish-reuse-session t)
(if (eq major-mode 'shell-mode)
(dirvish (string-trim-right (dirs)))
(dirvish)))
(defun dirvish-shell ()
(interactive)
;; kill open shells (processes and buffers)
(let ((kill-buffer-query-functions
(remq 'process-kill-buffer-query-function
kill-buffer-query-functions)))
(dolist (process (process-list))
(when (string-match-p "shell" (process-name process))
(let ((buffer (process-buffer process)))
(when buffer
(kill-buffer buffer)))
(delete-process process))))
(if (eq major-mode 'dired-mode)
(progn
(shell)
(delete-other-windows))
(shell default-directory)))
;; This gives the pdf preview the familiar keybindings when I want to walk through the preview
(defun dirvish-switch-window ()
(interactive)
"i2r"
(if (or (eq major-mode 'dired-mode) (eq major-mode 'wdired-mode))
(progn
(other-window 1)
(load-keys))
(progn
(save-buffer)
(other-window 1)
(if (eq major-mode 'pdf-view-mode)
(progn
(if mv-midnight-mode
(progn
(pdf-view-midnight-minor-mode)
(pdf-view-midnight-minor-mode))))
;; (if (not (eq major-mode 'wdired-mode))
;; (save-buffer))
))))
(defun dirvish-layout-switch-mv ()
(interactive)
(dirvish-layout-switch '(0 0 0.8)))
;; (defun dirvish-open-xdg ()
;; (interactive)
;; (shell-command (format "xdg-open \"%s\"" (dired-get-file-for-visit))))
;; (defun dirvish-open-nautilusf ()
;; (interactive)
;; (if (eq major-mode 'dired-mode)
;; (progn
;; (let* ((path (dired-get-file-for-visit))
;; (path (if (file-exists-p path)
;; (file-name-directory path) path)))
;; (async-shell-command (format "nautilus \"%s\" &" path))))
;; (async-shell-command (format "nautilus \"%s\" &" (buffer-file-name)))))
(defun dirvish-open-nautilus ()
(interactive)
(if (eq major-mode 'dired-mode)
(progn
(let* ((path (dired-get-file-for-visit))
(path (if (file-exists-p path)
(file-name-directory path) path)))
(async-shell-command (format "nautilus \"%s\" &" path)
(generate-new-buffer-name "*nautilus-async*"))))
(async-shell-command (format "nautilus \"%s\" &" (buffer-file-name))
(generate-new-buffer-name "*nautilus-async*"))))
(defun dirvish-history-jump ()
"Open a target directory from `dirvish--history'."
(interactive)
(unless dirvish--history (user-error "Dirvish[error]: no history entries"))
(let* ((result (ivy-read "Recently visited: " dirvish--history :sort nil)))
(when result (dirvish-find-entry-a result))))
(defalias 'rename-in-dirvish
(kmacro "i 0 w w v t . c"))
(defalias 'change-name-dirvish
(kmacro "0 t . l i"))
(defalias 'change-name-dirvish-folder
(kmacro "A"))
(defun change-name-dirvish2 ()
(interactive)
(wdired-change-to-wdired-mode)
(beginning-of-line)
(let ((eol (save-excursion (end-of-line) (point))))
(if (search-forward "." eol t)
(change-name-dirvish)
(change-name-dirvish-folder))))
Keybindings
(evil-define-key 'normal dired-mode-map (kbd "SPC") nil)
(evil-define-key 'normal dired-mode-map (kbd "q") 'dirvish-quit)
(evil-define-key 'normal dired-mode-map (kbd "h") 'dired-up-directory)
(evil-define-key 'normal dired-mode-map (kbd "l") 'dired-find-file)
(evil-define-key 'normal dired-mode-map (kbd "M") 'dirvish-move)
(evil-define-key 'normal dired-mode-map (kbd "Y") 'dirvish-yank)
(evil-define-key 'normal dired-mode-map (kbd "C") 'dired-create-directory)
(evil-define-key 'normal dired-mode-map (kbd "T") 'dired-create-empty-file)
(evil-define-key 'normal dired-mode-map (kbd "yp") 'dirvish-copy-file-path)
(evil-define-key 'normal dired-mode-map (kbd "yn") 'dirvish-copy-file-name)
(evil-define-key 'normal dired-mode-map (kbd "F") 'browse-url-of-dired-file)
(evil-define-key 'normal dired-mode-map (kbd "c") nil)
(evil-define-key 'normal dired-mode-map (kbd "cw") 'rename-in-dirvish)
(evil-define-key 'normal dired-mode-map (kbd "H") 'dirvish-open-nautilus)
(evil-define-key 'normal dired-mode-map (kbd "a") 'change-name-dirvish2)
(evil-define-key 'normal dired-mode-map (kbd "r") nil)
(evil-define-key 'normal dired-mode-map (kbd "r") 'revert-buffer)
(evil-define-key 'normal dired-mode-map (kbd "e") 'mv/process-marked-files-as-attachments)
(spc-define-keys spc-leader-map
"dn" 'dirvish-nextcloud
"dy" 'dirvish-presentations
"di" 'dirvish-images
"dt" 'dirvish-website
"du" 'dirvish-auc
"dd" 'dirvish-download
"dm" 'dirvish-mnotes
"dp" 'dirvish-pdf-library
"dg" 'dirvish-git
"db" 'dirvish-books
"de" 'dirvish-extra
"do" 'dirvish-any-dir-Nextcloud
"dh" 'dirvish-history-jump
"df" 'dirvish-fd-ask-nextcloud
"d." 'dirvish-open-folder-of-file
"dr" 'dirvish-resume
"ts" 'dirvish-shell
"tp" 'run-python
"d/" 'dirvish-narrow
"dw" 'dirvish-switch-window
"d0" 'dirvish-nix-home
"d1" 'dirvish-home
"d2" 'dirvish-other-config
"sas" 'dirvish-send-attach
)
Open with external program
(setq dirvish-open-with-programs '((("ape" "stm" "s3m" "ra" "rm" "ram" "wma" "wax" "m3u" "med" "669"
"mtm" "m15" "uni" "ult" "mka" "flac" "axa" "kar" "midi" "mid" "s1m"
"smp" "smp3" "rip" "multitrack" "ecelp9600" "ecelp7470" "ecelp4800"
"vbk" "pya" "lvp" "plj" "dtshd" "dts" "mlp" "eol" "uvva" "uva"
"koz" "xhe" "loas" "sofa" "smv" "qcp" "psid" "sid" "spx" "opus"
"ogg" "oga" "mp1" "mpga" "m4a" "mxmf" "mhas" "l16" "lbc" "evw"
"enw" "evb" "evc" "dls" "omg" "aa3" "at3" "atx" "aal" "acn" "awb"
"amr" "ac3" "ass" "aac" "adts" "726" "abs" "aif" "aifc" "aiff" "au"
"mp2" "mp3" "mp2a" "mpa" "mpa2" "mpega" "snd" "vox" "wav")
#1="/usr/bin/mpv" "--profile=builtin-pseudo-gui" "%f")
(("f4v" "rmvb" "wvx" "wmx" "wmv" "wm" "asx" "mk3d" "mkv" "fxm" "flv"
"axv" "webm" "viv" "yt" "s1q" "smo" "smov" "ssw" "sswf" "s14" "s11"
"smpg" "smk" "bk2" "bik" "nim" "pyv" "m4u" "mxu" "fvt" "dvb" "uvvv"
"uvv" "uvvs" "uvs" "uvvp" "uvp" "uvvu" "uvu" "uvvm" "uvm" "uvvh"
"uvh" "ogv" "m2v" "m1v" "m4v" "mpg4" "mp4" "mjp2" "mj2" "m4s"
"3gpp2" "3g2" "3gpp" "3gp" "avi" "mov" "movie" "mpe" "mpeg" "mpegv"
"mpg" "mpv" "qt" "vbs")
#1# "%f")
(("odt" "odp" "docx" "doc" "ods" "xlsx" "pptx" "csv") #1="xdg-open" "%f")
))
(dirvish-define-preview exa (file)
"Use `exa' to generate directory preview."
:require ("exa") ; tell Dirvish to check if we have the executable
(when (file-directory-p file) ; we only interest in directories here
`(shell . ("exa" "-lr" "--color=always" "--sort=newest" ,file))))
(add-to-list 'dirvish-preview-dispatchers 'exa)
;;(setq-default truncate-lines t)
Basics
;; (package-install 'pdf-tools) ;;nixos
(pdf-tools-install)
;; this disables the useless visual state when viewing a pdf
(with-eval-after-load 'pdf-view
(evil-define-key 'visual pdf-view-mode-map
"y" 'pdf-view-kill-ring-save
(kbd "<C-down-mouse-1>") 'pdf-view-mouse-extend-region
(kbd "<M-down-mouse-1>") 'pdf-view-mouse-set-region-rectangle
(kbd "<down-mouse-1>") 'pdf-view-mouse-set-region))
(evil-set-initial-state 'pdf-view-mode 'emacs)
(add-hook 'pdf-view-mode-hook
(lambda ()
(set (make-local-variable 'evil-emacs-state-cursor) (list nil))
(blink-cursor-mode -1)))
(add-hook 'pdf-view-mode-hook (lambda () (run-with-timer 0.1 nil #'evil-emacs-state)))
Functions
translate
(defun mvr/translate-pdf ()
(interactive)
(pdf-view-kill-ring-save)
(let ((to-translate (current-kill 0))) ; get last entry from kill ring
(google-translate-translate "auto" "en" to-translate 'help))
(switch-to-buffer-other-window "*Help*"))
other
(defun red_highlight (arg)
(interactive (list (pdf-view-active-region t)))
(pdf-annot-add-markup-annotation arg 'highlight '"red"))
;; Daniel made this one for me in the beginning to search pdfs
(defun pdf-occur (string &optional regexp-p)
"List lines matching STRING or PCRE.
Interactively search for a regexp. Unless a prefix arg was given,
in which case this functions performs a string search.
If `pdf-occur-prefer-string-search' is non-nil, the meaning of
the prefix-arg is inverted."
(interactive
(progn
(pdf-util-assert-pdf-buffer)
(list
(pdf-occur-read-string
(pdf-occur-want-regexp-search-p))
(pdf-occur-want-regexp-search-p))))
(pdf-util-assert-pdf-buffer)
(pdf-view-fit-width-to-window)
(pdf-occur-search (list (current-buffer)) string regexp-p)
(select-window (get-buffer-window "*PDF-Occur*"))
(next-error-follow-minor-mode)
(sit-for 1)
(pdf-occur-view-occurrence)
)
(defun pdf-view-next-line-or-next-page-and-switcht-to-emacs ()
(interactive)
(evil-emacs-state nil)
(pdf-view-next-line-or-next-page 1))
(defun pdf-view-next-line-or-next-page-and-switch-to-emacs ()
(interactive)
(evil-emacs-state nil)
(pdf-view-next-line-or-next-page 1))
(defun pdf-view-scroll-up-or-next-page-and-switch-to-emacs ()
(interactive)
(evil-emacs-state nil)
(pdf-view-scroll-up-or-next-page 1))
(defun pdf_link_page ()
(interactive)
(let ((page (pdf-view-current-page))
(path (buffer-file-name)))
(kill-new (format "[[pdf:%s::%s][]]" path page))
))
(defun evil-collection-pdf-view-goto-last-page ()
(interactive)
(pdf-view-goto-page (pdf-cache-number-of-pages)))
Use doi
(defun substring-from-first-number (str)
(interactive)
(when (string-match "[0-9]" str)
(substring str (match-beginning 0))))
(defun rename-from-doi ()
(interactive)
(let* ((doi (if mark-active (progn (pdf-view-kill-ring-save) (car kill-ring)) (ivy-read "select doi: " (split-string (shell-command-to-string (format "pdftotext -f %s -l %s \"%s\" /tmp/pdftotext.txt && cat /tmp/pdftotext.txt | grep -i doi" (pdf-view-current-page) (pdf-view-current-page) (buffer-file-name))) "\n"))))
(doi (read-from-minibuffer "Adjust doi: " doi))
(doi (if (not (string= (substring doi 0 4) "http")) (format "http://dx.doi.org/%s" (substring-from-first-number doi)) doi)))
(shell-command-to-string (format "curl -LH \"Accept: application/json\" %s > /tmp/article-json" doi))
(let* ((names (split-string (shell-command-to-string "jq -r '.. | objects | select(.family) | .family' /tmp/article-json") "\n"))
;;(names (butlast names))
(name (if (> (length names) 3)
(format "%s et al." (car names))
(if (> (length names) 2)
(format "%s & %s" (car names) (nth 1 names))
(format "%s" (car names)))))
(title (replace-regexp-in-string ":" "-" (shell-command-to-string "jq -r .title /tmp/article-json | tr -d \"\n\"")))
(year (shell-command-to-string "cat /tmp/article-json | jq -r '.license[0].start[\"date-time\"]' | cut -f1 -d \"-\" | tr -d \"\n\"")))
(rename-mv (format "%s - %s - %s.pdf" name year title))
)))
(defun rename-from-doi ()
(interactive)
(let* ((doi
(if mark-active
(progn (pdf-view-kill-ring-save) (car kill-ring))
(ivy-read "select doi: " (split-string (shell-command-to-string (format "pdftotext -f %s -l %s \"%s\" /tmp/pdftotext.txt && cat /tmp/pdftotext.txt | grep -i doi" (pdf-view-current-page) (pdf-view-current-page) (buffer-file-name))) "\n"))))
(doi (read-from-minibuffer "Adjust doi: " doi))
(doi (if (not (string= (substring doi 0 4) "http"))
(format "http://dx.doi.org/%s" (substring-from-first-number doi))
doi)))
(shell-command-to-string (format "curl -LH \"Accept: application/json\" %s > /tmp/article-json" doi))
(let* ((names (split-string (shell-command-to-string "jq -r '.. | objects | select(.family) | .family' /tmp/article-json") "\n"))
;;(names (butlast names))
(name (if (> (length names) 3)
(format "%s et al." (car names))
(if (> (length names) 2)
(format "%s & %s" (car names) (nth 1 names))
(format "%s" (car names)))))
(title (replace-regexp-in-string ":" "-" (shell-command-to-string "jq -r .title /tmp/article-json | tr -d \"\n\"")))
(year (shell-command-to-string "cat /tmp/article-json | jq -r '.license[0].start[\"date-time\"]' | cut -f1 -d \"-\" | tr -d \"\n\"")))
(rename-mv (format "%s - %s - %s.pdf" name year title)))))
(defun rename-from-doi-manual ()
(interactive)
(let* ((doi (read-from-minibuffer "doi: "))
(doi (if (not (string= (substring doi 0 4) "http")) (format "http://dx.doi.org/%s" (substring-from-first-number doi)) doi)))
(shell-command-to-string (format "curl -LH \"Accept: application/json\" %s > /tmp/article-json" doi))
(let* ((names (split-string (shell-command-to-string "jq -r '.. | objects | select(.family) | .family' /tmp/article-json") "\n"))
;;(names (butlast names))
(name (if (> (length names) 3)
(format "%s et al." (car names))
(if (> (length names) 2)
(format "%s & %s" (car names) (nth 1 names))
(format "%s" (car names)))))
(title (replace-regexp-in-string ":" "-" (shell-command-to-string "jq -r .title /tmp/article-json | tr -d \"\n\"")))
(year (shell-command-to-string "cat /tmp/article-json | jq -r '.license[0].start[\"date-time\"]' | cut -f1 -d \"-\" | tr -d \"\n\"")))
(rename-mv (format "%s - %s - %s.pdf" name year title))
)))
(defun get-citation-from-doi-manual-input ()
(interactive)
(let* ((doi (read-from-minibuffer "doi: "))
(doi (if (not (string= (substring doi 0 4) "http")) (format "http://dx.doi.org/%s" (substring-from-first-number doi)) doi)))
(shell-command-to-string (format "curl -LH \"Accept: text/x-bibliography; style=apa\" %s > /tmp/cite" doi))
(let ((cite (shell-command-to-string "cat /tmp/cite")))
(message cite)
(kill-new cite))))
Keybindings
;; this makes SPC available
;; (add-hook 'pdf-view-mode-hook
;; (lambda ()
;; (evil-define-key 'normal pdf-view-mode-map (kbd "SPC") nil)))
;; (add-hook 'pdf-view-mode-hook
;; (lambda ()
;; (evil-define-key 'emacs pdf-view-mode-map (kbd "SPC") nil)))
(defun load-keys ()
(interactive)
(define-key evil-emacs-state-local-map "e" 'pdf-view-previous-line-or-previous-page)
(define-key evil-normal-state-local-map "w" 'pdf-view-next-line-or-next-page-and-switch-to-emacs)
(define-key evil-emacs-state-local-map "w" 'pdf-view-next-line-or-next-page)
(define-key evil-emacs-state-local-map "k" 'pdf-view-previous-line-or-previous-page)
(define-key evil-emacs-state-local-map "j" 'pdf-view-next-line-or-next-page)
(define-key evil-emacs-state-local-map "1" 'pdf-annot-add-underline-markup-annotation)
(define-key evil-emacs-state-local-map "2" 'pdf-annot-add-highlight-markup-annotation)
(define-key evil-emacs-state-local-map "4" 'pdf-annot-delete)
(define-key evil-emacs-state-local-map "5" 'red_highlight)
(define-key evil-emacs-state-local-map "s" 'org-noter-insert-note)
(define-key evil-emacs-state-local-map "r" 'pdf-view-scroll-down-or-previous-page)
(define-key evil-emacs-state-local-map "q" 'pdf-view-scroll-up-or-next-page)
(define-key evil-emacs-state-local-map "y" 'pdf-view-kill-ring-save)
(define-key evil-normal-state-local-map "q" 'pdf-view-scroll-up-or-next-page-and-switch-to-emacs)
(define-key evil-emacs-state-local-map "f" 'save-noter)
(define-key evil-emacs-state-local-map "gt" 'pdf-view-goto-page)
(define-key evil-emacs-state-local-map "aa" 'mvr/translate-pdf)
(define-key evil-emacs-state-local-map "o" 'pdf-outline)
(define-key evil-emacs-state-local-map "9" 'close-noter)
(define-key evil-emacs-state-local-map "d" 'define-word-at-point)
(define-key evil-emacs-state-local-map "gg" 'evil-collection-pdf-view-goto-first-page)
(define-key evil-emacs-state-local-map "G" 'evil-collection-pdf-view-goto-last-page)
(define-key evil-emacs-state-local-map "[" 'evil-collection-pdf-jump-backward)
)
(add-hook 'pdf-view-mode-hook 'load-keys)
(define-key pdf-view-mode-map (kbd "SPC") nil)
(define-key pdf-view-mode-map (kbd "SPC") 'spc-root)
;; (define-key evil-emacs-state-map "e" 'pdf-view-previous-line-or-previous-page)
;; (define-key evil-emacs-state-map "w" 'pdf-view-next-line-or-next-page)
;; (define-key evil-emacs-state-map "j" 'pdf-view-previous-line-or-previous-page)
;; (define-key evil-emacs-state-map "k" 'pdf-view-next-line-or-next-page)
;; (define-key evil-emacs-state-map "1" 'pdf-annot-add-underline-markup-annotation)
;; (define-key evil-emacs-state-map "4" 'pdf-annot-delete)
;; (define-key evil-emacs-state-map "5" 'red_highlight)
;; (define-key evil-emacs-state-map "s" 'org-noter-insert-note)
;; (define-key evil-emacs-state-map "q" 'pdf-view-scroll-down-or-previous-page)
;; (define-key evil-emacs-state-map "r" 'pdf-view-scroll-up-or-next-page)
(spc-define-keys spc-leader-map
"mss" 'pdf-occur
"fh" 'pdf-view-fit-height-to-window
"fw" 'pdf-view-fit-width-to-window
"1" 'pdf-annot-add-underline-markup-annotation
"2" 'pdf-annot-add-highlight-markup-annotation
"4" 'pdf-annot-delete
"5" 'red_highlight
"." 'sync-note-mv)
(add-hook 'pdf-view-mode-hook
(lambda ()
(local-set-key (kbd "C-c 1") 'pdf-annot-add-underline-markup-annotation)
(local-set-key (kbd "C-c 4") 'pdf-annot-delete)
(local-set-key (kbd "C-c 5") 'red_highlight)
(local-set-key "j" nil)
(local-set-key "j" 'pdf-view-next-line-or-next-page)
(local-set-key (kbd "C-c s") 'org-noter-insert-note)))
Adjust mode line
(defvar old-mode-line-format mode-line-format)
(defun my-pdf-view-page-count ()
(if (eq major-mode 'pdf-view-mode)
(let ((my-window-number (winum-get-number-string))
(my-file-name (buffer-name))
(my-state (cond ((eq evil-state 'normal) "N")
((eq evil-state 'emacs) "E")
(t (symbol-name evil-state)))))
(format "%s | <%s> | %d/%d | %s"
my-window-number
my-state
(pdf-view-current-page)
(pdf-cache-number-of-pages)
my-file-name))
old-mode-line-format))
(setq-default mode-line-format
'(:eval (my-pdf-view-page-count)))
ORG
(require 'org)
Settings
Auto update inline images
For example for when you're running code and immediately want to check the output.
(eval-after-load 'org
(add-hook 'org-babel-after-execute-hook 'org-redisplay-inline-images))
Babel
(org-babel-do-load-languages
'org-babel-load-languages
'(
;;(racket . t)
(python . t)
(shell . t)
;;(jupyter .t)
))
Indent and visual line mode
(add-hook 'org-mode-hook
(lambda ()
(org-indent-mode)
(visual-line-mode)))
Opening links with RET
(with-eval-after-load 'evil-maps
(define-key evil-motion-state-map (kbd "RET") nil))
(setq org-return-follows-link t)
Functions
search headers (ji)
(defun ji-mv ()
(interactive)
(add-hook 'minibuffer-exit-hook 'turn-on-prescient-mode-mv)
(ivy-prescient-mode -1)
(if (eq major-mode 'org-mode)
(counsel-org-goto)
(if (eq major-mode 'mu4e-headers-mode)
(select-mu4e-box)
(if (eq major-mode 'latex-mode)
(swiper "section ")))))
org themes
create-theme
(defun mv/create-theme ()
(interactive)
(if (bolp)
(insert (format "tt_%s" (replace-regexp-in-string " " "_" (read-from-minibuffer "Enter theme: "))))
(insert (format " tt_%s" (replace-regexp-in-string " " "_" (read-from-minibuffer "Enter theme: "))))))
get-themes
(defun mv/get-themes ()
(let ((re "tt_\\S-+") ; updated regex to avoid trailing spaces
forms
matches)
(save-excursion
(goto-char (point-min))
(while (re-search-forward re nil t)
(push (match-string-no-properties 0) forms)))
(setq theme-matches (delete-dups forms))))
Paste link
(spc-define-keys spc-leader-map "ol" 'paste-link)
(defun paste-link ()
(interactive)
(if (or (string= major-mode "org-mode") (string= major-mode "mu4e-compose-mode"))
(progn
(if (= (length (buffer-substring-no-properties (line-beginning-position) (line-end-position))) 0)
(progn
(insert (format "[[%s][]]" (substring-no-properties (current-kill 0 t))))
(evil-backward-char 2)
(evil-append 1)
(print "yes"))
(progn
(insert (format " [[%s][]]" (substring-no-properties (current-kill 0 t))))
(evil-backward-char 3)
(evil-append 1)
)
))
(if (string= major-mode "mail-mode")
(progn
(insert (format " [](%s)" (substring-no-properties (current-kill 0 t))))
;; (evil-find-char-backward 1 ?\[)
;; (evil-append 1)
))))
Paste image
(defun image-enable ()
(interactive)
(org-display-inline-images t t))
(defun mv/buffer-has-path ()
"Check if the open buffer has a specific path in its full path."
(let ((buffer-path (buffer-file-name)))
(if buffer-path
(string-match-p "/home/misha/Nextcloud/mnotes/org-roam/presentations" buffer-path)
nil)))
(defun insert-image-mv ()
(interactive)
(let* ((path (substring-no-properties (current-kill 0 t)))
(filename (file-name-nondirectory path)))
(if (mv/buffer-has-path)
(insert (format "#+ATTR_HTML: :width 350\n[[./../../../images/%s]]" filename))
(insert (format "#+ATTR_HTML: :width 350\n[[%s]]" path)))))
(defun insert-image-stretch-mv ()
(interactive)
(let ((var (file-name-nondirectory (substring-no-properties (current-kill 0 t)))))
(if (string-match-p "images" var)
(insert (format "#+REVEAL_HTML: <img class=\"r-stretch\" src=\"%s\">" var))
(insert (format "#+REVEAL_HTML: <img class=\"r-stretch\" src=\"./../../../images/%s\">" var)))))
Internal reference
(defun buffer-contains-substring (string)
(save-excursion
(save-match-data
(goto-char (point-min))
(search-forward string nil t))))
(defun internal-reference-mv ()
(interactive)
(let ((num 1))
(while (buffer-contains-substring (format "i%sr" (number-to-string num)))
(message (format "i%sr" (number-to-string num)))
(setq num (+ num 1)))
(insert (format "i%sr" (number-to-string num)))
(kill-new (format "i%sr" (number-to-string num)))))
org-meta-return
Check if dash or number
(defun first-char-match ()
(interactive)
(save-excursion
(beginning-of-line)
(skip-chars-forward "[:space:]")
(looking-at "[-0-9]")))
down
(defun org-meta-return-mv-down ()
(interactive)
(if (first-char-match)
(progn
(if (or (eq major-mode 'org-mode) (eq major-mode 'org-msg-edit-mode))
(progn
(end-of-line)
(evil-append-line 1)
(org-meta-return)
(evil-insert 1))))
(if (eq major-mode 'LaTeX-mode)
(progn
(beginning-of-line)
(if (looking-at "^\\s-*\\\\item")
(progn
(end-of-line)
(insert "\n\\item ")
(fix-indent-mv)
(evil-append 1))
(evil-open-below 1)))
(if (org-at-table-p)
(progn (org-table-next-row)
(if (bolp) (evil-forward-char 2))
(evil-insert 1))
(progn
(evil-append-line 1)
(newline))))))
up
(defun org-meta-return-mv-up ()
(interactive)
(if (first-char-match)
(progn
(if (or (eq major-mode 'org-mode) (eq major-mode 'org-msg-edit-mode))
(progn
(beginning-of-line)
(evil-insert-line 1)
(org-meta-return)
(evil-insert 1))))
(if (eq major-mode 'latex-mode)
(progn
(beginning-of-line)
(if (looking-at "^\\s-*\\\\item")
(progn
(previous-line)
(end-of-line)
(insert "\n\\item ")
(fix-indent-mv)
(evil-append 1))
(evil-open-below 1)))
(if (org-at-table-p)
(progn (org-table-insert-row)
(if (bolp) (evil-forward-char 2))
(evil-insert 1))
(progn
(beginning-of-line)
(insert "\n")
(previous-line)
(evil-insert 1))))))
COMMENT Next/previous bullet
(defun paragraph-first-char-is-dash-p ()
(interactive)
(save-excursion
;;(evil-backward-sentence-begin)
(beginning-of-line)
(skip-chars-forward "[:space:]")
(looking-at "-")))
(defun org-next-item-mv ()
(interactive)
(if (eq major-mode 'latex-mode)
(progn
(beginning-of-line)
(if (looking-at "^\\s-*\\\\item")
(progn
(end-of-line)
;(TeX-newline)
(insert "\n\\item ")
(fix-indent-mv)
(evil-append 1)
)
(evil-open-below 1)
))
(progn
(if (paragraph-first-char-is-dash-p)
(progn
(end-of-line)
(evil-append 1)
(org-meta-return))
(if (org-at-table-p)
(progn (org-table-next-row)
(if (bolp) (evil-forward-char 2))
(evil-insert 1))
(evil-open-below 1))))))
(defun org-previous-item-mv ()
(interactive)
(if (paragraph-first-char-is-dash-p)
(progn
(beginning-of-line)
(org-insert-item)
(evil-append 1)
)
(if (org-at-table-p)
(progn
(org-table-insert-row)
(evil-insert 1))
(evil-open-above 1))))
Delete to eol
(defun delete-point-eol ()
(interactive)
(kill-region (point) (line-end-position))
(evil-insert 1))
Archive done tasks
(defun org-archive-done-tasks-subtree ()
(interactive)
(org-map-entries
(lambda ()
(org-archive-subtree)
(setq org-map-continue-from (org-element-property :begin (org-element-at-point))))
"/DONE" 'tree))
(defun org-archive-done-tasks-file ()
(interactive)
(org-map-entries
(lambda ()
(org-archive-subtree)
(setq org-map-continue-from (org-element-property :begin (org-element-at-point))))
"*/DONE" 'file))
Keybindings
(evil-define-key 'visual org-mode-map "s" 'evil-surround-region)
(spc-define-keys spc-leader-map
"is" 'org-insert-subheading
"ih" 'org-insert-heading
"osl" 'org-store-link
"oil" 'org-insert-link
"oit" 'mv/insert-themes
"oft" 'mv/filter-themes
"oct" 'mv/create-theme
"oir" 'internal-reference-mv
"ii" 'insert-image-mv
"iy" 'insert-image-stretch-mv
"it" 'org-toggle-inline-images
"ie" 'image-enable
)
(with-eval-after-load 'org
(setq org-src--preserve-indentation t)
(setq org-edit-src-content-indentation 0))
;; (define-key evil-normal-state-map "H" 'dirvish-open-nautilus)
(define-key evil-normal-state-map "o" nil)
;;(define-key evil-normal-state-map "o" 'org-next-item-mv)
(define-key evil-normal-state-map "o" 'org-meta-return-mv-down)
(define-key evil-normal-state-map "O" nil)
;;(define-key evil-normal-state-map "O" 'org-previous-item-mv)
(define-key evil-normal-state-map "O" 'org-meta-return-mv-up)
(define-key evil-normal-state-map "C" nil)
(define-key evil-normal-state-map "C" 'delete-point-eol)
(define-key evil-normal-state-map "}" nil)
(define-key evil-normal-state-map "}" 'org-next-link)
(define-key evil-normal-state-map "{" nil)
(define-key evil-normal-state-map "{" 'org-previous-link)
(define-key evil-normal-state-map "[" nil)
(define-key evil-normal-state-map (kbd "SPC [") 'flyspell-goto-previous-error)
(define-key evil-normal-state-map (kbd "SPC ]") 'flyspell-goto-next-error)
ORG-ROAM
Basics
;; (package-install 'org-roam) ;;nixos
(require 'org-roam)
;; (package-install 'org-roam-ui) ;;nixos
(require 'org-roam-ui)
(setq org-roam-db-update-on-save nil)
(setq org-roam-ui-browser-function 'browse-url-firefox)
(require 'websocket)
(require 'org-roam-ui)
(setq org-roam-ui-sync-theme t
org-roam-ui-follow t
org-roam-ui-update-on-save t
org-roam-ui-open-on-start t)
(require 'org-roam-protocol)
(setq org-roam-directory "~/Nextcloud/mnotes/org-roam/")
(setq org-roam-file-exclude-regexp ".*drill\.org")
(setq org-roam-dailies-directory "daily/")
(add-to-list 'display-buffer-alist
'("\\*org-roam\\*"
(display-buffer-in-side-window)
(side . right)
(slot . 0)
(window-width . 0.33)
(window-parameters . ((no-other-window . t)
(no-delete-other-windows . t)))
))
(setq org-roam-capture-templates '(("d" "default" plain "%?"
:if-new (file+head "${slug}.org"
"#+TITLE: ${title} \n#+CREATED: %U\n#+LAST_MODIFIED: %U\n\n")
:unnarrowed t)))
(setq org-roam-mode-section-functions
(list #'org-roam-backlinks-section
#'org-roam-reflinks-section
#'org-roam-unlinked-references-section
))
(setq org-roam-node-display-template
;; (concat "${title:*} " (propertize "${tags:20}" 'face 'org-tag)))
(concat "${title:100} " (propertize "${tags:20}" 'face 'org-tag)))
(advice-add #'org-roam-fontify-like-in-org-mode :around (lambda (fn &rest args) (save-excursion (apply fn args))))
Functions
(defun find-org-roam-mv ()
(interactive)
(add-hook 'minibuffer-exit-hook 'turn-on-prescient-mode-mv)
(ivy-prescient-mode -1)
(org-roam-node-find)
(ivy-prescient-mode 1))
(defun insert-org-roam-mv ()
(interactive)
(add-hook 'minibuffer-exit-hook 'turn-on-prescient-mode-mv)
(ivy-prescient-mode -1)
(when (not (bolp))
(insert " "))
(org-roam-node-insert)
(ivy-prescient-mode 1))
ORG-NOTER
Loading files
(load-file (format "%s/other-config/emacs/org-noter/org-noter.el" mv/nixos-base-folder))
(load-file (format "%s/other-config/emacs/org-noter/org-pdftools.el" mv/nixos-base-folder))
(load-file (format "%s/other-config/emacs/org-noter/org-noter-pdftools.el" mv/nixos-base-folder))
(load-file (format "%s/other-config/emacs/org-noter/org-noter-embed-misha.el" mv/nixos-base-folder))
Defining functions
(defun mv/add-general-notes ()
(interactive)
(evil-goto-first-line)
(search-forward "NOTER_DOCUMENT")
(org-next-visible-heading 1)
(evil-open-above 0)
(insert "** General notes\n")
(save-excursion
(insert "** Annotations")
;; (org-next-visible-heading 1)
;; (evil-visual-line (point) (point-max))
(set-mark (point))
(goto-char (point-max))
(activate-mark)
(org-do-demote))
(evil-open-above 1)
)
(defun add-annotation-roam ()
(interactive)
(org-entry-delete nil "ID")
(org-entry-delete nil "ROAM_EXCLUDE")
(org-id-get-create)
(save-buffer)
(org-roam-db-sync))
(defun sync-note-mv ()
(interactive)
(save-excursion
;; (org-previous-visible-heading 1)
;; (if (string= (car (last (split-string (what-cursor-position) "="))) "0")
(if (string= (substring (thing-at-point 'line t) 0 1 ) "*")
;; (message "yes")
(org-open-at-point 1)
(progn
(search-backward-regexp "^\*")
(org-open-at-point 1)))
(evil-window-next 2)
))
(defun close-noter ()
(interactive)
(save-buffer)
(other-window 1)
(save-buffer)
;; (org-noter-kill-session org-noter--session)
(org-noter-kill-session)
(kill-buffer))
(setq mv-midnight-mode nil)
(defun toggle-mv-midnight-mode ()
(interactive)
"Toggle the value of VAR between t and nil. i2r"
(if mv-midnight-mode
(progn
(setq mv-midnight-mode nil)
(command-execute 'pdf-view-midnight-minor-mode))
(progn
(setq mv-midnight-mode t)
(pdf-view-midnight-minor-mode nil)
(pdf-view-midnight-minor-mode)))
(message "mv-midnight-mode: %s" mv-midnight-mode))
(defun save-noter ()
(interactive)
(save-buffer)
(other-window 1)
(save-buffer)
(other-window 1)
(if mv-midnight-mode
(progn
(pdf-view-midnight-minor-mode)
(pdf-view-midnight-minor-mode))))
(defun fix-10-noter ()
(interactive)
(save-excursion
(goto-char (point-min))
(while (search-forward "++9" nil t)
(replace-match "++9" nil t))
(goto-char (point-min))
(while (search-forward "++9" nil t)
(replace-match "++9" nil t))))
Set bindings, add hooks
(add-hook 'org-noter-doc-mode-hook
(lambda ()
(local-set-key (kbd "C-c a") 'org-noter-insert-note)))
;; This is necessary for going from org to pdf
(add-hook 'org-mode-hook #'org-pdftools-setup-link)
;; This enables clicking from pdf to org
(with-eval-after-load 'pdf-annot
(add-hook 'pdf-annot-activate-handler-functions #'org-noter-pdftools-jump-to-note))
(spc-define-keys spc-leader-map
"oaa" 'org-noter
"9" 'close-noter
)
Setting variables
(setq org-noter-default-notes-file-names nil)
(setq org-noter-notes-search-path (list (format "%s/mnotes/org-roam/pdf_notes/" mv/nextcloud-base)))
(setq org-noter-pdftools-markup-pointer-color "#93f086")
(setq org-noter-doc-split-fraction '(0.66 . 0.66))
(setq org-noter-always-create-frame t)
(setq org-noter-notes-window-location 'horizontal-split)
(setq org-noter-closest-tipping-point 0)
(setq org-noter-insert-note-no-questions t)
(setq org-noter-hide-other nil)
GPTEL
;; (package-install 'gptel) ;; nixos
(require 'gptel)
COMMENT Use UvA-chat
(gptel-make-azure "UvAchat" ;Name, whatever you'd like
:protocol "https" ;Optional -- https is the default
:host "ai-research-proxy.azurewebsites.net"
:endpoint "/openai/deployments/gpt4o/chat/completions"
:stream t ;Enable streaming responses
:key #'gptel-api-key-uva-chat
:models '(gpt4o))
(setq gptel-log-level 'debug)
(setq gptel-api-key-uva-chat (string-trim-right (shell-command-to-string "pass misc/uvachat")))
COMMENT Use ollama
(setq
gptel-model 'deepseek-r1:latest
gptel-backend (gptel-make-ollama "Ollama"
:host "localhost:11434"
:stream t
:models '(deepseek-r1:latest)))
Use OpenAI
(setq gptel-api-key (string-trim-right (shell-command-to-string "pass mail/chatgpt-api-key-emacs")))
(setq gptel-model 'gpt-4o)
General
;; I think this has to be loaded again because markdown is not loaded yet when this is defined?
(setq gptel-default-mode 'org-mode)
;; window can only split above-below if the window has more than # lines
(setq split-height-threshold nil)
;; window can only split left-right if the window has more than # columns
(setq split-width-threshold 100)
;; (setq gptel-model "gpt-4") (I've set this with customized)
(spc-define-keys spc-leader-map
"ot" 'send-mv)
;; (setq gptel--system-message "You are a large language model living in Emacs and a helpful assistant. Respond concisely. Also, you are very knowledgeable. An expert. Think and respond with confidence.")
ORG-AGENDA
Disable space
(add-hook 'org-agenda-mode-hook
(lambda ()
(evil-define-key 'normal org-agenda-mode-map (kbd "SPC") nil)))
(evil-set-initial-state 'org-agenda-mode 'normal)
Keybindings
(add-hook 'org-agenda-mode-hook
(lambda ()
(local-set-key (kbd "C-c f") 'org-agenda-later)
(local-set-key (kbd "C-c b") 'org-agenda-earlier)
(local-set-key (kbd "C-c .") 'org-agenda-goto-today)
(local-set-key (kbd "C-c q") 'org-agenda-quit)
))
(evil-define-key 'normal org-agenda-mode-map "n" 'org-agenda-later-mv)
(evil-define-key 'normal org-agenda-mode-map "p" 'org-agenda-earlier-mv)
(evil-define-key 'normal org-agenda-mode-map "." 'org-agenda-goto-today)
(evil-define-key 'normal org-agenda-mode-map "q" 'org-agenda-quit)
(evil-define-key 'normal org-agenda-mode-map "J" 'org-agenda-goto-date)
(evil-define-key 'normal org-agenda-mode-map "w" 'org-agenda-week-view)
(evil-define-key 'normal org-agenda-mode-map "d" 'org-agenda-day-view)
(evil-define-key 'normal org-agenda-mode-map "t" 'org-agenda-todo)
(evil-define-key 'normal org-agenda-mode-map "m" 'org-agenda-month-view)
(evil-define-key 'normal org-agenda-mode-map "r" 'org-agenda-redo)
(evil-define-key 'normal org-agenda-mode-map "s" 'org-search-view)
(spc-define-keys spc-leader-map
"occ" 'my-org-capture
"oc1" 'org-capture
"mau" 'mv/caldav-async
"maq" 'open-cal-mv-quick
"mad" 'open-cal-mv-thorough
)
Setting variables
(require 'color)
(setq org-agenda-span 'month)
(setq calendar-week-start-day 1)
(setq org-deadline-warning-days 0)
(setq org-read-date-popup-calendar nil)
(setq org-agenda-files-basic
(mapcar (lambda (file)
(format "/home/misha/Nextcloud/calendar/%s/%s" (system-name) file))
'("personal.org" "work.org" "teaching.org" "bij1.org" "reminders.org" "amor.org")))
Defining functions
agenda week later and sooner
(defun org-agenda-later-mv ()
(interactive)
(org-agenda-later 1)
(run-with-timer 0.1 nil #' evil-goto-first-line))
(defun org-agenda-earlier-mv ()
(interactive)
(org-agenda-earlier 1)
(run-with-timer 0.1 nil #' evil-goto-first-line))
Colombia functions
(setq in-colombia nil)
(defun toggle-colombia ()
(interactive)
"Toggle the value of VAR between t and nil."
(if in-colombia
(setq in-colombia nil)
(setq in-colombia t))
(message "in-colombia: %s" in-colombia))
(defun timezone-diff-mv ()
(interactive)
(let* ((hours1 (string-to-number (substring (shell-command-to-string "echo -n $(TZ=\"Europe/Amsterdam\" date +%z)") 1 3)))
(hours2 (string-to-number (substring (shell-command-to-string "echo -n $(TZ=\"America/Bogota\" date +%z)") 1 3)))
(diff (+ hours1 hours2)))
diff))
(defun timezone-mv ()
(interactive)
(evil-write-all nil)
(mapc (lambda (var)
(let* ((name1 (car (split-string (file-name-nondirectory var) "\\.")))
(name2 (format "%s_col.org" name1))
(file2 (format "/home/misha/caltemp/%s" name2))
;; (file2 (format "%s%s" (file-name-directory var) name2))
(revert-without-query '(".*"))
(revert-without-query '(".*")))
(copy-file var file2 t)
(find-file file2)
(goto-char (point-min))
(while (re-search-forward (org-re-timestamp 'all) nil t)
;; don't apply the timestamp change when it's just a day.
(if (string-match ":" (thing-at-point 'line t))
(org-timestamp-change (* -1 (timezone-diff-mv)) 'hour)))
(org-map-entries
(lambda ()
(org-delete-property "ID")
'file))
(save-buffer)
(kill-buffer name2)
)) org-agenda-files-basic))
Main functions
open-cal-mv-thorough
(defun open-cal-mv-thorough ()
(interactive)
(if in-colombia (progn
(setq org-agenda-files (mapcar (lambda (var)
(let* ((name1 (car (split-string (file-name-nondirectory var) "\\.")))
(name2 (format "%s_col.org" name1))
;; (file2 (format "%s%s" (file-name-directory var) name2))
(file2 (format "/home/misha/caltemp/%s" name2))
) file2)) org-agenda-files-basic))
(timezone-mv))
(setq org-agenda-files org-agenda-files-basic))
(org-agenda nil "a")
(org-agenda-week-view)
;; (org-agenda-month-view)
)
open-cal-mv-quick
(defun open-cal-mv-quick ()
(interactive)
;;(refresh-theme)
;;(mv/caldav-async)
(if in-colombia (progn
(setq org-agenda-files
(mapcar (lambda (var)
(let* ((name1
(car (split-string (file-name-nondirectory var) "\\.")))
(name2 (format "%s_col.org" name1))
;; (file2 (format "%s%s" (file-name-directory var) name2))
(file2 (format "/home/misha/caltemp/%s" name2))) file2)) org-agenda-files-basic)))
(setq org-agenda-files org-agenda-files-basic))
(if (and (not (one-window-p)) (not (org-calendar-window-open-p)))
(progn
(let ((org-agenda-window-setup 'current-window))
(split-window-below) ;; Split the window horizontally
(other-window 1) ;; Move to the new window
(org-agenda nil "a")
(org-agenda-week-view)
;; (org-agenda-list)
;; (org-agenda-week-view)
))
(progn
(message "There is only one window open.")
(org-agenda nil "a")
(org-agenda-week-view)
(calendar-basic-setup nil t))))
(defun org-calendar-window-open-p ()
(interactive)
(if (seq-some (lambda (win)
(string= (buffer-name (window-buffer win)) "*Org Agenda*"))
(window-list))
(message "An Org Agenda window is open.")
nil))
set org capture templates
(setq org-capture-templates
`(
("w" "Work agenda" entry (file ,(format "~/Nextcloud/calendar/%s/work.org" (system-name)))
"* %?")
("t" "time track" entry (file+headline "/home/misha/Nextcloud/mnotes/Tracking_January_2023.org" "Entries")
"* %? %^g" :clock-in t :prepend t)
("p" "Personal agenda" entry (file ,(format "~/Nextcloud/calendar/%s/personal.org" (system-name)))
"* %?")
("r" "Reminders" entry (file ,(format "~/Nextcloud/calendar/%s/reminders.org" (system-name)))
"* %?")
("a" "Amor" entry (file ,(format "~/Nextcloud/calendar/%s/amor.org" (system-name)))
"* %?")
("b" "BIJ1 agenda" entry (file ,(format "~/Nextcloud/calendar/%s/bij1.org" (system-name)))
"* %?")
("u" "Todo Uni" entry (file+headline "~/Nextcloud/mnotes/todo.org" "Uni")
"** TODO %?" :prepend t)
("o" "Todo overig" entry (file+headline "~/Nextcloud/mnotes/todo.org" "Overig")
"** TODO %?" :prepend t)
("c" "Todo computer" entry (file+headline "~/Nextcloud/mnotes/todo.org" "Computer")
"** TODO %?" :prepend t)
("m" "Add spatial memory" plain (file "~/Nextcloud/mnotes/spatial_memory.org")
"* %?")
("i" "BIJ1 todo" entry (file+headline "~/Nextcloud/mnotes/todo.org" "Bij1")
"** TODO %?" :prepend t)
("l" "Watching list" entry (file+headline "~/Nextcloud/mnotes/todo.org" "Watching list")
"** %?")
("s" "Add Spanish word" entry (file "/home/misha/Nextcloud/mnotes/orgzly/Español.org")
"* %?" :prepend t)
))
my-org-capture
(defun get-date-from-agenda ()
(interactive)
(let* ((date (calendar-gregorian-from-absolute (get-text-property (min (1- (point-max)) (point)) 'day)))
(day (format "%02d" (nth 0 date)))
(month (format "%02d" (nth 1 date)))
(year (nth 2 date)))
(format "<%s-%s-%s>" year day month)))
(defun my-org-capture ()
(interactive)
(let ((org-agenda-files-basic '("/home/misha/Nextcloud/calendar/personal.org"
"/home/misha/Nextcloud/calendar/work.org"
"/home/misha/Nextcloud/calendar/teaching.org"
"/home/misha/Nextcloud/calendar/bij1.org"
"/home/misha/Nextcloud/calendar/reminders.org"
"/home/misha/Nextcloud/calendar/amor.org"
)))
(let ((agenda-date (if (derived-mode-p 'org-agenda-mode) (get-date-from-agenda) nil)))
(if (and (> (count-windows) 1) (not (org-calendar-window-open-p)))
(split-window-below))
(org-capture)
(if (not (string-match "CAPTURE-todo" (buffer-name)))
(progn
(evil-open-below 1)
(if (not (eq agenda-date nil))
(progn
(let ((time (if in-colombia (read-from-minibuffer "Time in Colombia: ") (read-from-minibuffer "Time: "))))
(if (not (string= "" time))
(progn
(insert (format agenda-date))
(left-char)
(insert (format " %s" time))
(org-set-property "TIMEZONE" "Europe/Amsterdam")
(if in-colombia (org-timestamp-change (* 1 (timezone-diff-mv)) 'hour)))
(progn
(insert agenda-date)))
(evil-goto-first-line)))
(progn
(let ((time (org-time-stamp nil)))
(other-window 1)
(open-agenda-in-buffer time)
(other-window -1)
(evil-goto-first-line)))))))))
(defun close-extra-org-agenda-window ()
"If more than one window is open displaying the *Org Agenda* buffer, close down one."
(let ((agenda-buf (get-buffer "*Org Agenda*")))
(when agenda-buf
(let ((agenda-windows (get-buffer-window-list agenda-buf)))
(when (> (length agenda-windows) 1)
(delete-window (car agenda-windows))))))
(org-agenda-redo))
(add-hook 'org-capture-after-finalize-hook 'close-extra-org-agenda-window)
get-time-appointment
Using chatgpt
(defun chatgpt-input-output ()
(interactive)
(let* ((input (replace-regexp-in-string "\n" "" (buffer-substring (region-beginning) (region-end))))
(setup (replace-regexp-in-string "\n" "" "This is an email about a meeting. Give me the title of the meeting, the time and the location if there is any. Give me the output like a string, without newlines following this setup: 'topic, date, time, location'. Use this format for the date '2023-10-31' and this format for time 22:10'"))
(output (shell-command-to-string (format "bash /home/misha/Nextcloud/scripts_misha/misc_useful/openai-basic-prompt-input-output.sh \"%s\" \"%s\"" setup input)))
(topic (car (split-string output ",")))
(date (nth 1 (split-string output ",")))
(time (nth 2 (split-string output ",")))
(location (nth 3 (split-string output ","))))
(message "test: %s, %s, %s, %s" topic date time location)))
manually
(defun get-time-appointment (&optional col)
(interactive)
(save-excursion)
(goto-char (point-min))
(let* ((summary (progn
(search-forward "Summary: ")
(evil-forward-word-begin 1)
(let ((beg (point)))
(evil-end-of-line)
(buffer-substring-no-properties beg (+ 1 (point))))))
(message-link (format "[[mu4e:msgid:%s][link to mail]]" (mu4e-message-field-at-point :message-id)))
(location (progn
(goto-char (point-min))
(search-forward "Location: ")
;; If location is empty give this variable the value nil
(if (not (looking-at "[[:space:]\n]*$"))
(progn
(evil-forward-word-begin 1)
(let ((beg (point)))
(evil-end-of-line)
(buffer-substring-no-properties beg (+ 1 (point)))))
nil)))
(time (progn
(goto-char (point-min))
(search-forward "Time: ")
(search-forward "<")
(backward-char 1)
(let ((beg (point)))
(search-forward ">")
(buffer-substring-no-properties beg (point)))))
(time (if col
(let* ((subday (cdr (split-string (car (split-string time " ")) "<")))
(subtime1 (car (split-string (car (cdr (split-string time " "))) "-")))
(subtime2 (car (split-string (car (cdr (split-string (car (cdr (split-string time " "))) "-"))) ">")))
(subtime1-cor (shell-command-to-string (format "python3 /etc/nixos/other-config/emacs/timezone/timezone-basis.py %s %s %s %s" subtime1 "America/Bogota" "Europe/Amsterdam" (car subday))))
(subtime2-cor (shell-command-to-string (format "python3 /etc/nixos/other-config/emacs/timezone/timezone-basis.py %s %s %s %s" subtime2 "America/Bogota" "Europe/Amsterdam" (car subday))))
(subtime1-cor (replace-regexp-in-string "h" "" subtime1-cor))
(subtime2-cor (replace-regexp-in-string "h" "" subtime2-cor)))
(format "<%s>-<%s>" subtime1-cor subtime2-cor))
time)))
(open-cal-mv-quick)
(let ((agenda-window (get-buffer-window "*Org Agenda")))
(when agenda-window
(select-window agenda-window)))
(org-agenda-goto-date time)
(org-capture t "w")
(insert summary)
;;(evil-org-open-below 1)
(evil-open-below 1)
(insert time)
;; Only if the variable location is not nil
(if location
(org-set-property "LOCATION" location))
(evil-open-below 1)
(org-set-property "TIMEZONE" "Europe/Amsterdam")
(insert message-link)))
(defun get-time-appointment-col ()
(interactive)
(get-time-appointment t))
Todo overview
(defun open-tasks-mv ()
(interactive)
(setq org-agenda-custom-commands
'(("1" "n" agenda "Todos and scheduled"
((org-agenda-window-setup 'current-window)
(org-agenda-entry-types '(:deadline :scheduled))
(org-agenda-files
'("/home/misha/Nextcloud/mnotes/auc_tutees_keeping_track.org"
"/home/misha/Nextcloud/mnotes/auc_capstone_projects.org"
"/home/misha/Nextcloud/mnotes/orgzly/todo.org"
"/home/misha/Nextcloud/calendar/work.org"
))))))
(org-agenda nil "1")
(org-agenda-day-view))
(spc-define-keys spc-leader-map
"mat" 'open-tasks-mv
)
Recur-mv
(defun recur-mv ()
(interactive)
(org-insert-subheading 1)
(insert (format "%s\n" (read-string "Title: ")))
(org-time-stamp nil)
(org-clone-subtree-with-time-shift (- (string-to-number (read-string "Number or recurrences: ")) 1) "+1w"))
Rest?
(defun his-tracing-function (orig-fun &rest args)
(let ((res (apply orig-fun args)))
(print (file-name-nondirectory (car args)))
(mapcar (lambda (s)
;; (add-face-text-property 1 (string-match-p ":" s) 'warning nil s)
(add-face-text-property 1 5 'warning nil s)
)
res)
res))
(advice-add 'org-agenda-get-day-entries :around #'his-tracing-function)
(defun my-org-capture-place-template-dont-delete-windows (oldfun &rest args)
(cl-letf (((symbol-function 'delete-other-windows) 'ignore))
(apply oldfun args)))
(with-eval-after-load "org-capture"
(advice-add 'org-capture-place-template :around 'my-org-capture-place-template-dont-delete-windows))
(defun close-extra-org-agenda-window ()
(interactive)
"If more than one window is open displaying the *Org Agenda* buffer, close down one."
(let ((agenda-buf (get-buffer "*Org Agenda*")))
(when agenda-buf
(let ((agenda-windows (get-buffer-window-list agenda-buf)))
(when (> (length agenda-windows) 1)
(delete-window (car agenda-windows))))))
(org-agenda-redo))
(add-hook 'org-capture-after-finalize-hook 'close-extra-org-agenda-window)
CALDAV
(load-file "/etc/nixos/other-config/emacs/caldav/org-caldav.el")
(setq org-caldav-calendars-prep
`(
(:calendar-id "personal-2" :files ,(list (format "/home/misha/Nextcloud/calendar/%s/personal.org" (system-name)))
:inbox ,(format "/home/misha/Nextcloud/calendar/%s/personal.org" (system-name)))
(:calendar-id "work-3" :files ,(list (format "/home/misha/Nextcloud/calendar/%s/work.org" (system-name)))
:inbox ,(format "/home/misha/Nextcloud/calendar/%s/work.org" (system-name)))
(:calendar-id "teaching-2" :files ,(list (format "/home/misha/Nextcloud/calendar/%s/teaching.org" (system-name)))
:inbox ,(format "/home/misha/Nextcloud/calendar/%s/teaching.org" (system-name)))
(:calendar-id "bij1-2" :files ,(list (format "/home/misha/Nextcloud/calendar/%s/bij1.org" (system-name)))
:inbox ,(format "/home/misha/Nextcloud/calendar/%s/bij1.org" (system-name)))
(:calendar-id "reminders-1" :files ,(list (format "/home/misha/Nextcloud/calendar/%s/reminders.org" (system-name)))
:inbox ,(format "/home/misha/Nextcloud/calendar/%s/reminders.org" (system-name)))
(:calendar-id "amor-1" :files ,(list (format "/home/misha/Nextcloud/calendar/%s/amor.org" (system-name)))
:inbox ,(format "/home/misha/Nextcloud/calendar/%s/amor.org" (system-name)))
))
(setq org-caldav-calendars org-caldav-calendars-prep)
(setq org-caldav-url "https://nextcloud.mishathings.com/remote.php/dav/calendars/misha2")
(defun caldav-save-and-sync ()
(interactive)
(evil-write-all nil)
(let ((use-dialog-box nil))
(advice-add 'yes-or-no-p :override (lambda (_prompt) t))
(org-caldav-sync)
(advice-remove 'yes-or-no-p (lambda (_prompt) t))))
(defun mv/caldav-async ()
(interactive)
(make-thread
(lambda ()
(caldav-save-and-sync))))
;; Run at startup
(mv/caldav-async)
(setq org-caldav-sync-changes-to-org 'all)
(require 'auth-source)
(setq auth-sources
'((:source "~/.authinfo.gpg")))
Colors
(defun his-tracing-function (orig-fun &rest args)
(let ((res (apply orig-fun args)))
(mapcar (lambda (s)
(add-face-text-property 1 (length s)
;;(string-match-p ":" s)
(pcase (file-name-nondirectory (car args))
("personal.org" 'all-the-icons-green)
("personal_col.org" 'all-the-icons-green)
("work.org" 'all-the-icons-dorange)
("work_col.org" 'all-the-icons-dorange)
("teaching.org" 'all-the-icons-blue)
("teaching_col.org" 'all-the-icons-blue)
("bij1.org" 'help-argument-name)
("bij1_col.org" 'help-argument-name)
("reminders.org" 'gnus-cite-2)
("amor.org" 'dired-marked)
)
nil s))
res)
res))
MU4E
(require 'mu4e)
Contexts
(setq mu4e-contexts
`(
,(make-mu4e-context
:name "uva"
:enter-func (lambda () (mu4e-message "Entering uva context"))
:leave-func (lambda () (mu4e-message "Leaving uva context"))
;; we match based on the contact-fields of the message
:match-func (lambda (msg)
(when msg
(mu4e-message-contact-field-matches msg
:to "m.velthuis@uva.nl")))
;;:to "work@mishavelthuis.nl")))
:vars '( ( user-mail-address . "m.velthuis@uva.nl" )
( user-full-name . "Misha Velthuis" )
( mu4e-sent-folder . "/uva/INBOX" )
;;( mu4e-drafts-folder . "/../external-mail-folder/unnecessary-drafts/for-mu4e/uva")
( mu4e-drafts-folder . "/uva/Concepten")
( mu4e-trash-folder . "/../external-mail-folder/mail-trash/for-mu4e/uva")
;;( mu4e-refile-folder . "/uva/archive-March252024-onwards" )
( mu4e-refile-folder . "/work/Archive-5Feb2025-onwards" )
))
,(make-mu4e-context
:name "work"
:enter-func (lambda () (mu4e-message "Entering work context"))
:leave-func (lambda () (mu4e-message "Leaving work context"))
:match-func (lambda (msg)
(when msg
(mu4e-message-contact-field-matches msg
:to "work@mishavelthuis.nl")))
:vars '( ( user-mail-address . "work@mishavelthuis.nl" )
( user-full-name . "Misha Velthuis" )
( mu4e-sent-folder . "/work/INBOX" )
;;( mu4e-drafts-folder . "/../external-mail-folder/unnecessary-drafts/for-mu4e/work")
( mu4e-drafts-folder . "/work/Drafts")
( mu4e-trash-folder . "/../external-mail-folder/mail-trash/for-mu4e/work")
( mu4e-refile-folder . "/work/Archive-5Feb2025-onwards" )
))
,(make-mu4e-context
:name "transip"
:enter-func (lambda () (mu4e-message "Entering work context"))
:leave-func (lambda () (mu4e-message "Leaving work context"))
;; we match based on the contact-fields of the message
:match-func (lambda (msg)
(when msg
(mu4e-message-contact-field-matches msg
:to "mail@mishavelthuis.nl")))
:vars '( ( user-mail-address . "mail@mishavelthuis.nl" )
( user-full-name . "Misha Velthuis" )
( mu4e-sent-folder . "/transip/INBOX" )
;;( mu4e-drafts-folder . "/../external-mail-folder/unnecessary-drafts/for-mu4e/transip")
( mu4e-drafts-folder . "/transip/Drafts")
( mu4e-trash-folder . "/../external-mail-folder/mail-trash/for-mu4e/transip")
( mu4e-refile-folder . "/transip/Archive-5Feb2025-onwards" )
))
,(make-mu4e-context
:name "bij1"
:enter-func (lambda () (mu4e-message "Entering bij1 context"))
:leave-func (lambda () (mu4e-message "Leaving bij1 context"))
;; we match based on the contact-fields of the message
:match-func (lambda (msg)
(when msg
(mu4e-message-contact-field-matches msg
:to "misha@bij1.org")))
:vars '( ( user-mail-address . "misha@bij1.org" )
( user-full-name . "Misha Velthuis" )
( mu4e-sent-folder . "/bij1/INBOX" )
( mu4e-drafts-folder . "/bij1/Drafts" )
( mu4e-trash-folder . "/../mail-trash/for-mu4e" )
( mu4e-refile-folder . "/bij1/Archief" )))
))
(mu4e-context-switch nil "uva")
(mu4e t)
Sending & pulling
(setq message-sendmail-f-is-evil t
message-sendmail-extra-arguments '("--read-envelope-from")
sendmail-program "msmtp"
send-mail-function 'smtpmail-send-it
message-send-mail-function 'message-send-mail-with-sendmail)
(defun check-canvas ()
(interactive)
(save-excursion
(goto-char (point-min))
(let ((end (progn (forward-line 15) (point))))
(goto-char (point-min))
(if (search-forward "via Canvas Notifications" end t)
(progn
(adsi)
(evil-goto-first-line 1))
(progn
(goto-char (point-min))
(if (search-forward "notifications@instructure.com" end t)
(progn
(adsi)
(evil-goto-first-line 1))
(export-buffer-content-to-html-and-replace)
(message-send-and-exit)
;;(org-ctrl-c-ctrl-c)
;;(message "send")
))))))
(defun mv/delete-cc ()
(interactive)
(goto-char (point-min))
(while (re-search-forward "^Cc:.*" nil t)
(beginning-of-line)
(kill-line 1)))
(defun adsi ()
(interactive)
(let* ((line (ivy-read "select: "
(split-string (shell-command-to-string "python3 /etc/nixos/other-config/emacs/mu4e/new_script.py") "\n")
:initial-input (progn
(goto-char (point-min))
(search-forward "To: ")
(let ((var (thing-at-point 'word t)))
(message var)))))
(line2 (replace-regexp-in-string "'" "" line)))
(insert (shell-command-to-string (format "bash /etc/nixos/other-config/emacs/mu4e/extract_email.sh '%s'" line2)))
(evil-change-line (point) (line-end-position)))
(mv/delete-cc))
Get email addresses
;; (defun ads ()
;; (interactive)
;; (insert (shell-command-to-string (format "bash /etc/nixos/other-config/mail/extract_email.sh '%s'" (ivy-read "select: "(split-string (shell-command-to-string (format "python3 %s/new_script.py" filemv-mu4e)) "\n"))))))
;; get email of groups
(defun adg ()
(interactive)
(insert (shell-command-to-string (format "cat /home/misha/Nextcloud/Addresses/groups/%s" (ivy-read "select" (directory-files "/home/misha/Nextcloud/Addresses/groups"))))))
(spc-define-keys spc-leader-map
"oas" 'adsi
"oag" 'adg)
Folding
See also Theming
;; I am using this thread folding script
(load-file "/etc/nixos/other-config/emacs/mu4e/mu4e-thread-folding.el")
(require 'mu4e-thread-folding)
(mu4e-thread-folding-mode t)
(setq mu4e-thread-folding-keep-faces t)
(add-to-list 'mu4e-header-info-custom
'(:empty . (:name "Empty"
:shortname ""
:function (lambda (msg) " "))))
(setq mu4e-headers-fields '((:empty . 0)
(:human-date . 19)
(:flags . 3)
(:from . 22)
(:to . 20)
(:subject . nil)))
(setq mu4e-headers-date-format "%a %d %b %H:%M %y")
(setq mu4e-thread-folding-root-folded-prefix-string "")
(setq mu4e-thread-folding-root-unfolded-prefix-string "")
(define-key mu4e-headers-mode-map (kbd "<tab>") 'mu4e-headers-toggle-at-point)
Defining functions
search-mail
(setq ag-reuse-buffers 't)
;;(setq ag-arguments "--smart-case" "--ignore-dir=/home/misha/Maildir/transip")
(defun mv/focus-ag-search-buffer ()
"Focus the first buffer that starts with *ag search."
(let ((buf (catch 'found
(dolist (b (buffer-list))
(when (string-prefix-p "*ag search" (buffer-name b))
(throw 'found b))))))
(if buf
(switch-to-buffer buf)
(message "No *ag search buffer found."))))
(setq ag-arguments '("--smart-case" "--stats" "--ignore-dir" "transip/"))
(defun mv/mail-rg ()
(interactive)
;;(rg nil "/home/misha/Maildir/" "-g !/home/misha/Maildir/transip/ -i --sortr=modified -B 2 -A 2" "Type: ")
(ag (read-from-minibuffer "Keyword: ") "/home/misha/Maildir")
(mv/focus-ag-search-buffer)
(delete-other-windows))
;; (defun mv/open-mail-with-id ()
;; (interactive)
;; (save-excursion
;; (compile-goto-error)
;; (goto-char (point-min)) ; Start searching from the beginning of the buffer
;; (when
;; ;;(re-search-forward "message-id: *<\\([^>]+\\)>" nil t)
;; ;;(re-search-forward "message-id: *\\(?:<\\([^>]+\\)>\\|\\([^<>\n]+\\)\\)" nil t)
;; (re-search-forward "message-id: *<\\([^>\n]+\\)\\|message-id: *\n *<\\([^>\n]+\\)" nil t)
;; (let ((input (match-string 1))) ; Get the captured group
;; (message (format "Opening mail with id: %s" input))
;; (mu4e-headers-search (format "msgid:%s" input)))
;; (run-with-timer 0.2 nil 'mu4e-headers-view-message-mv)
;; )))
(defun mv/open-mail-with-id ()
"Open mail with the message ID found in the current buffer.
Only counts if the message ID is followed by '<' on the same line
or on the next line."
(interactive)
(save-excursion
(compile-goto-error)
(goto-char (point-min)) ; Start searching from the beginning of the buffer
(let ((case-fold-search t) ; Optional: make the search case-insensitive
(found-id nil))
(while (re-search-forward "message-id: *<\\([^>\n]+\\)\\|message-id: *\n *<\\([^>\n]+\\)" nil t)
(setq found-id (or (match-string 1) (match-string 2))))
(when found-id
(message "Opening mail with id: %s" found-id)
(mu4e-headers-search (format "msgid:%s" found-id))
(run-with-timer 0.2 nil 'mu4e-headers-view-message-mv)))))
(evil-define-key 'normal ag-mode-map "o" 'mv/open-mail-with-id)
Show thread in all modes
(defun mv/show-thread-all-modes ()
(interactive)
;; (delete-other-windows)
;; (split-window-right)
(if (or (eq major-mode 'mu4e-headers-mode) (eq major-mode 'mu4e-view-mode))
(let ((mu4e-headers-include-related t))
(mu4e-headers-search (format "msgid:%s" (mu4e-message-field-at-point :message-id))))
(let* ((current-file (buffer-file-name))
(temp-buffer (generate-new-buffer "*temp-email*")))
(with-temp-buffer
(insert-file-contents current-file)
(goto-char (point-min))
(let ((in-reply-to-regex "In-Reply-To: *<\\([^>]+\\)>"))
(if (re-search-forward in-reply-to-regex nil t)
(let ((in-reply-to (match-string 1))) ; Extract without <>
(message "In-Reply-To: %s" in-reply-to)
;; (setq my-in-reply-to-variable in-reply-to) ; Save in variable if needed
;; (delete-other-windows)
;; (split-window-right)
(other-window 1)
(message (concat "msgid:" in-reply-to))
(let ((mu4e-headers-include-related t))
(mu4e-headers-search (format "msgid:%s" in-reply-to))))))))))
(spc-define-keys spc-leader-map
"ww" 'mv/show-thread-all-modes)
read-mail-mv
New
(defun mv/read-mail ()
"Open the current file in a temporary buffer, extract the In-Reply-To email address without <>, and then close the buffer."
(interactive)
(save-buffer "/tmp/mail-tmp")
(save-excursion
(message "read-mail is running")
(let* ((current-file (buffer-file-name))
(temp-buffer (generate-new-buffer "*temp-email*")))
(with-temp-buffer
(insert-file-contents current-file)
(goto-char (point-min))
(let ((in-reply-to-regex "In-Reply-To: *<\\([^>]+\\)>"))
(if (re-search-forward in-reply-to-regex nil t)
(let ((in-reply-to (match-string 1))) ; Extract without <>
(message "In-Reply-To: %s" in-reply-to)
;; (setq my-in-reply-to-variable in-reply-to) ; Save in variable if needed
(delete-other-windows)
(split-window-right)
(message (concat "msgid:" in-reply-to))
(mu4e-headers-search (concat "msgid:" in-reply-to))
(mu4e-view-message-with-message-id in-reply-to)
(let ((buf (get-buffer "*mu4e-headers*")))
(when buf
(let ((window (get-buffer-window buf)))
(when window
(delete-window window))))))
(other-window 1)
(message "No In-Reply-To found.")))))))
COMMENT Old (not working anymore)
<2025-01-08 Wed>
(defun read-mail-mv ()
(interactive)
(save-excursion
(delete-other-windows)
(goto-char (point-min))
(if
(re-search-forward "reply-to:" nil t)
(progn
(let
((id (car (split-string (nth 1 (split-string (thing-at-point 'line t) "<")) ">")))
(mu4e-search-include-related t))
(split-window-right)
(other-window 1)
(switch-to-buffer "*mu4e-headers*")
(evil-window-set-width 80)
(mu4e-headers-search (format "msgid:%s" id))
;;(mu4e-headers-toggle-include-related)
(run-with-timer 0.2 nil #'open-mail-no-split)))
(progn
(if (get-buffer "*mu4e-article*")
(switch-to-buffer "*mu4e-article*")
(go-to-inbox)
)))))
Remove trash
;; (defun mv/move-files-from-x-to-y (x y)
;; "Move all files from directory X to directory Y."
;; (let ((files (directory-files x t "\\`[^.]"))) ;; Exclude `.` and `..`
;; (when files
;; (dolist (file files)
;; (when (file-regular-p file)
;; (rename-file file (expand-file-name (file-name-nondirectory file) y)))))))
(defun mv/move-files-from-x-to-y (x y)
"Move all files from directory X to directory Y, overwriting if they exist."
(let ((files (directory-files x t "\\`[^.]"))) ;; Exclude `.` and `..`
(when files
(dolist (file files)
(when (file-regular-p file)
(rename-file file (expand-file-name (file-name-nondirectory file) y) t))))))
search without threads
(defun turn-off-threads ()
(interactive)
(setq mu4e-headers-show-threads nil))
(defun search-mv ()
(interactive)
(turn-off-threads)
(mu4e-search))
Toggle the organization of mail in threads
(defun toggle-threads-mv ()
(interactive)
(if mu4e-headers-show-threads
(setq mu4e-headers-show-threads nil)
(setq mu4e-headers-show-threads t)))
Select inbox, archives, trash, concepts
(defun select-mu4e-box ()
(interactive)
(let* ((folders-alist `(("mu4e-drafts-folder" . ,mu4e-drafts-folder)
("mu4e-trash-folder" . ,mu4e-trash-folder)
("mu4e-refile-folder" . ,mu4e-refile-folder)))
(choice (ivy-read "Select:" folders-alist)))
(mu4e~headers-jump-to-maildir (cdr (assoc choice folders-alist)))))
go-to-headers
(defun go-to-headers ()
(interactive)
(mv/move-files-from-x-to-y (format "/home/misha/external-mail-folder/mail-trash/for-mu4e/%s/cur/" (mu4e-context-name (mu4e-context-current))) (format "/home/misha/external-mail-folder/mail-trash/real/%s/" (mu4e-context-name (mu4e-context-current))))
(mv/move-files-from-x-to-y (format "/home/misha/Maildir%s/cur/" mu4e-drafts-folder) (format "/home/misha/external-mail-folder/unnecessary-drafts/real/%s/" (mu4e-context-name (mu4e-context-current))))
(if (get-buffer "*mu4e-headers*")
(switch-to-buffer "*mu4e-headers*")
(progn
(mu4e t)
(show-combined-inbox))))
go-to-inbox
(defun go-to-inbox ()
(interactive)
;; (when mv/draft-name
;; (mv/remove-drafts))
(setq mu4e-headers-show-threads t)
(let ((current-context (mu4e-context-current)))
(if (and current-context
(string= (mu4e-context-name current-context) "work"))
(show-combined-inbox)
(mu4e~headers-jump-to-maildir mu4e-sent-folder)))
;; (when mu4e-headers-include-related (mu4e-headers-toggle-include-related))
;;(org-msg-mode t)
(mv/move-files-from-x-to-y (format "/home/misha/external-mail-folder/mail-trash/for-mu4e/%s/cur/" (mu4e-context-name (mu4e-context-current))) (format "/home/misha/external-mail-folder/mail-trash/real/%s/" (mu4e-context-name (mu4e-context-current))))
(mv/move-files-from-x-to-y (format "/home/misha/Maildir%s/cur" mu4e-drafts-folder) (format "/home/misha/external-mail-folder/unnecessary-drafts/real/%s/" (mu4e-context-name (mu4e-context-current))))
(refresh-theme)
(mv/close-duplicate-mu4e-headers)
(mv/empty-directory "/home/misha/Documents/attach")
)
mu4e-update-index-mv
(defun mu4e-quit-open ()
(interactive)
(mu4e-quit)
(go-to-inbox)
(mu4e-update-index))
show-single-thread
(defun show-single-thread ()
(interactive)
(let ((mu4e-headers-include-related t))
(mu4e-headers-search (format "msgid:%s" (mu4e-message-field-at-point :message-id)))))
search-sent-mv
(defun search-sent-mv ()
(interactive)
(setq mu4e-headers-show-threads nil)
(if (string= (mu4e-context-name (mu4e-context-current)) "work")
(mu4e-headers-search "from:m.velthuis@uva.nl or from:work@mishavelthuis.nl")
(mu4e-headers-search (format "from:%s and (maildir:\"%s\" or maildir:\"%s\")" user-mail-address mu4e-sent-folder mu4e-refile-folder) nil nil)))
show-combined-inbox
(defun show-combined-inbox ()
(interactive)
(mu4e-headers-search "maildir:\"/uva/INBOX\" or maildir:\"/work/INBOX\""))
show-archive-mv
Adding other archives does not make that much sense if the result is limited to 500 messages.
(defun show-archive-mv ()
(interactive)
(let ((current-context (mu4e-context-current)))
(if (and current-context
(string= (mu4e-context-name current-context) "work"))
(mu4e-headers-search "maildir:\"/uva/archive-March252024-onwards\" or maildir:\"/transip/uva.archive-uva2024\" or \"/transip/Archive-5Feb2025-onwards\" or \"/work/Archive-5Feb2025-onwards\"")
(mu4e~headers-jump-to-maildir mu4e-refile-folder))))
show-drafts-mv
(defun show-drafts-mv ()
(interactive)
(dirvish (format "/home/misha/Maildir/%s/cur" mu4e-drafts-folder)))
archive-mv-thread
(defun archive-mv-thread ()
(interactive)
(let ((mu4e-refile-folder "/work/Archive-5Feb2025-onwards"))
(mu4e-headers-mark-thread nil '(refile))
;;(mu4e-update-index)
))
open-mail-no-split
(defun open-mail-no-split ()
(interactive)
(setq mu4e-split-view 'single-window)
(mu4e-headers-view-message)
(sleep-for 0.1)
(setq mu4e-split-view 'vertical))
mu4e-headers-view-message-mv
(defun mu4e-headers-view-message-mv ()
(interactive)
(if (< (length (window-list)) 2)
(mu4e-headers-view-message)
(open-mail-no-split)))
tomail
(defun tomail ()
(interactive)
(delete-other-windows)
(let ((buffernames nil))
;; (dolist (name (mapcar #'buffer-name (buffer-list)))
;; (when (or (string-match "-draft*" name) (string-match "Re:" name) (string-match "Fwd:" name))
;; (push name buffernames)))
(dolist (buffer (buffer-list))
(when (with-current-buffer buffer (derived-mode-p 'mu4e-compose-mode))
(push (buffer-name buffer) buffernames)))
(if (> (length buffernames) 1)
(progn
(dolist (x (cdr buffernames))
(split-window-right))
(winum-select-window-1)
(setq count 2)
(dolist (bufferm buffernames)
(switch-to-buffer bufferm)
(evil-window-next count)
(setq count (+ count 1))))
(switch-to-buffer (car buffernames)))))
check if source block is python
(defun inside-python-src-block-p ()
"Check if the cursor is in a Python source block in org-mode."
(interactive)
(let ((element (org-element-context)))
(and (eq (org-element-type element) 'src-block)
(string= (org-element-property :language element) "python"))))
send-mv
Check if cursor is in a source block
Made by ChatGPT
(defun is-cursor-in-source-block-p ()
"Check if cursor is in a source block."
(interactive)
(let ((element (org-element-at-point)))
(if (eq (car element) 'src-block) t nil)))
Actual script
(defun send-mv ()
(interactive)
(if (string= major-mode "mu4e-compose-mode")
(check-canvas)
(if (string= major-mode "org-mode")
(if (is-cursor-in-source-block-p)
(cl-letf (((symbol-function 'yes-or-no-p) (lambda (prompt) t))
((symbol-function 'y-or-n-p) (lambda (prompt) t)))
(org-ctrl-c-ctrl-c))
;;(org-ctrl-c-ctrl-c)
(progn (evil-end-of-visual-line) (gptel-send))))))
mail-view-move-up/ mail-view-move-down
(defun mail-view-move-down ()
(interactive)
(mu4e-view-quit)
(winum-select-window-1)
(evil-next-line 1)
(mu4e-headers-view-message-mv))
(defun mail-view-move-up ()
(interactive)
(mu4e-view-quit)
(winum-select-window-1)
(evil-previous-line 1)
(mu4e-headers-view-message-mv))
Closing buffers
Close mu4e-article buffer
(defun mv/close-article-buffer ()
(interactive)
(switch-to-buffer "*mu4e-article*")
(mu4e-view-quit))
Close headers windows
;; Sometimes, after closing the export buffer (and maybe the *mu4e-article*?)
;; I end up with two windows with the same mu4e-headers. This makes sure that
;; it is only one.
(defun mv/close-duplicate-mu4e-headers ()
(interactive)
"Close one duplicate *mu4e-headers* window if multiple exist."
(sleep-for 0.1)
(let ((headers-windows (cl-loop for win in (window-list)
if (string= (buffer-name (window-buffer win)) "*mu4e-headers*")
collect win)))
(when (> (length headers-windows) 1)
(delete-window (car headers-windows))))
(message "mv/close-duplicate-mu4e-headers has run"))
Keybindings & hooks
Zie ook ORG-MSG voor hooks:
;; Prevents two mu4e windows from being open
;; (add-hook 'mu4e-headers-mode-hook 'close-duplicate-mu4e-headers)
;; This turns of (hopefully) the constant creation of new drafts
(add-hook 'mu4e-compose-mode-hook #'(lambda () (auto-save-mode -1)))
(add-hook 'org-msg-edit-mode-hook #'(lambda () (auto-save-mode -1)))
;; This frees up the space bar
(add-hook 'mu4e-view-mode-hook
(lambda ()
(evil-define-key 'normal mu4e-view-mode-map (kbd "SPC") nil)))
(spc-define-keys spc-leader-map
"mu" 'go-to-headers
"mm" 'tomail
"nn" 'mv/read-mail
"aa" 'add-extra-attach
)
(add-hook 'mu4e-headers-mode-hook
(lambda ()
(visual-line-mode -1)
(toggle-truncate-lines)
))
;; This stops the autosaving of messages hopefully (<2024-04-06 Sat +0200 12:42>)
(add-hook 'mu4e-compose-mode-hook #'(lambda () (auto-save-mode -1)))
(evil-define-key 'normal mu4e-headers-mode-map "o" 'mu4e-headers-view-message-mv)
(evil-define-key 'normal mu4e-headers-mode-map "O" 'open-mail-no-split)
(evil-define-key 'normal mu4e-headers-mode-map "a" 'archive-mv-thread)
(evil-define-key 'normal mu4e-headers-mode-map "t" 'add-tag-mv)
(evil-define-key 'normal mu4e-headers-mode-map "i" 'go-to-inbox)
(evil-define-key 'normal mu4e-headers-mode-map "q" 'mu4e-quit)
(evil-define-key 'normal mu4e-headers-mode-map "I" 'mu4e-update-index)
(evil-define-key 'normal mu4e-headers-mode-map "r" nil)
(evil-define-key 'normal mu4e-headers-mode-map "r" 'mu4e-compose-wide-reply)
(evil-define-key 'normal mu4e-headers-mode-map "R" 'mu4e-compose-reply)
(evil-define-key 'normal mu4e-headers-mode-map "F" 'mu4e-compose-forward)
(evil-define-key 'normal mu4e-view-mode-map "F" 'mu4e-compose-forward)
(evil-define-key 'normal mu4e-headers-mode-map "w" 'show-single-thread)
(evil-define-key 'normal mu4e-headers-mode-map "S" 'search-sent-mv)
(evil-define-key 'normal mu4e-headers-mode-map "s" 'search-mv)
(evil-define-key 'normal mu4e-headers-mode-map "D" 'show-drafts-mv)
(evil-define-key 'normal mu4e-headers-mode-map "A" 'show-archive-mv)
(evil-define-key 'normal mu4e-headers-mode-map "x" (lambda () (interactive) (mu4e-mark-execute-all t)))
(evil-define-key 'normal mu4e-view-mode-map "f" 'mu4e-view-go-to-url)
(evil-define-key 'normal mu4e-view-mode-map "r" 'mu4e-compose-wide-reply)
(evil-define-key 'normal mu4e-view-mode-map (kbd "C-k") 'mail-view-move-up)
(evil-define-key 'normal mu4e-view-mode-map (kbd "C-j") 'mail-view-move-down)
(evil-define-key 'normal mu4e-view-mode-map "o" 'mu4e-view-save-attachments)
(add-hook 'org-msg-edit-mode-hook
(lambda ()
(turn-on-visual-line-mode)
(flyspell-mode t)
))
(add-hook 'mu4e-view-mode-hook
(lambda ()
(turn-on-visual-line-mode)
(display-line-numbers-mode -1)
))
(setq mu4e-headers-include-related nil)
(with-eval-after-load "mm-decode"
(add-to-list 'mm-discouraged-alternatives "text/html")
(add-to-list 'mm-discouraged-alternatives "text/richtext"))
(add-hook 'message-sent-hook 'mv/close-article-buffer)
(add-hook 'message-sent-hook 'mv/close-duplicate-mu4e-headers)
Defining basic variables
(setq mu4e-confirm-quit nil) ; don't ask for yes or no when quitting
(setq mu4e-headers-open-after-move nil) ; i1r (I have to set it there again)
(setq message-kill-buffer-on-exit t)
(setq org-export-show-temporary-export-buffer nil)
(setq mu4e-split-view 'vertical)
(setq mu4e-attachment-dir "~/Downloads")
(setq shr-use-fonts nil)
(setq mu4e-headers-visible-columns 60)
(setq mail-user-agent 'mu4e-user-agent) ;;
;;(setq mail-user-agent 'message-user-agent)
(setq mu4e-compose-dont-reply-to-self t) ;; the old one
(setq message-dont-reply-to-names t) ;; the new one
Message Compose
(add-hook 'mu4e-compose-mode-hook 'turn-off-auto-fill) ;; this prevents the mu4e-compose-mode from truncating
(setq message-citation-line-function nil) ;; this turns off the "bla bla writes ..." at the beginning
(defun mv/update-buffer-text ()
(interactive)
(goto-char (point-min))
;; ;; For some reason, when replying, mu4e always defaults to the :From address that the original email was addressed to.
;; (while (re-search-forward "From: Misha Velthuis <m\\.velthuis@uva\\.nl>" nil t)
;; (replace-match "From: Misha Velthuis <work@mishavelthuis.nl>" nil nil))
;; (goto-char (point-min))
;; ;; (while (re-search-forward "Misha Velthuis <m\\.velthuis@uva\\.nl>" nil t)
;; ;; (replace-match "" nil nil))
;; (while (re-search-forward "\\(Misha Velthuis <m\\.velthuis@uva\\.nl>\\|Cc: \"m\\.velthuis@uva\\.nl\" <m\\.velthuis@uva\\.nl>\\|\"dr\\. Misha Velthuis\" <m\\.velthuis@uva\\.nl>\\,\\)" nil t)
;; (replace-match "" nil nil))
(while (re-search-forward "From: Misha Velthuis <work@mishavelthuis\\.nl>" nil t)
(replace-match "From: Misha Velthuis <m.velthuis@uva.nl>" nil nil))
(goto-char (point-min))
(while (re-search-forward "\\(Misha Velthuis <work@mishavelthuis\\.nl>\\|Cc: \"work@mishavelthuis\\.nl\" <work@mishavelthuis\\.nl>\\|\"dr\\. Misha Velthuis\" <work@mishavelthuis\\.nl>\\,\\)" nil t)
(replace-match "" nil nil))
;; (goto-char (point-min))
(when (re-search-forward "--text follows this line--" nil t)
(delete-region (point) (point-max))
(insert "\n\n\n\nGroetjes,\n\nMisha\n\n---\n\n"
"#+html:<div class=\"signature\">\n\n"
"/Lecturer Sciences/\n\n"
"Amsterdam University College\n\n"
"Science Park 113 | 1098 XG Amsterdam | The Netherlands\n\n"
"[[https://mishathings.org][Blog]] [[https://social.edu.nl/@MishaVelthuis][Mastodon]] [[https://matrix.to/#/@misha:pub.solar][Matrix]]"
"\n\n#+html:</div>\n"
))
(message "update-buffer-text is running now")
(run-with-timer 1 nil '(lambda ()
(other-window 1)
(goto-char (point-max))
(previous-logical-line 19)))
(save-excursion (mv/read-mail))
)
(setq mu4e-compose-context-policy 'pick-first)
(add-hook 'mu4e-compose-mode-hook 'mv/update-buffer-text)
(add-hook 'mu4e-compose-mode-hook 'visual-line-mode)
;;(setq mail-default-reply-to "Misha Velthuis <work@mishavelthuis.nl>")
(setq mail-default-reply-to "Misha Velthuis <m.velthuis@uva.nl>")
(setq mu4e-compose-reply-ignore-address '("work@mishavelthuis.nl"))
(setq user-mail-address "m.velthuis@uva.nl")
(setq gnus-ignored-from-addresses "work@mishavelthuis.nl")
mail html mails
Set-up 2
(defun export-buffer-content-to-html-and-replace ()
(interactive)
(let* ((split-point (save-excursion
(goto-char (point-min))
(when (search-forward "--text follows this line--" nil t)
(line-end-position))))
(content (when split-point
(buffer-substring-no-properties (1+ split-point) (point-max))))
(org-export-show-temporary-export-buffer nil))
(when content
(with-temp-buffer
(insert
;; "#+HTML_HEAD: <style type=\"text/css\">
;; #+HTML_HEAD: signature {
;; #+HTML_HEAD: background-color: #d9fcd4 ;
;; #+HTML_HEAD: border-left: 5px solid #95ac92 ;
;; #+HTML_HEAD: margin: 3em 1em;
;; #+HTML_HEAD: padding: 3em 10px;
;; #+HTML_HEAD: }
;; #+HTML_HEAD: </style>"
"#+HTML_HEAD: <style>
#+HTML_HEAD: .signature {
#+HTML_HEAD: background-color: #defada ; /* Light green background */
#+HTML_HEAD: border-left: 5px solid #9cdb93 ; /* Dark green left border */
#+HTML_HEAD: margin: 1em 0;
#+HTML_HEAD: padding: 0.5em 10px;
#+HTML_HEAD: }
#+HTML_HEAD: blockquote {
#+HTML_HEAD: background-color: #f0f0f0; /* Light gray background */
#+HTML_HEAD: border-left: 5px solid #ccc; /* Gray left border */
#+HTML_HEAD: margin: 1em 0;
#+HTML_HEAD: padding: 0.5em 10px;
#+HTML_HEAD: }
#+HTML_HEAD: </style>"
)
(insert content)
(write-file "/tmp/mail.org")
(let ((org-export-with-author nil)
(org-export-with-date nil)
(org-html-postamble nil))
(org-html-export-to-html nil nil nil nil nil)
(rename-file (concat default-directory (file-name-sans-extension "mail.org") ".html") "/tmp/mail.html" t))))
(when split-point
(save-excursion
(goto-char (1+ split-point))
(delete-region (point) (point-max))
(insert "<#part filename=\"/tmp/mail.html\"><#/part>")))
(insert-part-for-files-in-attach-directory)
))
send attachments
(defun insert-part-for-files-in-attach-directory ()
"Insert a part tag for each file in the '/home/misha/Documents/attach' directory into the current buffer."
(interactive)
(goto-char (point-max))
(insert "\n")
(let ((dir-path "/home/misha/Documents/attach")
(files (directory-files "/home/misha/Documents/attach" t "^[^.].*"))) ; List files, excluding '.' and '..'
(dolist (file files)
(when (file-regular-p file) ; Check if it's a regular file
(let ((filename (file-name-nondirectory file)))
(insert (format "<#part filename=\"/home/misha/Documents/attach/%s\"><#/part>\n" filename)))))))
Set-up 1
- Create mail.
- And then simply use mv/process-marked-files-as-attachments
(defun mv/create-html-mail ()
(interactive)
(let ((file-path "/home/misha/html-mail/mail.org"))
(with-temp-buffer
(insert "#+OPTIONS: toc:nil num:nil author:nil timestamp:nil\n#+HTML_HEAD: <style>\n#+HTML_HEAD: body { background-color: beige; font-family: monospace; }\n#+HTML_HEAD: </style>\n\n\n")
(write-file file-path)))
(find-file "/home/misha/html-mail/mail.org")
(goto-line 6))
(setq org-html-validation-link nil)
Attachments
Getting other people's attachments
;; From /usr/local/share/emacs/site-lisp/mu4e/mu4e-mime-parts.el
;; Rewritten to remove forward slashes
(defun mu4e-view-save-attachments (&optional ask-dir)
"Save files from the current view buffer.
This applies to all MIME-parts that are \"attachment-like\" (have a filename),
regardless of their disposition.
With ASK-DIR is non-nil, user can specify the target-directory; otherwise
one is determined using `mu4e-attachment-dir'."
(interactive "P")
(let* ((parts (mu4e-view-mime-parts))
(candidates (seq-map
(lambda (fpart)
(cons ;; (filename . annotation)
(plist-get fpart :filename)
fpart))
(seq-filter
(lambda (part) (plist-get part :attachment-like))
parts)))
(candidates (or candidates
(mu4e-warn "No attachments for this message")))
(files (mu4e--completing-read "Save file(s): " candidates
'attachment 'multi))
(custom-dir (when ask-dir (read-directory-name
"Save to directory: "))))
;; we have determined what files to save, and where.
(seq-do (lambda (fname)
(let* ((part (cdr (assoc fname candidates)))
(path (mu4e--uniqify-file-name
(mu4e-join-paths
(or custom-dir (plist-get part :target-dir))
(replace-regexp-in-string "\/" "-" (plist-get part :filename))))))
(mm-save-part-to-file (plist-get part :handle) path)))
files)))
;; (load-file "/usr/local/share/emacs/site-lisp/mu4e/mu4e-mime-parts.el")
;; I need to load both these files for the attachment process to work
;;(load-file (format "%s/mu4e-folders_oud.el" filemv-mu4e))
;; (load-file (format "%s/mu4e-folders.el" filemv-mu4e))
;; I asked ChatGPT to modify the code above to produce something that saves all files
(defun save-files-custom-dir (&optional ask-dir)
"Save files from the current view buffer.
This applies to all MIME-parts that are \"attachment-like\" (have a filename),
regardless of their disposition.
With ASK-DIR is non-nil, user can specify the target-directory; otherwise
one is determined using `mu4e-attachment-dir'."
(interactive "P")
(let* ((parts (mu4e-view-mime-parts))
(candidates (seq-map
(lambda (fpart)
(cons ;; (filename . annotation)
(plist-get fpart :filename)
fpart))
(seq-filter
(lambda (part) (plist-get part :attachment-like))
parts)))
(candidates (or candidates
(mu4e-warn "No attachments for this message")))
(files (mapcar 'car candidates)) ; save all files without prompting
(targets (split-string (shell-command-to-string (format "find %s -type d" mv/nextcloud-base)) "\n"))
(custom-dir (ivy-read "Pick dir: " targets)))
;; we have determined what files to save, and where.
(seq-do (lambda (fname)
(let* ((part (cdr (assoc fname candidates)))
(path (mu4e--uniqify-file-name
(mu4e-join-paths
(or custom-dir (plist-get part :target-dir))
(replace-regexp-in-string "\/" "-" fname)))))
(mm-save-part-to-file (plist-get part :handle) path)
))
files)
(dirvish custom-dir)
))
(defun save-files-downloads (&optional ask-dir)
"Save files from the current view buffer.
This applies to all MIME-parts that are \"attachment-like\" (have a filename),
regardless of their disposition.
With ASK-DIR is non-nil, user can specify the target-directory; otherwise
one is determined using `mu4e-attachment-dir'."
(interactive "P")
(if (not (eq major-mode 'mu4e-view-mode))
(dirvish (format "%s/mail" filemv-download))
(progn
(let* ((parts (mu4e-view-mime-parts))
(candidates (seq-map
(lambda (fpart)
(cons ;; (filename . annotation)
(plist-get fpart :filename)
fpart))
(seq-filter
(lambda (part) (plist-get part :attachment-like))
parts)))
(candidates (or candidates
(mu4e-warn "No attachments for this message")))
(files (mapcar 'car candidates)) ; save all files without prompting
(custom-dir "/home/misha/Downloads/mail"))
(shell-command (format "rm -rf %s/mail/*" filemv-download))
(shell-command (format "mkdir %s/mail" filemv-download))
;; we have determined what files to save, and where.
(seq-do (lambda (fname)
(let* ((part (cdr (assoc fname candidates)))
(path (mu4e--uniqify-file-name
(mu4e-join-paths
(or custom-dir (plist-get part :target-dir))
(replace-regexp-in-string "\/" "-" fname)))))
(mm-save-part-to-file (plist-get part :handle) path)
))
files)
(when (file-directory-p custom-dir) (dirvish custom-dir))
))))
(spc-define-keys spc-leader-map
"sac" 'save-files-custom-dir
"sad" 'save-files-downloads)
Saving own attachments
Adjusted from this.
(defun mv/process-marked-files-as-attachments ()
"Processes all marked files in the Dired buffer as attachments for mu4e."
(interactive)
(if (dired-get-marked-files)
(progn
(let ((marked-files (dired-get-marked-files)))
(dired-unmark-all-marks)
(with-temp-buffer
(dolist (file marked-files)
(insert "<\#part filename=\"" file "\">\n" "<\#\/part>"))
(setq attachments (buffer-string))))
(dirvish-quit)
(if compose-buffer
(mv/return-to-mu4e-draft)
(message "no mail buffer selected")))
(message "No files selected.")))
(defun mv/return-to-mu4e-draft ()
"Returns to the mu4e draft and inserts all attachments at point."
;;(revert-buffer)
(when compose-buffer
(switch-to-buffer compose-buffer)
(save-excursion (goto-char (point-max))
(insert "\n\n" attachments)))
(setq compose-buffer nil))
COMMENT ORG-MSG (compose and save attachment)
Add signature
(setq
org-msg-greeting-fmt "Hi%s,\n\n\n\n--\n\nBlog: https://mishathings.org\n\nMastodon: https://social.edu.nl/@MishaVelthuis\n\nMatrix (chat): https://matrix.to/#/@misha:pub.solar\n"
org-msg-default-alternatives '((new . (text html))
(reply-to-html . (text html))
(reply-to-text . (text))))
COMMENT Other stuff
;; (package-install 'org-msg) ;;nixos
(setq org-msg-options "html-postamble:nil H:5 num:nil ^:{} toc:nil author:nil email:nil \\n:t"
org-msg-startup "hidestars indent inlineimages"
org-msg-greeting-fmt "Hi%s,\n\n\n\n--\n\nBlog: https://mishathings.org\n\nMastodon: https://social.edu.nl/@MishaVelthuis\n\nMatrix (chat): https://matrix.to/#/@misha:pub.solar\n"
;org-msg-signature "--\n\nBlog: https://mishathings.org\n\nMastodon: https://social.edu.nl/@MishaVelthuis\n\nMatrix (chat): https://matrix.to/#/@misha:pub.solar"
org-msg-greeting-name-limit 3
org-msg-default-alternatives '((new . (text html))
(reply-to-html . (text html))
(reply-to-text . (text)))
org-msg-convert-citation t)
close buffers and remove drafts
Setting things up
Save buffer
;; This closes the org export buffer (from org-msg)
;; It also closes the *mu4e-artcle* to which I replied
;; and it closes a duplicate mu4e-header.
(setq mv/draft-name nil)
(defun mv/save-mail-buffer ()
(interactive)
(save-buffer)
(setq mv/mail-buffer (replace-regexp-in-string "<[0-9]+>$" "" (buffer-name)))
(setq mv/draft-name (file-name-nondirectory (buffer-file-name)))
(message (format "Mail buffer name: %s" mv/mail-buffer)))
Remove drafts
- Depends on variable mv/draft-name
- I remove the drafts after sending (bound to go-to-inbox). Adding it to the sent-hook caused errors ("draft not found" etc.)
(defun mv/print-directory-contents (dir)
(interactive)
(let ((directory "/path/to/directory/")) ; Replace with your directory path
(dolist (file (directory-files dir t))
(message "file: %s" file))))
(mv/print-directory-contents "/home/misha/Downloads/")
(defun extract-up-to-ml1 (str)
"Return the part of STR up to '.ml1'."
(if (string-match "\\(.+?\\)\\.ml1" str)
(match-string 1 str)
str))
(defun remove-files-starting-with (directory prefix)
"Remove all files in DIRECTORY that start with PREFIX."
(dolist (file (directory-files directory t (concat "^" (regexp-quote prefix))))
(when (file-exists-p file)
(progn
(message (format "%s delted" file))
(delete-file file))))
(mv/print-directory-contents directory))
(defun remove-broken-symlinks (directory)
"Remove all broken symlinks from the specified DIRECTORY."
(interactive "DDirectory: ")
(let ((default-directory directory))
(dolist (file (directory-files default-directory t))
(when (and (file-symlink-p file) (not (file-exists-p file)))
(delete-file file)
(message "Removed broken symlink: %s" file)))))
(defun mv/remove-drafts ()
(interactive)
;; Delete drafts ...
(remove-files-starting-with (format "/home/misha/Maildir%s/cur" mu4e-drafts-folder) (extract-up-to-ml1 mv/draft-name))
(remove-broken-symlinks (format "/home/misha/Maildir%s/cur" mu4e-drafts-folder)))
Close buffers and windows after sending
Function for closing double mu4e-header windows
;; Sometimes, after closing the export buffer (and maybe the *mu4e-article*?)
;; I end up with two windows with the same mu4e-headers. This makes sure that
;; it is only one.
(defun close-duplicate-mu4e-headers ()
(interactive)
"Close one duplicate *mu4e-headers* window if multiple exist."
(let ((headers-windows (cl-loop for win in (window-list)
if (string= (buffer-name (window-buffer win)) "*mu4e-headers*")
collect win)))
(when (> (length headers-windows) 1)
(delete-window (car headers-windows)))))
Close buffers
(defun mv/close-mail-export ()
(interactive)
;;kill the export buffer
(let ((mail-buffer-string mv/mail-buffer))
(dolist (buffer (buffer-list))
(with-current-buffer buffer
(when (and (eq major-mode 'org-msg-edit-mode)
(string-match-p (concat (regexp-quote mail-buffer-string) ".*") (buffer-name)))
(message (format "killing %s" buffer))
(kill-buffer buffer)))))
;; close duplicate mu4e headers window
(close-duplicate-mu4e-headers)
;; kill mu4e-article
(switch-to-buffer "*mu4e-article*")
(mu4e-view-quit)
;; close duplicate mu4e headers window
(close-duplicate-mu4e-headers))
Move cursor to beginning email
(defun move-mail-to-writing-area ()
(interactive)
;;(evil-scroll-line-down 12)
;(sleep-for 0.5)
(search-forward ":END:")
(evil-next-visual-line 3)
(evil-insert 1)
)
(add-hook 'org-msg-edit-mode-hook (lambda () (run-with-timer 0.8 nil #'move-mail-to-writing-area)))
Attachments
Attaching stuff myself
;; ChatGPT made this. Allows me to save what is in between brackets
(defun get-between-brackets ()
(interactive)
(let ((bounds (bounds-of-thing-at-point 'list)))
(when bounds
(buffer-substring-no-properties (1+ (car bounds)) (cdr bounds)))))
(defun add-extra-attach ()
(interactive)
(save-excursion
(goto-char (point-min))
(search-forward ":attachment: ")
(if (not (string-equal (char-to-string (char-after (point))) "("))
(progn
(delete-char (- (line-end-position) (point)))
(insert (prin1-to-string (split-string (current-kill 0) "\n"))))
(progn
(let* ((my-variable (get-between-brackets))
(listmv (mapcar (lambda (in)
;; Add quotes
(format "\"%s\""
;; Remove trailing ")"
(replace-regexp-in-string ")\\'" ""
;; Remove quotes
(replace-regexp-in-string "\"" ""
;; Not sure what substring does
(substring in)))))
;; Split strings on spaces, but only when they are in between quotes? (Came from ChatGPT)
(split-string (string-trim my-variable) "\"? +\""))))
(mapc (lambda (var) (add-to-list 'listmv (format "\"%s\"" var))) (split-string (current-kill 0) "\n"))
(delete-char (- (line-end-position) (point)))
(insert (format "%s" listmv)))))))
mu4e-goodies
(load-file "/etc/nixos/other-config/emacs/mu4e/mu4e-goodies-utils.el")
(load-file "/etc/nixos/other-config/emacs/mu4e/mu4e-goodies-tags.el")
(defun add-tag-mv ()
(interactive)
(setq mu4e-action-tags-completion-list (split-string (shell-command-to-string "python3 /etc/nixos/other-config/emacs/mu4e/get-tags.py") ","))
(mu4e-action-retag-message (mu4e-message-at-point)))
Theming
See Folding
;; (package-install 'standard-themes) ;;nixos
(require 'color)
(load-file "/etc/nixos/other-config/emacs/mu4e/mu4e-headers.el")
;; I have to set this back to nil
(setq mu4e-headers-open-after-move nil) ; i1r
Theme light and dark
- This file defines some new faces.
- Only the color of the faces changes with dark-light
- The bold font for the unread (flagged or not flagged) remains
Dark
(defun make-theme-dark-mv ()
(interactive)
(load-theme 'standard-dark)
;; set background
(set-background-color "gray12")
;;(set-face-foreground 'default "gray60")
;; The "normal" thread child face (background + foreground) (inactive when mu4e-thread-folding-keep-faces is t)
(set-face-background 'mu4e-thread-folding-child-face "gray20")
(set-face-foreground 'mu4e-thread-folding-child-face "#a6a6a6")
;; foreground unread + flagged (outside thread)
(set-face-foreground 'mu4e-unread-flagged-face "#ff6f60")
;; background + foreground unread + flagged (inside thread)
(set-face-background 'mu4e-unread-flagged-child-face "gray20")
(set-face-foreground 'mu4e-unread-flagged-child-face "#ff6f60")
;; background + foreground unread child face
(set-face-background 'mu4e-unread-child-face "gray20")
(set-face-foreground 'mu4e-unread-child-face "white")
;; background flagged child face
(set-face-background 'mu4e-flagged-child-face "gray20")
(set-face-foreground 'mu4e-flagged-child-face "#ff6f60")
;; background (inside thread)
(set-face-background 'mu4e-child-face "gray20")
(set-face-foreground 'mu4e-child-face "#a6a6a6")
;; root background (inactive when mu4e-thread-folding-keep-faces is t)
(set-face-background 'mu4e-thread-folding-root-unfolded-face "gray10")
(set-face-background 'mu4e-thread-folding-root-unfolded-face "gray10")
;; root foreground (inactive when mu4e-thread-folding-keep-faces is t)
(set-face-foreground 'mu4e-thread-folding-root-folded-face "#a6a6a6")
(set-face-foreground 'mu4e-thread-folding-root-unfolded-face "#a6a6a6")
;; set replied face
(set-face-foreground 'mu4e-replied-face "#a6a6a6")
;; org block
(set-face-attribute 'org-block nil :background "gray20")
;; colors of agenda
(defun his-tracing-function (orig-fun &rest args)
(let ((res (apply orig-fun args)))
(mapcar (lambda (s)
(add-face-text-property 1 (length s)
;;(string-match-p ":" s)
(pcase (file-name-nondirectory (car args))
("personal.org" 'all-the-icons-green)
("personal_col.org" 'all-the-icons-green)
("work.org" 'all-the-icons-dorange)
("work_col.org" 'all-the-icons-dorange)
("teaching.org" 'all-the-icons-blue)
("teaching_col.org" 'all-the-icons-blue)
("bij1.org" 'help-argument-name)
("bij1_col.org" 'help-argument-name)
)
nil s))
res)
res))
;; <2023-12-12 Tue> I needed this to keep this face from being overwritten by this definition
(set-face-foreground 'mu4e-flagged-face "#ff6f60")
;;(add-hook 'mu4e-headers-mode-hook 'make-theme-dark-mv)
)
Light
(defun make-theme-light-mv ()
(interactive)
(load-theme 'standard-light)
;; The "normal" thread child face (background + foreground) (inactive when mu4e-thread-folding-keep-faces is t)
(set-face-background 'mu4e-thread-folding-child-face "white smoke")
(set-face-foreground 'mu4e-thread-folding-child-face "black")
(set-face-foreground 'mu4e-forwarded-face "gray90")
;; foreground unread + flagged (outside thread)
(set-face-foreground 'mu4e-unread-flagged-face "#e00033")
(set-face-foreground 'mu4e-flagged-face "#e00033")
;; background + foreground, unread + flagged (inside thread)
(set-face-background 'mu4e-unread-flagged-child-face "gray90")
(set-face-extend 'mu4e-unread-flagged-child-face t)
(set-face-foreground 'mu4e-unread-flagged-child-face "#e00033")
(set-face-background 'mu4e-flagged-child-face "gray90")
(set-face-foreground 'mu4e-flagged-child-face "#e00033")
;; background + foreground unread (inside thread)
(set-face-background 'mu4e-unread-child-face "gray90")
(set-face-foreground 'mu4e-unread-child-face "black")
;; background (inside thread)
(set-face-background 'mu4e-child-face "gray90")
(set-face-foreground 'mu4e-child-face "#7f7f7f")
;; root background (inactive when mu4e-thread-folding-keep-faces is t)
(set-face-background 'mu4e-thread-folding-root-unfolded-face "gainsboro")
(set-face-foreground 'mu4e-thread-folding-root-unfolded-face "black")
;; root background (inactive when mu4e-thread-folding-keep-faces is t)
(set-face-background 'mu4e-thread-folding-root-folded-face "gainsboro")
(set-face-foreground 'mu4e-thread-folding-root-folded-face "black")
;; set replied face
(set-face-foreground 'mu4e-replied-face "#7f7f7f")
;; org agenda date
(set-face-foreground 'org-agenda-date "black")
;; org blocks
(set-face-attribute 'org-block nil :background
(color-darken-name (face-attribute 'default :background) 15))
;; set background
(set-background-color "linen")
;; Colors of agenda
(defun his-tracing-function (orig-fun &rest args)
(let ((res (apply orig-fun args)))
(mapcar (lambda (s)
(add-face-text-property 1 (length s)
;;(string-match-p ":" s)
(pcase (file-name-nondirectory (car args))
("personal.org" 'bookmark-face)
("personal_col.org" 'bookmark-face)
("work.org" 'font-lock-comment-delimiter-face)
("work_col.org" 'font-lock-comment-delimiter-face)
("teaching.org" 'company-tooltip-common-selection)
("teaching_col.org" 'company-tooltip-common-selection)
("bij1.org" 'gnus-group-mail-1-empty)
("bij1_col.org" 'gnus-group-mail-1-empty)
)
nil s))
res)
res))
;; <2023-12-12 Tue> I needed this to keep this face from being overwritten by this definition
(set-face-foreground 'mu4e-flagged-face "#e00033")
)
Toggle
;; This script allows me to toggle between light and dark
(defun refresh-theme ()
(interactive)
(set-face-bold 'mu4e-unread-flagged-child-face t)
(let* ((current-time (current-time))
(current-hour (string-to-number (format-time-string "%H" current-time))))
(if (or (< current-hour 6) (>= current-hour 17))
;;(if t
(make-theme-dark-mv)
(make-theme-light-mv))))
(refresh-theme)
Reveal
Auto export to html at save
(defun mv/after-save-hook ()
(interactive)
(require 'f)
(when (string-match-p "\\.org$" (buffer-file-name))
(when (f-descendant-of? (file-truename buffer-file-name) "/home/misha/Nextcloud/mnotes/org-roam/presentations")
(org-reveal-export-to-html-mv))))
;;(add-hook 'after-save-hook 'mv/after-save-hook)
Fix image in reveal presentation
Made largely by ChatGPT
(defun mv/replace-under-cursor ()
(interactive)
(let ((line (thing-at-point 'line t)))
(when (string-match "\./images" line)
(setq line (replace-match "\./../../../images" t t line))
(delete-region (line-beginning-position) (line-end-position))
(insert line))))
(defun update-image-reveal ()
(interactive)
(let* ((full-string (save-excursion
(beginning-of-line)
(buffer-substring-no-properties
(line-beginning-position)
(line-end-position)
)))
(name-of-file (or (when (string-match "\\[\\[\\(.*/\\)\\(.*?\\)\\]\\]" full-string)
(match-string-no-properties 2 full-string))
(when (string-match "src=\"\\(.*\\)\"" full-string)
(file-name-nondirectory (match-string 1 full-string)))))
(origin-path (cond
((string-match "system-earth" (buffer-name))
(when name-of-file
(concat "/home/misha/Nextcloud/mnotes/org-roam/presentations/2023-2024/system-earth2023/images/"
name-of-file)))
((string-match "system-earth" (buffer-name))
(when name-of-file
(concat "/home/misha/Nextcloud/mnotes/org-roam/presentations/2023-2024/system-earth2023/images/"
name-of-file)))
((string-match "energy-transition" (buffer-name))
(when name-of-file
(concat "/home/misha/Nextcloud/mnotes/org-roam/presentations/2023-2024/intro-to-energy-transition/images/"
name-of-file)))
((string-match "climate-sustainability" (buffer-name))
(when name-of-file
(concat "/home/misha/Nextcloud/mnotes/org-roam/presentations/2023-2024/intro-to-climate-and-sustainability2023/images/"
name-of-file)))
((string-match "BigTime" (buffer-name))
(when name-of-file
(concat "/home/misha/Nextcloud/mnotes/org-roam/presentations/2023-2024/BigTime/images/"
name-of-file)))
((string-match "ECS" (buffer-name))
(when name-of-file
(concat "/home/misha/Nextcloud/mnotes/org-roam/presentations/2023-2024/ECS/images/"
name-of-file)))
))
(destination (when origin-path
(expand-file-name (file-name-nondirectory origin-path)
"/home/misha/Nextcloud/mnotes/org-roam/presentations/images/"))))
(when (and origin-path destination (file-exists-p origin-path))
(copy-file origin-path destination t)
(message "'%s' copied to '%s'" origin-path destination)
(let ((org-image-regex "\\[\\[\\(\\.\\./\\)*\\./images/\\(.*\\)\\]\\]")
(html-image-regex "#\\+REVEAL_HTML: <img class=\"r-stretch\" src=\"\\(.*\\)\">"))
(mv/replace-under-cursor)
))))
(defun mv/update-image-reveal-buffer ()
(interactive)
(save-excursion
(while (search-forward "./images" nil t)
(update-image-reveal))))
(require 'ox-reveal)
(setq org-reveal-root "/home/misha/git/reveal.js")
(setq org-export-html-date-format-string "%d-%m-%Y")
(setq org-export-date-timestamp-format "%d-%m-%Y")
(setq org-reveal-plugins '(markdown notes))
(defun org-reveal-export-to-html-open-mv ()
(interactive)
(org-set-custom-id)
(org-reveal-export-to-html)
(rename-file (concat (file-name-sans-extension (buffer-file-name)) ".html") "./../" t)
(shell-command (format "xdg-open %s" (concat "./../" (file-name-sans-extension (buffer-name)) ".html"))))
(defun org-reveal-export-to-html-mv ()
(interactive)
(let* ((current-dir (directory-file-name (expand-file-name default-directory)))
(last-two-dirs (mapconcat 'identity (last (split-string current-dir "/") 2) "/")))
(if (string-equal last-two-dirs "PYW/org")
;;(message "You're not in a directory ending with PYW/org")
(org-html-export-to-html)
(progn
(org-set-custom-id)
(org-reveal-export-to-html))
))
(rename-file (concat (file-name-sans-extension (buffer-file-name)) ".html") "./../" t)
)
(spc-define-keys spc-leader-map
"oga" 'org-reveal-export-to-html-mv)
(spc-define-keys spc-leader-map
"ogb" 'org-reveal-export-to-html-open-mv)
(spc-define-keys spc-leader-map
"ogp" 'reveal-sync-presentations-exclude-drafts)
;; From ChatGPT
(defun org-set-custom-id ()
(interactive)
(save-excursion
(goto-char (point-min))
(let ((count-top-level 0)
(count-sub-level 0)
parent-level headline-level)
(while (re-search-forward org-heading-regexp nil t)
(setq headline-level (length (match-string-no-properties 1)))
(if (= headline-level 1)
(save-excursion
(setq count-top-level (1+ count-top-level))
(setq count-sub-level 0)
(org-entry-put (point) "CUSTOM_ID" (number-to-string count-top-level)))
(save-excursion
(setq count-sub-level (1+ count-sub-level))
(org-entry-put (point) "CUSTOM_ID" (format "%d-%d" count-top-level count-sub-level))))))))
(defun reveal-sync-presentations-exclude-drafts ()
(interactive)
"Sync 'presentations' directories using rsync, excluding drafts."
;;(replace-reveal-root)
(save-buffer)
(shell-command
"rsync -avm --delete --include='*/' --include='ltximg/***' --include='images/***' --exclude='*draft*.html' --include='*.html' --exclude='*' /home/misha/Nextcloud/mnotes/org-roam/presentations /home/misha/Nextcloud/mishathings-website/static/public/")
(shell-command "bash /etc/nixos/other-config/emacs/update_website.sh")
)
(defun reveal-toggle-speaker-notes ()
(interactive)
(save-excursion
(goto-char (point-min))
(if (search-forward "#+REVEAL_INIT_OPTIONS: width:1100, slideNumber:true, hash:true, showNotes:'separate-page'" nil t)
(progn
(goto-char (point-min))
(while (search-forward "#+REVEAL_INIT_OPTIONS: width:1100, slideNumber:true, hash:true, showNotes:'separate-page'" nil t)
(replace-match "#+REVEAL_INIT_OPTIONS: width:1100, slideNumber:true, hash:true" nil t))
(message "speaker notes off"))
(while (search-forward "#+REVEAL_INIT_OPTIONS: width:1100, slideNumber:true, hash:true" nil t)
(replace-match "#+REVEAL_INIT_OPTIONS: width:1100, slideNumber:true, hash:true, showNotes:'separate-page'" nil t)
(message "speaker notes on")))))
(defun insert-pdf-link-reveal ()
(interactive)
(let* ((buffer-file-path (buffer-file-name))
(replacement "/home/misha/Nextcloud/mnotes/mnotes_folders/")
(modified-path (replace-regexp-in-string replacement "https://mishathings.org/public/" buffer-file-path))
(html-path (replace-regexp-in-string "\.org$" ".html" modified-path)))
(insert (format "[[%s?print-pdf][click]]" html-path))))
push presentation
(defun push-presentation ()
(interactive)
(shell-command-to-string "ssh misha@$(pass ip/transip) 'rm /home/misha/git/reveal.js-remote/presentations/index.html'")
(org-reveal-export-to-html-mv)
(let ((new-content "
<script src=\"dist/reveal.js\"></script>
<script src=\"plugin/notes/notes.js\"></script>
<script src=\"plugin/search/search.js\"></script>
<script src=\"plugin/markdown/markdown.js\"></script>
<script src=\"plugin/highlight/highlight.js\"></script>
<!--
reveal.js-remote:
the next two dependencies are required
-->
<script src=\"../socket.io/socket.io.js\"></script>
<script src=\"../_remote/plugin.js\"></script>
<script src=\"../_remote/remotezoom.js\"></script>
<script>
// Also available as an ES module, see:
// https://revealjs.com/initialization/
Reveal.initialize({
controls: true,
progress: true,
center: true,
hash: true,
/*
reveal.js-remote:
optional configuration (with default values)
,*/
remote: {
// enable remote control
remote: true,
// enable multiplexing
multiplex: true,
// server address
// change this if you do not serve the presentation from the same domain
// example: https://presentations.jowisoftware.de
server: window.location.protocol + \"//\" + window.location.host + \"/\",
// path to socket.io
// change this if the basepath of the server is not \"/\"
path: \"/socket.io\",
// url of the presentation to share
shareUrl: window.location.href
},
// Learn about plugins: https://revealjs.com/plugins/
plugins: [ RevealRemoteZoom, RevealNotes, RevealSearch, RevealMarkdown, RevealHighlight, RevealRemote ]
});
</script>
</body>
</html>"))
(find-file (concat "./../" (file-name-sans-extension (buffer-name)) ".html"))
(goto-char (point-min))
(when (search-forward "<script src=\"https://cdn.jsdelivr.net/npm/reveal.js/dist/reveal.js\">" nil t)
(delete-region (line-beginning-position) (point-max))
(insert new-content))
(save-buffer)
(kill-buffer))
(shell-command-to-string (format "rsync -rv --delete %s misha@$(pass ip/transip)://home/misha/git/reveal.js-remote/presentations/index.html" (concat "./../" (file-name-sans-extension (buffer-name)) ".html")))
(shell-command-to-string "rsync -rv --delete /home/misha/Nextcloud/mnotes/org-roam/presentations/images/ misha@$(pass ip/transip)://home/misha/git/reveal.js-remote/presentations/images/")
(shell-command "firefox http://mishathings.org:8080")
)
Latex
Normal latex
;; (package-install 'auctex) ;; nixos
;; Use pdf-tools to open PDF files
(setq TeX-view-program-selection '((output-pdf "PDF Tools"))
TeX-source-correlate-start-server t)
;; Update PDF buffers after successful LaTeX runs
(add-hook 'TeX-after-compilation-finished-functions
#'TeX-revert-document-buffer)
(add-hook 'LaTeX-mode-hook #'visual-line-mode)
(spc-define-keys spc-leader-map
"lb" 'TeX-command-run-all
)
(setq Latex-command "latex --synctex=1")
(setq TeX-source-correlate-mode t)
Latex fragments
Functions and variables
(setq org-format-latex-options (plist-put org-format-latex-options :scale 1.5))
(setq constants-snip '(
("Stefan Boltzmann Constant: 5.56*10**-8" . "5.67*10**-8")
("Euler's number: 2.718281828459" . "2.718281828459")
("Avogadro constant: 6.02214076*10**23" . "6.02214076*10**23")
("Constant in Wien's law: 2898" . "2898")
))
(defun constants_insert ()
(interactive)
(insert (format "%s" (alist-get (completing-read "Choose: " constants-snip) constants-snip nil nil #'string=)))
(evil-insert 1))
(defun clear_latex_fragments_buffer ()
(interactive)
(org-clear-latex-preview (point-min) (point-max)))
(setq org-startup-latex-with-latex-preview t)
(defun insert_latex_fragments ()
(interactive)
(insert " \\(\\)")
(evil-backward-char 2)
(evil-insert 1))
(defun clear_latex_fragments_buffer ()
(interactive)
(org-clear-latex-preview (point-min) (point-max)))
(defun show_latex_fragments_buffer ()
(interactive)
(org--latex-preview-region (point-min) (point-max)))
;; This allows me to make the permil symbol
;; (add-to-list 'org-latex-packages-alist '("AUTO" "wasysym" t))
(setq latex-snip '(
("CH4 (methane)" . "$CH_4")
("double arrow" . "\\leftrightarrow")
("Mg2+ (magnesium)" . "$Mg^{2+}")
("pi" . "\\pi")
("Pi" . "\\Pi")
("micrometer" . "\\mu $m")
("alpha" . "\\alpha")
("beta" . "\\beta")
("mu" . "\\mu")
("Fe2+ (ferrous)" . "$Fe^{2+}")
("Fe3+ (ferric)" . "$Fe^{3+}")
("permil" . "\\permil")
("approx" . "\\approx")
("plusminus" . "\\pm")
("sigma" . "\\sigma")
("Sigma" . "\\Sigma")
("NH4+ (ammonium)" . "$NH_4^+")
("rho (density)" . "\\rho")
("tau (stress)" . "\\tau")
("N2 (nitrogen)" . "$N_2")
("NH3 (ammonia)" . "$NH_3")
("NO3- (nitrate)" . "$NO_3^-")
("NO2- (nitrite)" . "$NO_2^-")
("NO2 (nitrogen dioxide)" . "$NO_2")
("NO (nitric oxide)" . "$NO")
("N2O (nitrous oxide)" . "$N_2$O")
("HNO3 (nitric acid)" . "$HNO_3")
("SO42- (Sulfate ion)" . "$SO_4^{2-}")
("lambda" . "\\lambda")
("Delta" . "\\Delta")
("H+ (hydrogen)" . "\\textrm{H}^+")
("H3O+" . "$H_3$O^+")
("H2O (water)" . "$H_2$O")
("H2CO3 (carbonic acid)" . "$H_2$CO_3")
("HCO3- (bicarbonate)" . "$HCO_3^-")
("CO2 (CO2)" . "$CO_2")
("CO32- (carbonate)" . "$CO_3^{2-}")
("Ca2+ (calcium)" . "$Ca^{2+}")
("O2 (Oxygen)" . "$O_2")
("C6H12O6 (Glucose)" . "$C_6$H_12$O_6")
("CaCO3 (calcium carbonate)" . "$CaCO_3")
("MgCO3 (magnesium carbonate)" . "$MgCO_3")
("Stefan Boltzmann equation" . "F = \\sigma T^4")
))
(defun latex-insert-separate ()
(interactive)
(insert (format " \\(%s\\)" (alist-get (completing-read "Choose: " latex-snip) latex-snip nil nil #'string=)))
(org-latex-preview)
(evil-insert 1))
(defun latex-insert-add ()
(interactive)
(insert (alist-get (completing-read "Choose: " latex-snip) latex-snip nil nil #'string=)))
Yasnippet
;; (package-install 'yasnippet) ;;nixos
;; (package-install 'yasnippet-snippets) ;; nixos
(require 'yasnippet)
(yas-global-mode 1)
(spc-define-keys spc-leader-map "ys" 'yas-insert-snippet)
Org-mapping-notes
Add org-coor
(defun add-org-coor ()
(interactive)
(evil-paste-after 1)
(evil-undo 1)
(let ((var (car kill-ring)))
(org-set-property "org-coor" var)
(org-set-property "CREATED" (format-time-string "<%Y-%m-%d %a %z %H:%M>"))))
The program
(load-file "/etc/nixos/other-config/emacs/org-mapping/org-mapping-notes.el")
(setq org-mapping-skip-files '(
"/home/misha/Nextcloud/mnotes/spatial_memory_project.org"
"/home/misha/Nextcloud/git/codeberg/org-mapping-notes/README.md"
"/home/misha/Nextcloud/git/pub-solar/org-mapping-notes/README.md"
"/home/misha/.emacs.d/history"
"/home/misha/emacs-troep/.emacs.default-28.28/history"
"/home/misha/Nextcloud/mnotes/spanish_practice.org"
"/home/misha/Nextcloud/mnotes/practicing_geological_timescales.org"
"/home/misha/Nextcloud/rc_files/emacs/README.org"
"/home/misha/Nextcloud/website/mapm/org-mapping-notes-docs/data.js"
"/home/misha/Nextcloud/mishathings-website/static/mapm/org-mapping-notes-docs/data.js"
"/home/misha/Nextcloud/mishathings-website/public/mapm/org-mapping-notes-docs/data.js"
))
(setq org-mapping-base-folder "/home/misha/Nextcloud/mishathings-website/static/mapm")
(setq org-mapping-image-folder "/home/misha/Nextcloud/mishathings-website/static/mapm/imagesmv/")
(setq recoll-search-folder "/home/misha/Nextcloud/")
(setq spatial-memory-folder "/home/misha/Nextcloud/mnotes/org-roam/spatial_memory.org")
(setq mapping-code-folder "/etc/nixos/other-config/emacs/org-mapping")
(setq org-export-with-broken-links t)
(defun org-mapping-notes-build-map-and-sync ()
(interactive)
(prefer-coding-system 'utf-8)
(org-mapping-notes-build-map)
(shell-command "bash /etc/nixos/other-config/emacs/update_website.sh"))
Spelling check
(defun dutch_dic ()
(interactive)
(ispell-change-dictionary "nl_NL")
(flyspell-buffer)
)
(defun span_dic ()
(interactive)
(ispell-change-dictionary "spanish")
(flyspell-buffer)
)
(defun english_dic ()
(interactive)
(ispell-change-dictionary "en_US")
(flyspell-buffer)
)
;; <2024-01-02 Tue> I took this from /usr/local/share/emacs/30.0.50/lisp/textmodes/flyspell.el.gz I couldn't invoke it interactively because it's not available like that. So I took it and added "interactive"
(defun flyspell--mode-off ()
"Turn Flyspell mode off."
(interactive)
(remove-hook 'post-command-hook (function flyspell-post-command-hook) t)
(remove-hook 'pre-command-hook (function flyspell-pre-command-hook) t)
(remove-hook 'after-change-functions 'flyspell-after-change-function t)
(remove-hook 'hack-local-variables-hook
(function flyspell-hack-local-variables-hook) t)
(flyspell-delete-all-overlays)
(setq flyspell-pre-buffer nil)
(setq flyspell-pre-point nil)
(setq flyspell-mode nil))
(spc-define-keys spc-leader-map
"osn" 'dutch_dic
"ose" 'english_dic
"oso" 'flyspell--mode-off
"oss" 'span_dic
"osc" 'flyspell-correct-word-before-point)
(defun flyspell-goto-previous-error (arg)
"Go to arg previous spelling error."
(interactive "p")
(while (not (= 0 arg))
(let ((pos (point))
(min (point-min)))
(if (and (eq (current-buffer) flyspell-old-buffer-error)
(eq pos flyspell-old-pos-error))
(progn
(if (= flyspell-old-pos-error min)
;; goto end of buffer
(progn
(message "Restarting from end of buffer")
(goto-char (point-max)))
(backward-word 1))
(setq pos (point))))
;; seek the previous error
(while (and (> pos min)
(let ((ovs (overlays-at pos))
(r '()))
(while (and (not r) (consp ovs))
(if (flyspell-overlay-p (car ovs))
(setq r t)
(setq ovs (cdr ovs))))
(not r)))
(backward-word 1)
(setq pos (point)))
;; save the current location for next invocation
(setq arg (1- arg))
(setq flyspell-old-pos-error pos)
(setq flyspell-old-buffer-error (current-buffer))
(goto-char pos)
(if (= pos min)
(progn
(message "No more miss-spelled word!")
(setq arg 0))))))
Google translate
;; (package-install 'google-translate) ;; nixos
(require 'google-translate)
;; the normal functions don't work with pdfs (but I can fix that)
(defun google-translate-mv ()
(interactive)
(if (eq major-mode 'pdf-view-mode)
(pdf-view-kill-ring-save))
(let* ((input (current-kill 0)))
(google-translate-translate "auto" "en" input 'kill-ring)
(shell-command-to-string (format "dunstify -t 70000 'Original text: %s\n\nTranslation: %s'" input (current-kill 0)))))
(defun tr_en_nl ()
(interactive)
(setq google-translate-default-source-language "en")
(setq google-translate-default-target-language "nl")
(let ((display-buffer-overriding-action '(display-buffer-in-direction . (direction right))))
(google-translate-at-point))
)
;; Google translate
(defun tr_en_es ()
(interactive)
(setq google-translate-default-source-language "en")
(setq google-translate-default-target-language "es")
(let ((display-buffer-overriding-action '(display-buffer-in-direction . (direction right))))
(google-translate-at-point))
)
(defun tr_es_en ()
(interactive)
(setq google-translate-default-source-language "es")
(setq google-translate-default-target-language "en")
(let ((display-buffer-overriding-action '(display-buffer-in-direction . (direction right))))
(google-translate-at-point))
)
(defun tr_nl_en ()
(interactive)
(setq google-translate-default-source-language "nl")
(setq google-translate-default-target-language "en")
(let ((display-buffer-overriding-action '(display-buffer-in-direction . (direction right))))
(google-translate-at-point))
)
(defun tr_en_nl ()
(interactive)
(setq google-translate-default-source-language "en")
(setq google-translate-default-target-language "nl")
(let ((display-buffer-overriding-action '(display-buffer-in-direction . (direction right))))
(google-translate-at-point))
)
(defun tr_nl_es ()
(interactive)
(setq google-translate-default-source-language "nl")
(setq google-translate-default-target-language "es")
(let ((display-buffer-overriding-action '(display-buffer-in-direction . (direction right))))
(google-translate-at-point))
)
(defun tr_es_nl ()
(interactive)
(setq google-translate-default-source-language "es")
(setq google-translate-default-target-language "nl")
(let ((display-buffer-overriding-action '(display-buffer-in-direction . (direction right))))
(google-translate-at-point))
)
(defun tr_en_en ()
(interactive)
(setq google-translate-default-source-language "en")
(setq google-translate-default-target-language "en")
(let ((display-buffer-overriding-action '(display-buffer-in-direction . (direction right))))
(google-translate-at-point))
)
Misc
Remove folder
(defun mv/empty-directory (dir)
"Delete all files and directories in DIR."
(when (and (file-exists-p dir) (file-directory-p dir))
(dolist (file (directory-files dir t directory-files-no-dot-files-regexp))
(if (file-directory-p file)
(delete-directory file t) ; t for recursive
(delete-file file)))))
Remove-annotations
(defun remove-annotations ()
(interactive)
(let ((file-path (buffer-file-name)))
(if file-path
(shell-command (format "bash $HOME/Nextcloud/scripts_misha/misc_useful/remove-annotations.sh \"%s\"" file-path))
(message "Buffer is not associated with a file."))
(dirvish "/home/misha/Nextcloud/pdf_library/misc/no_annot")))
Clean directory
(defun clean-directory (directory)
"Recursively delete files ending with #, starting with .#, or ending with ~ in DIRECTORY."
(let ((files (directory-files-recursively directory ".*")))
(dolist (file files)
(when (or (string-match-p "#$" file)
(string-match-p "~$" file)
(string-prefix-p (expand-file-name ".#" (file-name-directory file)) file))
(message "Deleting file: %s" file)
(delete-file file)))))
(defun clean-current-dirvish-directory ()
"Recursively delete files ending with #, starting with .#, or ending with ~ in the current Dired directory."
(interactive)
(let ((directory (dired-current-directory)))
(clean-directory directory)
(revert-buffer)))
Store file history recentf
(recentf-mode)
(setq
recentf-save-file "~/.emacs.d/recentf"
recentf-max-saved-items 100000
recentf-max-menu-items 5000
)
(run-at-time (current-time) 300 'recentf-save-list)
(defun recentmv ()
(interactive)
(add-hook 'minibuffer-exit-hook 'turn-on-prescient-mode-mv)
(ivy-prescient-mode -1)
(find-file (ivy-read "Select: " recentf-list))
(ivy-prescient-mode 1))
(spc-define-keys spc-leader-map
"fr" 'recentmv)
Find folders locate
These function use dirfilter, which is a script that Daniel made to replace the following:
locate -i --nul %s | xargs -r0 sh -c 'for i do [ -d \"$i\" ] && printf \"%%s\\n\" \"$i\"; done' sh {} +
The script looks as follows, and is in my /usr/local/bin
#!/usr/bin/env python
import sys import os
for line in sys.stdin: if os.path.isdir(line[:-1]): sys.stdout.write(line)
Find folders with locate
(defun find-folders-mv ()
(interactive)
(dirvish (ivy-read "Search folder and open in Dirvish: "
(lambda (str)
(let ((shell-command
(format "locate -i %s | /etc/nixos/other-config/emacs/dirfilter.py" str)))
(split-string (shell-command-to-string shell-command) "\n")))
:dynamic-collection t)))
Find folders with locate + nautilus (non-fuzzy)
(defun find-folders-mv-nautilus ()
(interactive)
(call-process-shell-command (format "nautilus \"%s\" &" (ivy-read "Open Nautilus of folder: "
(lambda (str)
(let ((shell-command
(format "locate -i %s | /etc/nixos/other-config/emacs/dirfilter.py" str)))
(split-string (shell-command-to-string shell-command) "\n")))
:dynamic-collection t
:action (lambda (x)
(setq current-str ivy-text)))) nil 0 ))
Find folder of specific file and move focus to file
- The script below requires a bit of abacadabra (Daniel helped) to get the focus on the file.
- It worked for Daniel but it didn't work for me. The solution: the run-with-timer in the hook function.
(defvar dired-file nil)
(defun dired-goto-initial-pos ()
(when dired-file
(evil-goto-first-line)
(search-forward dired-file)
(evil-beginning-of-line))
(setq dired-file nil))
(add-hook 'dired-initial-position-hook #'(lambda () (run-with-timer nil 1 #'dired-goto-initial-pos)))
(defun dirvish-open-folder-of-specified-file ()
(interactive)
(let* ((path (ivy-read "Open folder of file: "
(lambda (str)
(let ((shell-command
(format "locate -i %s" str)))
(split-string (shell-command-to-string shell-command) "\n")))
:dynamic-collection t))
(folder (file-name-directory path))
(file (file-name-nondirectory path)))
(setq dired-file (if (> (length file) 20)
(substring-no-properties file 0 20)
file))
(setq dired-file file)
(dirvish folder)))
Select between spaces
Built by ChatGPT
(defun select-between-spaces ()
"Select text between the nearest two spaces, or from the beginning of line
to the first space, or from the last space to the end of line."
(interactive)
(let ((start (save-excursion
(search-backward " " (line-beginning-position) t)))
(end (save-excursion
(search-forward " " (line-end-position) t))))
(cond
;; If both start and end are found and surrounded by spaces
((and start end)
(goto-char (1+ start)) ; Move past the first space
(set-mark (1- end)) ; Move to just before the second space
(message "Selected: %s" (buffer-substring-no-properties (mark) (point))))
;; If at the start of the line, select to the first space
(start
(goto-char (1+ start)) ; Move past the space
(set-mark (line-end-position)) ; Select to the end of the line
(message "Selected: %s" (buffer-substring-no-properties (mark) (point))))
;; If at the end of the line, select from the last space
(end
(goto-char (line-beginning-position)) ; Move to the start of the line
(set-mark (1- end)) ; Move to just before the end space
(message "Selected: %s" (buffer-substring-no-properties (mark) (point))))
(t
(message "No spaces found on this line.")))))
(define-key evil-inner-text-objects-map " " 'select-between-spaces)
Create file functions
Make klad
(defun make_klad ()
(interactive)
(counsel-find-file nil "/home/misha/Nextcloud/scripts_misha/klad/"))
Make mnotes
(defun create_mnotes ()
(interactive)
(let* ((filename1 (read-from-minibuffer "Enter name of file: "))
(filename (replace-regexp-in-string " " "_" filename1))
(filepath (format "~/Nextcloud/mnotes/%s.org" filename))
(date (format-time-string "[%Y-%m-%d %a %H:%M]")))
(if (file-exists-p filepath) (message "file already exists")
(with-temp-file filepath
(insert (format "#+TITLE: %s \n#+CREATED: %s\n#+LAST_MODIFIED: %s\n\n" filename1 date date)))
(find-file filepath)
(goto-line 5)
(evil-insert 0))))
#+end_src
Run block
Run all blocks
(defun mv/run-all-python-src-blocks ()
(interactive)
(save-excursion
(goto-char (point-min))
(while (search-forward "#+begin_src python" nil t)
(when (org-in-src-block-p)
(run-block)))))
Python
This removes
(defun run-block ()
(interactive)
(if (inside-python-src-block-p)
(progn
(setq display-buffer-alist
;; remove the "open in the same buffer"
(delq (assoc "^\\*Python\\*$" display-buffer-alist)
display-buffer-alist))
(run-python nil nil t)
(sleep-for 0.1)
(org-babel-mark-block)
(call-interactively 'python-shell-send-region)
;; add the "open in the same buffer"
(add-to-list 'display-buffer-alist
'("^\\*Python\\*$" . (display-buffer-same-window))))
(cl-letf (((symbol-function 'yes-or-no-p) (lambda (&rest args) t))
((symbol-function 'y-or-n-p) (lambda (&rest args) t)))
(org-ctrl-c-ctrl-c))))
Run region
Select region
(defun mv-get-region (&optional start end)
"Send the region delimited by START and END to inferior Python process."
(interactive)
(let ((start (cond (start start)
((region-active-p) (region-beginning))
(t (point-min))))
(end (cond (end end)
((region-active-p) (region-end))
(t (point-max)))))
(list start end)))
Bash
(defun run-bash-region ()
(interactive)
(shell-command-on-region (region-beginning) (region-end) "bash"))
Run bash or python
(defun run-region-mv ()
(interactive)
(if (eq major-mode 'sh-mode) (run-bash-region)
(if (eq major-mode 'python-mode)
(python-shell-send-region (region-beginning) (+ (region-end) 1))
;; (python-shell-send-region (car (mv-get-region)) (cdr (mv-get-region)))
(if (eq major-mode 'racket-mode) (racket-send-region (region-beginning) (+ (region-end) 1) )))))
Calc
(defun calc-mv ()
(interactive)
(evil-append 1)
(insert (format "%.2f" (string-to-number (calc-eval (buffer-substring-no-properties
(save-excursion
(if (not (re-search-backward "[a-z]" (line-beginning-position) t))
(move-beginning-of-line nil))
(1- (re-search-forward "[0-9(]"))) (- (point) 1)))))))
(spc-define-keys spc-leader-map "/" 'calc-mv)
Rename files
;; I prefer this rename function because the other shows the files in the folder in an expanding minibuffer
(defun rename-mv (&optional path)
(interactive)
(let* (
(fil buffer-file-name)
(dir (file-name-directory (buffer-file-name)))
(newn (if (not path)
(read-from-minibuffer "Enter name of file: ")
(read-from-minibuffer "Enter name of file: " path)))
(newp (format "%s%s" dir newn))
)
(if (file-exists-p newp) (message "file already exists")
(progn (rename-file fil newp)
(kill-this-buffer)
(find-file newp)))))
Buffer bookmarks
(spc-define-keys spc-leader-map
"bi" 'bookmark-set
"bj" 'bookmark-jump
"bD" 'bookmarks-delete
"b1" 'mv/bookmark1
"b2" 'mv/bookmark2
"b3" 'mv/bookmark3
"b4" 'mv/bookmark4
"b5" 'mv/bookmark5
"b6" 'mv/bookmark6
"p1" 'mv/bookmarkgo1
"p2" 'mv/bookmarkgo2
"p3" 'mv/bookmarkgo3
"p4" 'mv/bookmarkgo4
"p5" 'mv/bookmarkgo5
"p6" 'mv/bookmarkgo6
)
(defun mv/bookmark1 ()
(interactive)
(bookmark-set "1"))
(defun mv/bookmark2 ()
(interactive)
(bookmark-set "2"))
(defun mv/bookmark3 ()
(interactive)
(bookmark-set "3"))
(defun mv/bookmark4 ()
(interactive)
(bookmark-set "4"))
(defun mv/bookmark5 ()
(interactive)
(bookmark-set "5"))
(defun mv/bookmark6 ()
(interactive)
(bookmark-set "6"))
(defun mv/bookmarkgo1 ()
(interactive)
(bookmark-jump "1"))
(defun mv/bookmarkgo2 ()
(interactive)
(bookmark-jump "2"))
(defun mv/bookmarkgo3 ()
(interactive)
(bookmark-jump "3"))
(defun mv/bookmarkgo4 ()
(interactive)
(bookmark-jump "4"))
(defun mv/bookmarkgo5 ()
(interactive)
(bookmark-jump "5"))
(defun mv/bookmarkgo6 ()
(interactive)
(bookmark-jump "6"))
(defun bookmarks-delete ()
(interactive)
(dolist (bookmark (bookmark-all-names))
(bookmark-delete bookmark))
(message "bookmarks deleted"))
;; This is to make sure that the mail opens in one window, and not half.
(defun mu4e--jump-to-bookmark (bookmark)
"View the message referred to by BOOKMARK."
(let ((msgid (bookmark-prop-get bookmark 'message-id)))
;;(message msgid)
;; Perform the search
(mu4e-headers-search (concat "msgid:" msgid))
;; Delay the call to open-mail-no-split
(run-with-timer 0.1 nil 'open-mail-no-split)))
Copy buffer filename
(defun copy-buffer-filename ()
(interactive)
(kill-new buffer-file-name))
(spc-define-keys spc-leader-map
"fyy" 'copy-buffer-filename
)
Delete org ids
(defun remove-org-ids-from-headlines ()
"Remove all :ID: properties from all headlines in the current Org buffer."
(interactive)
(org-map-entries
(lambda ()
(when (org-at-heading-p)
(org-delete-property "ID")))))
(defun remove-org-custom_ids-from-headlines ()
"Remove all :ID: properties from all headlines in the current Org buffer."
(interactive)
(org-map-entries
(lambda ()
(when (org-at-heading-p)
(org-delete-property "CUSTOM_ID")))))