magit:~/matrix/tools/.emacs.d
https://github.com/yitang/.emacs.d
(setq yt-sphinx/proj-dir "~/matrix/tools/.emacs.d")
(setq yt-sphinx/docs-dir "~/matrix/tools/.emacs.d/docs")
(setq yt-sphinx/proj-badge-md (list "[![Documentation Status](https://readthedocs.org/projects/emacs/badge/?version=latest)](https://readthedocs.org/projects/emacs/?badge=latest)"))
(yt-sphinx/update-documentation)
[2015-01-19 Mon 12:14]
Firstly, define a function for reloading Emacs configuration, need this function in debugging this configuration file.
(defun yt/reload-dot-emacs ()
"Save the .emacs buffer if needed, then reload .emacs."
(interactive)
(let ((dot-emacs "~/.emacs"))
(and (get-file-buffer dot-emacs)
(save-buffer (get-file-buffer dot-emacs)))
(load-file dot-emacs))
(message "Re-initialized!"))
(setq confirm-kill-emacs 'y-or-n-p)
Life is too short to type “yes” or “no”. ‘y’ or ‘n’ is enough.
(fset 'yes-or-no-p 'y-or-n-p)
;; (global-unset-key (kbd "C-x b"))
;; (global-unset-key (kbd "C-x C-b"))
(global-set-key (kbd "C-x C-b") 'ibuffer)
(global-unset-key (kbd "C-x C-c")) ;; save-buffers-kill-terminal
(global-unset-key (kbd "C-x o")) ;; other window. replace by f2 - ace-window.
[2015-01-19 Mon 12:21]
Automatically backup buffers/files into the working directory and the ~.emacs.d/backup// directory.
;; ref: http://stackoverflow.com/questions/151945/how-do-i-control-how-emacs-makes-backup-files
;; save all backup files (foo~) to this directory.
(setq make-backup-files nil) ; stop creating ~ files
(setq backup-directory-alist '(("." . "~/.emacs.d/backup"))
backup-by-copying t ; Don't delink hardlinks
version-control t ; Use version numbers on backups
delete-old-versions t ; Automatically delete excess backups
kept-new-versions 20 ; how many of the newest versions to keep
kept-old-versions 5 ; and how many of the old
auto-save-timeout 20 ; number of seconds idle time before auto-save (default: 30)
auto-save-interval 200 ; number of keystrokes between auto-saves (default: 300)
)
;; guide-key package
;; (require 'guide-key)
;; (setq guide-key/guide-key-sequence t) ;; on for all key-bindings
;; (guide-key-mode 1)
;; use company for all except few modes
(use-package company
:ensure t)
(add-hook 'after-init-hook 'global-company-mode)
;; Don't enable company-mode in below major modes, OPTIONAL
(setq company-global-modes '(not eshell-mode comint-mode erc-mode rcirc-mode))
;; config company mode
(setq company-selection-wrap-around t
company-tooltip-align-annotations t
company-idle-delay 0.36
company-minimum-prefix-length 2
company-tooltip-limit 10)
(setq company-ddabbrev-code-everywhere t)
(setq company-dabbrev-code-modes t)
(setq company-dabbrev-code-other-buffers 'all)
(setq company-dabbrev-ignore-buffers "\\`\\'")
(setq company-dabbrev-char-regexp "\\(\\sw\\|\\s_\\|_\\|-\\)")
;; config company for ESS mode
(defun yt/ess_company_mode_setup ()
;; this is really important. to source vairbales defined in the scripts.
(make-local-variable 'company-backends)
(add-to-list 'company-backends 'company-dabbrev-code)
)
(add-hook 'ess-mode-hook 'yt/ess_company_mode_setup)
(defun text-mode-hook-setup ()
(make-local-variable 'company-backends)
(add-to-list 'company-backends 'company-ispell)
;; (setq company-ispell-dictionary (file-truename "~/matrix/tools/.emacs.d/english_words.txt"))
)
(add-hook 'text-mode-hook 'text-mode-hook-setup)
(use-package company-quickhelp)
(company-quickhelp-mode 1)
(define-key company-active-map (kbd "M-h") #'company-quickhelp-manual-begin)
(define-key company-active-map (kbd "M-h") 'company-show-doc-buffer)
(setq company-dabbrev-downcase nil)
(setq company-show-numbers t)
Configure recent opened files.
(recentf-mode 1)
(setq recentf-max-saved-items 200
recentf-max-menu-items 15)
Shows an notication for invalid operations.
(setq visible-bell nil)
(setq ring-bell-function 'ignore)
Disable startup message
(setq inhibit-startup-message t)
yasnippet is a powerful package that I’d like to explore in the future, and this stage, I turned if off since it will slow down the start-up.
(use-package yasnippet
:ensure t)
(yas/global-mode 1)
(add-to-list 'yas/snippet-dirs "~/matrix/tools/.emacs.d/snippets" t)
(yas/reload-all)
[2015-01-19 Mon 12:13]
I switched from using ace-window
to using the build-in package
movewind
. It uses S+arrow keys to switch to the window adjacent to
the current window.
It was disabled in the org-mode calendar model due to key conflicts. This is the only conflicts I’m aware of in this config.
(windmove-default-keybindings)
(define-key org-read-date-minibuffer-local-map (kbd "<left>") (lambda () (interactive) (org-eval-in-calendar '(calendar-backward-day 1))))
(define-key org-read-date-minibuffer-local-map (kbd "<right>") (lambda () (interactive) (org-eval-in-calendar '(calendar-forward-day 1))))
(define-key org-read-date-minibuffer-local-map (kbd "<up>") (lambda () (interactive) (org-eval-in-calendar '(calendar-backward-week 1))))
(define-key org-read-date-minibuffer-local-map (kbd "<down>") (lambda () (interactive) (org-eval-in-calendar '(calendar-forward-week 1))))
Instead of equally split the window size, it make a lot sense to have the current window, the one I am working one, has bigger size.
;; (require 'golden-ratio)
;; (golden-ratio-mode 1)
;; (add-to-list 'golden-ratio-extra-commands 'ace-window) ;; active golden ratio when using ace-window
Some actions will add/remove windows, and sometimes I’d like to cycle
tough the window layout/changes. In the following settings, C-c
<left>
to undo window layout changes, and C-c <right>
to redo.
(winner-mode 1)
;; winner-undo -> C-c <left>
;; winner-redo -> C-c <right>
I’d like to use two frames, one for doing and logging, and other for reference/searching.
(defun yt/ref-frame ()
(interactive)
;; (frame-parameter (car (frame-list)) 'name)
(if (eq 1 (length (frame-list)))
(new-frame '((name . "***********************REFERENCE*******************")))
nil))
(global-set-key (kbd "M-`") 'other-frame)
[2015-01-19 Mon 12:15]
Solve the PATH issues for the software installed via Homebrew in OS
X. Uncomment the setenv
for CYGWIN since I am not using Windows any
more.
(defun set-exec-path-from-shell-PATH ()
(let ((path-from-shell
(replace-regexp-in-string "[[:space:]\n]*$" ""
(shell-command-to-string "$SHELL -l -c 'echo $PATH'"))))
(setenv "PATH" path-from-shell)
(setq exec-path (split-string path-from-shell path-separator))))
(when (equal system-type 'darwin) (set-exec-path-from-shell-PATH))
;; windows path convention
;; (setenv "CYGWIN" "nodosfilewarning")
Modify the Mac keyboard: unset the C-z just in case I run Emacs in terminal and C-z won’t stop the program without asking.
;; modify mac keyboard
(cond ((eq system-type 'darwin)
(setq mac-command-modifier 'meta)
(fset 'insertPound "#")
(global-set-key (kbd "M-3") 'insertPound)
(global-unset-key (kbd "M-`"))
(global-set-key (kbd "M-`") 'other-frame)
(global-set-key (kbd "C-Z") nil)
))
(prefer-coding-system 'utf-8)
(when (display-graphic-p)
(setq x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING)))
Open PDF files using external program.
;; (require 'openwith)
;; (openwith-mode t)
;; (if (string= system-type "darwin")
;; (setq openwith-associations '(("\\.pdf\\'" "Skim" (file))))
;; (setq openwith-associations '(("\\.pdf\\'" "evince" (file)))))
There are a set of characters that are more likely to occur as a pair, for example, quote and brackets. smartparens mode allows me to define such set of pairing characters.
(use-package smartparens)
(smartparens-global-mode 1)
(sp-pair "(" ")" :wrap "C-(")
;; |foobar
;; hit C-(
;; becomes (|foobar)
(sp-pair "'" nil :actions :rem)
Modern display is widen. Like many of the Emacs users, I prefer to have the text wrapper inside a small region rather than have a stretch across the whole screen. It’s easier to read in this way.
A well accepted rule is to set the width of lines to 80 characters,
and force a logical line breaks. This funcitonality is called
auto-fill
in Emacs, and I can do the filling by call
fill-paragraph
.
(add-hook 'text-mode-hook 'turn-on-auto-fill) ;;
Just in case I need to reverse the auto-fill process.
[2016-06-20 Mon 21:47] Can’t remember when was the last time I use unfill. This snippet is not long used.
(defun yt/unfill-paragraph ()
(interactive)
(let ((fill-column (point-max)))
(fill-paragraph nil)))
(defun yt/unfill-region ()
(interactive)
(let ((fill-column (point-max)))
(fill-region (region-beginning) (region-end) nil)))
Let Emacs remember what I’ve typed, so I don’t need to tediously type the whole thing.
(setq savehist-file "~/matrix/tools/.emacs.d/local/emacs-history")
(savehist-mode 1)
[2019-10-13 Sun 04:46]
;; ;; highlights FIXME: TODO: and BUG: in prog-mode
;; (add-hook 'text-mode-hook
;; (lambda ()
;; (font-lock-add-keywords nil
;; '(("\\<\\(YT\\|TODO\\|IMP\\):" 1 font-lock-warning-face t)))))
[2019-11-09 Sat 11:52]
(defun move-text-internal (arg)
(cond
((and mark-active transient-mark-mode)
(if (> (point) (mark))
(exchange-point-and-mark))
(let ((column (current-column))
(text (delete-and-extract-region (point) (mark))))
(forward-line arg)
(move-to-column column t)
(set-mark (point))
(insert text)
(exchange-point-and-mark)
(setq deactivate-mark nil)))
(t
(beginning-of-line)
(when (or (> arg 0) (not (bobp)))
(forward-line)
(when (or (< arg 0) (not (eobp)))
(transpose-lines arg))
(forward-line -1)))))
(defun move-text-down (arg)
"Move region (transient-mark-mode active) or current line
arg lines down."
(interactive "*p")
(move-text-internal arg))
(defun move-text-up (arg)
"Move region (transient-mark-mode active) or current line
arg lines up."
(interactive "*p")
(move-text-internal (- arg)))
(global-set-key [\M-\S-up] 'move-text-up)
(global-set-key [\M-\S-down] 'move-text-down)
[2015-07-20 Mon 11:46]
I use the Adobe’s Source Code Pro font, it is Monospaced font and claimed to be suitable for coding environments but I use it for all modes.
(add-to-list 'default-frame-alist '(font . "Source Code Pro-16"))
[2015-07-20 Mon 11:46]
I never click any buttons in the tool-bar, nor need the scroll-bar to tell me the cursor position the in the buffer, so I removed all of them to have minimalist GUI of Emacs.
Recently I found menu-bar is really useful, it shows commonly used functions for a particular mode. Occasionally I found something useful.
(tool-bar-mode -1)
(menu-bar-mode 1)
(scroll-bar-mode -1)
[2015-07-20 Mon 11:46]
I started using modus-operandi as the default theme.
(load-theme 'modus-operandi)
[2015-07-20 Mon 11:46]
The mode line is at the bottom of every Emacs Window aside from MiniBuffer windows. It has most of the relevant information about the buffer, including Git status, Major mode, clock info, etc.
The smart-mode-line packages can make mode-line “smart and sexy”. There are many options to tweak.
(setq sml/no-confirm-load-theme t)
(use-package smart-mode-line
:ensure t)
(setq powerline-arrow-shape 'curve)
(setq powerline-default-separator-dir '(right . left))
(setq sml/theme 'respectful)
(sml/setup)
There are too much information cluttered at the bottom. I disable the display of minor modes, there are just too many and almost all are irrelevant.
(rich-minority-mode 1)
(setf rm-blacklist "")
This will leave empty spaces which can be removed by
(setq sml/mode-width 'full)
(setq sml/name-width 40)
Finally, show the current time in the mode-line.
(setq display-time-format "W%W %H:%M")
(display-time-mode)
;; (display-time)
[2019-04-01 Mon 21:43]
later i found that Emacs runs much faster in Terminal. for the reason i don’t know but I really enjoy the lightning speed. here’s a selection of confugratino for working Emacs in terminal.
(add-hook 'suspend-hook
(lambda () (or (y-or-n-p "Really suspend? ")
(error "Suspend canceled"))))
(add-hook 'suspend-resume-hook (lambda () (message "Resumed!")
(sit-for 2)))
then fg
to bring back emacs.
[2015-01-19 Mon 12:10]
When refactoring code, I need to rename a variable or function names,
the normal way to do that is via searching and replacing.
multiple-cursors
provides function to select all the words/symbols
that is highlighted and then modify all of them at the same time.
(use-package multiple-cursors)
(global-set-key (kbd "C->") 'mc/mark-next-like-this)
(global-set-key (kbd "C-<") 'mc/mark-previous-like-this)
Instead of moving into the place I want, ace-jump provides a way to jump directly to there places, just by pressing 4-5 keys. The places can be a character, line, or word. Personally I found it is really efficient to jump to a word when editing.
(global-set-key (kbd "C-c w") 'ace-jump-word-mode)
[2015-01-20 Tue 07:47]
expand-region provides smart way of sectioning, by expanding the scope one at a time. for example,
S = "A B C"
If the cursor in inside of the quote, I press C-=
, everything inside
of the quote is selected, press it again, the quotes are also
selected, press it again, the whole line/region is selected. It saves
a lot of keystrokes in highlighting the area.
It works well with smartparens mode, if I want to apply markup
syntax around a word, I press C-=
to select it, then insert quote or
forward slash, the whole word will be warped inside of quote or
forward flash.
(use-package expand-region)
(global-set-key (kbd "C-=") 'er/expand-region)
[2015-01-28 Wed 07:46]
For the file management tasks like rename and delete, I’d like to wrapper it as a Lisp function and call it directly in Emacs.
Rename the buffer-visiting file, and also rename the buffer. Similar to the save as idea but will remove the older file.
;; rename current buffer-visiting file
(defun yt/rename-current-buffer-file ()
"Renames current buffer and file it is visiting."
(interactive)
(let ((name (buffer-name))
(filename (buffer-file-name)))
(if (not (and filename (file-exists-p filename)))
(error "Buffer '%s' is not visiting a file!" name)
(let ((new-name (read-file-name "New name: " filename)))
(if (get-buffer new-name)
(error "A buffer named '%s' already exists!" new-name)
(rename-file filename new-name 1)
(rename-buffer new-name)
(set-visited-file-name new-name)
(set-buffer-modified-p nil)
(message "File '%s' successfully renamed to '%s'"
name (file-name-nondirectory new-name)))))))
Another useful Lisp function is to copy the file path to clipboard for cross reference.
;; full path of current buffer
(defun yt/copy-full-path-to-kill-ring ()
"copy buffer's full path to kill ring"
(interactive)
(when buffer-file-name
(let* ((file-truename buffer-file-name))
;;(rel-name (file-relative-name file-truename "~/"))) ; BUG: if filename is not relative to home directory.
;; (kill-new (concat "~/" rel-name)))))
(kill-new file-truename))))
(defun yt/copy-rel-path-to-kill-ring ()
"copy buffer's relative path to project directory to kill ring"
(interactive)
(when (and buffer-file-name (magit-toplevel))
(let* ((file-truename buffer-file-name))
(kill-new (file-relative-name file-truename (magit-top-level))))))
Open a file as a root user in Emacs, very handy.
(defun yt/sudo-find-file (file-name)
"Like find file, but opens the file as root."
(interactive "FSudo Find File: ")
(let ((tramp-file-name (concat "/sudo::" (expand-file-name file-name))))
(find-file tramp-file-name)))
Find out the last modified date for current buffer, I need this often when updating a blog post or documents.
(defun yt/last-updated-date ()
"return modification time of current file-visitng buffer"
(interactive)
(let* ((mtime (visited-file-modtime)))
(unless (integerp mtime)
(concat "/Last UPdated/: "
(format-time-string "%d %b %Y" mtime)))))
Remove current buffer-visiting file, and kill the buffer. I use this function often in testing and trying out.
(defun yt/delete-this-buffer-and-file ()
"Removes file connected to current buffer and kills buffer."
(interactive)
(let ((filename (buffer-file-name))
(buffer (current-buffer))
(name (buffer-name)))
(if (not (and filename (file-exists-p filename)))
(error "Buffer '%s' is not visiting a file!" name)
(when (yes-or-no-p "Are you sure you want to remove this file? ")
(delete-file filename)
(kill-buffer buffer)
(message "File '%s' successfully removed" filename)))))
Open the file manager at the default directory.
;; http://ergoemacs.org/emacs/emacs_dired_open_file_in_ext_apps.html
(defun yt/open-file-manager ()
"Show current file in desktop (OS's file manager)."
(interactive)
(cond
((string-equal system-type "windows-nt")
(w32-shell-execute "explore" (replace-regexp-in-string "/" "\\" default-directory t t)))
((string-equal system-type "darwin") (shell-command "open ."))
((string-equal system-type "gnu/linux")
(let ((process-connection-type nil)) (start-process "" nil "xdg-open" "."))
;; (shell-command "xdg-open .") ;; 2013-02-10 this sometimes froze emacs till the folder is closed. ⁖ with nautilus
)))
;; sort files in dired mode by datetime
(setq dired-listing-switches "-lsh")
(setq dired-recursive-copies 'always)
(setq dired-dwim-target t)
(add-hook 'dired-mode-hook (lambda () (dired-hide-details-mode)))
[2015-01-19 Mon 12:08]
Projectile is an powerful Emacs package but I only use projectile to jump between different git folders.
(use-package projectile)
(projectile-mode +1)
(define-key projectile-mode-map (kbd "C-c p") 'projectile-command-map)
;; as of [2023-01-17 Tue 19:35], there's issue with
;; projectile-switch-project function. it cannot detect the right
;; project directory. so i have to use consult-projectile for this.
(use-package consult-projectile)
(setq consult-projectile-source-projectile-project-action #'(lambda (dir) (dired dir)))
(define-key projectile-command-map (kbd "p") 'consult-projectile-switch-project)
There are many things work out of box. For example, use C-p p
to
choose which project to jump to, but I can type M-g
to invoke Magit
or M-e
to invoke Eshell for that project.
[2015-01-22 Thu 23:11]
I can work on the remote files in Emacs via ssh or tramp, both are build-in packages.
(use-package tramp)
(use-package ssh)
(add-to-list 'tramp-remote-path 'tramp-own-remote-path)
(defun yt/tramp-abort ()
;; kill all tramp connections.
(interactive)
(recentf-cleanup)
(tramp-cleanup-all-buffers)
(tramp-cleanup-all-connections))
I’d like catch the password so that I don’t need to type it every time to open a file.
(setq password-cache-expiry nil)
I mainly run R on a remote machine. Sometimes I want to copy the charts I created to local to include them in my report. This workfow is suspended because it fails when the file size is large.
;; (defun yt/sync-local-remote ()
;; (interactive)
;; "copy all files in remote:~/LR_share to local:~/LR_share,
;; does not support the ther way"
;; (find-file "/ssh:remote_host:/remote_directory")
;; ;; (mark-whole-buffer)
;; (dired-mark-subdir-files)
;; ;; (find-file "~/LR_share")
;; ;; (setq-local dirqed-dwim-target t)
;; (dired-do-copy))
[2015-07-20 Mon 11:39]
scratch buffer is usually used for testing Emacs lisp functions. I
also need temporary buffers for testing R code and org-mode. In the
following settings, I can use F9-f
to select temporal buffers.
(defvar yt/temp-dir "~/.tmp"
"temporay folders")
(defun yt/open-tmp-R ()
(interactive)
(find-file (expand-file-name "tmp.R" yt/temp-dir)))
(defun yt/open-tmp-el ()
(interactive)
(find-file (expand-file-name "tmp.el" yt/temp-dir)))
(defun yt/open-tmp-org ()
(interactive)
(find-file (expand-file-name "tmp.org" yt/temp-dir)))
(global-set-key (kbd "<f9> f r") 'yt/open-tmp-R)
(global-set-key (kbd "<f9> f e") 'yt/open-tmp-el)
(global-set-key (kbd "<f9> f o") 'yt/open-tmp-org)
As Statistician, coding in R and writing report is what I do most of the day. I have been though a long way of searching the perfect editor for me, tried Rstudio, SublimeText, TextMate and settled down happily with ESS/Emacs, for both coding and writing.
There three features that have me made the decision:
- Auto Formatting
Scientists has reputation of being bad programmers, who wrote the code that is unreadable and therefore incomprehensible to others. I have intention to become top level programmer and followed a style guide strictly. It means I have to spent sometime in adding and removing space in the code.
To my surprise, Emacs will do it for me automatically, just by hitting the TAB and it also indent smartly, which make me conformable to write long function call and split it into multiple lines. Here’s an example. Also if I miss placed a ‘)’ or ‘]’ the formatting will become strange and it reminders me to check.
rainfall.subset <- data.table(rainfall.london, rainfall.pairs, rainfall.dublin)
- Search Command History
I frequently search the command history. Imaging I was produce a plot and I realised there was something miss in the data, so I go back and fix the data first, then run the ggplot command again, I press Up/Down bottom many times, or just search once/two times.
M-x ggplot(
will gives me the most recent command I typed containing the keyword ggplot(, then I pressRET
to select the command, which might beggplot(gg.df, aes(lon, lat, col = city)) + geom_line() + .....
. If it is not I want, I pressC-r
again to choose the second most recent one and repeat until I find right one. - Literate Programming
I am an supporter of literate statistical analysis and believe we should put code, results and discoveries together in developing models. Rstudio provides an easy to use tool for this purpose, but it does not support different R sessions, so if I need to generate a report, I have to re-run all the code from beginning, which isn’t particle for me with volumes data because it will take quit long.
ESS and org-mode works really well via Babel, which is more friendly to use. I can choose to run only part of the code and have the output being inserted automatically, no need to copy/paste. Also, I can choose where to execute the code, on my local machine or the remote server, or both at the same time.
These are only the surface of ESS and there are lot more useful features like spell checking for comments and documentation templates, that makes me productive and I would recommend anyone use R to learn ESS/Emacs. The following is my current setting.
;; Adapted with one minor change from Felipe Salazar at
;; http://www.emacswiki.org/emacs/EmacsSpeaksStatistics
(use-package ess
:ensure t
:init (require 'ess-site))
(setq ess-ask-for-ess-directory nil) ;; start R on default folder
(setq ess-local-process-name "R")
(setq ansi-color-for-comint-mode 'filter) ;;
;; (setq comint-scroll-to-bottom-on-input t)
;; (setq comint-scroll-to-bottom-on-output nil)
;; (setq comint-move-point-for-output nil)
(setq ess-eval-visibly-p 'nowait) ;; no waiting while ess evalating
(defun my-ess-start-R ()
(interactive)
(if (not (member "*R*" (mapcar (function buffer-name) (buffer-list))))
(progn
(delete-other-windows)
(setq w1 (selected-window))
(setq w1name (buffer-name))
(setq w2 (split-window w1))
(R)
(set-window-buffer w2 "*R*")
(set-window-buffer w1 w1name))))
(defun my-ess-eval ()
(interactive)
(my-ess-start-R)
(if (and transient-mark-mode mark-active)
(call-interactively 'ess-eval-region)
(call-interactively 'ess-eval-line-and-step)))
(add-hook 'ess-mode-hook
'(lambda()
(local-set-key [(shift return)] 'my-ess-eval)))
(add-hook 'ess-mode-hook
(lambda ()
(flyspell-prog-mode)
(run-hooks 'prog-mode-hook)
))
(add-hook 'ess-R-post-run-hook (lambda () (smartparens-mode 1)))
;; REF: http://stackoverflow.com/questions/2901198/useful-keyboard-shortcuts-and-tips-for-ess-r
;; Control and up/down arrow keys to search history with matching what you've already typed:
(define-key comint-mode-map [C-up] 'comint-previous-matching-input-from-input)
(define-key comint-mode-map [C-down] 'comint-next-matching-input-from-input)
(setq ess-history-file "~/.Rhisotry")
(setq ess-indent-with-fancy-comments nil)
(define-key ess-r-mode-map "_" #'ess-insert-assign)
(define-key inferior-ess-r-mode-map "_" #'ess-insert-assign)
In Emacs, syntax highlighting is known as font-locking. You can customize the amount of syntax highlighting that you want to see. At the top of the Emacs window, click on the ESS menu and select “Font Lock”. This will display a menu of buttons corresponding to language elements that you can syntax highlight.
(setq ess-R-font-lock-keywords
'((ess-R-fl-keyword:modifiers . t)
(ess-R-fl-keyword:fun-defs . t)
(ess-R-fl-keyword:keywords . t)
(ess-R-fl-keyword:assign-ops)
(ess-R-fl-keyword:constants . t)
(ess-fl-keyword:fun-calls . t)
(ess-fl-keyword:numbers)
(ess-fl-keyword:operators)
(ess-fl-keyword:delimiters)
(ess-fl-keyword:=)
(ess-R-fl-keyword:F&T)
(ess-R-fl-keyword:%op%)))
use pretty mode
;; (add-hook 'ess-mode-hook 'turn-on-pretty-mode)
[2015-01-23 Fri 17:53]
;; edit roxy template
;; ess-roxy-update-entry
(setq ess-roxy-template-alist '(("description" . " content for description")
("details" . "content for details")
("title" . "")
("param" . "")
("return" . "")
("export" . "")
("author" . "Yi Tang")))
[2015-01-20 Tue 10:49]
https://github.com/jimhester/lintr the default R-style is not meet my with current R project style, has to turn it off.
(use-package flycheck)
;; '(flycheck-lintr-caching nil) ;; need to customised it inside of Emacs
;; (add-hook 'ess-mode-hook
;; (lambda () (flycheck-mode t)))
[2015-06-25 Thu 10:02]
[2015-05-26 Tue 12:41]
clean up the messy R scripts buffer. it will
- remove comments lines start with ‘## ’
- remove blank lines,
- add one blank lines between sections, which defined by ‘#### ‘.
(defun yt/clean-R ()
(interactive)
(when (string= major-mode "ess-mode")
(progn
(goto-char (point-min))
(flush-lines "^\\(\\|[[:space:]]+\\)[#]\\{1,3\\} ") ;; remove lines with only commenst and start with #, ##, or ###, but not #### for it's the section heading.
(flush-lines "^\\(\\|[[:space:]]+\\)$") ;; blank lines
(replace-regexp "#### " "\n#### ") ;; add blank lines between sections.
(while (search-forward-regexp "##[^']" nil t) ;; remove inline comments start with ##
(kill-region (- (point) 3) (line-end-position)))
(save-buffer))))
apply the clean scripts to the tangled file. also, preappend the date and my name on the tangled file.
;; add author info
(defun yt/ess-author-date ()
(interactive)
(when (string= major-mode "ess-mode")
(goto-char (point-min))
(insert "##' @author: Yi Tang\n")
(insert "##' @date: ")
(insert (format-time-string "%F %T"))
(insert "\n\n")
(save-buffer)))
(add-hook 'org-babel-post-tangle-hook 'yt/ess-author-date)
(add-hook 'org-babel-post-tangle-hook 'yt/clean-R)
increase readability
(defun yt/ess-chunk-args--line ()
"sim.gc.table <- data.table(duration = sort(sim.duration, decreasing = TRUE), rp = 1e4 / seq(1, length(sim.duration))) becomes
sim.gc.table <- data.table(duration = sort(sim.duration,
decreasing = TRUE),
rp = 1e4 / seq(1, length(sim.duration)))
"
(interactive)
(save-excursion
(let ((start-point (point)))
(while (re-search-forward ", \\([a-z]+ =\\)" (line-end-position) t)
(replace-match (concat ",\n " (match-string 1))))
(indent-region start-point (line-end-position))
(goto-char start-point))))
(defun yt/ess-chunk-plus--line ()
"ggplot(obs.gc.table, aes(rp, duration)) + geom_point() + scale_x_log10() + scale_y_log10()
becomes
ggplot(obs.gc.table, aes(rp, duration)) +
geom_point() +
scale_x_log10() +
scale_y_log10()
"
(interactive)
(save-excursion
(let ((start-point (point)))
(replace-regexp " \\+ " " +\n " nil (point) (line-end-position))
(indent-region start-point (line-end-position))
(goto-char start-point))))
testing
(defun yt/ess-script-variables ()
(interactive)
(let ((var-list '())
(data-list '()))
(save-excursion
(while (search-forward-regexp "^[[:space:]]*\\([[:alpha:]]+\\) <- function\(" nil t)
(add-to-list 'func-list (match-string-no-properties 1))))
(save-excursion
(while (search-forward-regexp "^[[:space:]]*\\([a-z\\.]+\\) <- " nil t)
(add-to-list 'var-list (match-string-no-properties 1))))
(append (set-difference var-list func-list) data-list)))
(defun yt/ess-remove-variables-not-in-scripts ()
(interactive)
(let* ((all-vars (yt/ess-script-variables))
(all-vars-R (concat "c(\"" (mapconcat 'identity all-vars "\",\"")
"\")")))
(kill-new (concat "rm(list = setdiff\(setdiff\(ls\(\), lsf.str\(\)\), " all-vars-R "\)\)"))))
[2016-05-13 Fri 14:17]
Define in auto-complete section.
(defun yt/bash_run_R ()
(interactive)
(let* ((args (concat "R --no-save --no-restore < " (file-name-nondirectory (buffer-file-name))))
(output-buf-name (concat "*R:" (file-name-nondirectory (buffer-file-name)) "*"))
)
(async-shell-command args output-buf-name)
(with-current-buffer output-buf-name
(inferior-ess-mode))
))
;; (visit-tags-table "~/R_tags")
[2015-01-23 Fri 17:43]
Spell checking and correcting are essential in writing. Emacs need
third party program do this. There are a couple of programs and I use
aspell
. It is part of GNU and can be easily installed in OS X and
Ubuntu. The following snippet tells Emacs where aspell
is installed
and use British dictionary.
(if (eq system-type 'darwin)
(setq ispell-program-name "/opt/homebrew/bin/aspell") ;; this semes not necessary
(setq ispell-program-name "/usr/bin/aspell"))
(setq ispell-dictionary "british"
ispell-extra-args '() ;; TeX mode "-t"
ispell-silently-savep t)
I have a personal spelling dictionary, most are abbreviations and jargon. I can tell aspell that they are not misspellings.
(setq ispell-personal-dictionary "~/matrix/tools/.emacs.d/local/ispell-dict") ;; add personal dictionary
(add-to-list 'ispell-skip-region-alist '(":\\(PROPERTIES\\|LOGBOOK\\):" . ":END:"))
(add-to-list 'ispell-skip-region-alist '("#\\+BEGIN_SRC" . "#\\+END_SRC"))
Flyspell
depends on ispell mode and enables on-the-fly spell
checking/correcting. I enable the flyspell mode for text-mode and
org-mode.
By default, I use C-, to move the cursor to the next misspelled word,
and flycheck
will provide a list of candidates for
auto-correlection. I press C-.
select the first one, and press it
again to select the next one.
(use-package flyspell)
(add-hook 'text-mode-hook 'flyspell-mode)
(add-hook 'org-mode-hook 'flyspell-mode)
;; (define-key flyspell-mode-map (kbd "C-.") 'helm-flyspell-correct)
;; TODO - cannot get consult-flyspell working
(use-package consult-flyspell
;; :straight (consult-flyspell :type git :host gitlab :repo "OlMon/consult-flyspell" :branch "master")
:config
;; default settings
(setq consult-flyspell-select-function (lambda () (flyspell-correct-at-point) (consult-flyspell))
consult-flyspell-set-point-after-word t
consult-flyspell-always-check-buffer nil))
;; (require 'flyspell-correct)
;; (require 'flyspell-correct-ido)
;; (define-key flyspell-mode-map (kbd "C-;") 'flyspell-correct-wrapper)
(use-package flyspell-correct
:after flyspell
:bind (:map flyspell-mode-map ("C-." . flyspell-correct-wrapper)))
(use-package flyspell-correct-ivy
:after flyspell-correct)
I need an grammar check to let me know that
Have you do ...
is wrong, and also tell me to change do to done, and also why.
langtool
can do be the job, but currently I don’t understand how to
get it works, so I am not using it anymore.
;; ;; check grammar
(use-package langtool)
(if (eq system-type 'darwin)
;; (setq langtool-java-bin "/opt/homebrew/opt/openjdk/bin/java")
(setq langtool-language-tool-jar "~/Downloads/LanguageTool-6.3/languagetool-commandline.jar"))
(setq langtool-mother-tongue "en")
;; checkout this also; https://github.com/emacs-languagetool/flycheck-languagetool
;; https://github.com/PillFall/languagetool.el
;; not working
;; (use-package languagetool
;; :ensure t
;; :defer t
;; :commands (languagetool-check
;; languagetool-clear-suggestions
;; languagetool-correct-at-point
;; languagetool-correct-buffer
;; languagetool-set-language
;; languagetool-server-mode
;; languagetool-server-start
;; languagetool-server-stop)
;; :config
;; (setq languagetool-java-arguments '("-Dfile.encoding=UTF-8")
;; languagetool-console-command "/Users/yitang/Downloads/LanguageTool-6.3/languagetool-commandline.jar"
;; languagetool-server-command "/Users/yitang/Downloads/LanguageTool-6.3/languagetool-server.jar"))
I have been writing in Emacs/org-mode a lot, have been really tired of capitalise i to I, so I use abbrevitation table.
name | expand | Category |
---|---|---|
i | I | write |
amax | annual maximum | stat |
gmap | google map | website |
mailme | [email protected] | aboutme |
twitterme | @yi_tang_uk | aboutme |
eqt | equivalent to | english |
iif | if and only if | maths |
wrt | with respect to | English |
st | such that | English |
d/n | distribution | Stats |
obs | observation | stats |
obss | observations | stats |
(defun my-text-abbrev-expand-p ()
"Return t if the abbrev is in a text context, which is: in
comments and strings only when in a prog-mode derived-mode or
src block in org-mode, and anywhere else."
(if (or (derived-mode-p 'prog-mode)
(and (eq major-mode 'org-mode)
(org-in-src-block-p 'inside)))
(nth 8 (syntax-ppss))
t))
(define-abbrev-table 'my-text-abbrev-table ()
"Abbrev table for text-only abbrevs. Expands only in comments and strings."
:enable-function #'my-text-abbrev-expand-p)
(dolist (table (list text-mode-abbrev-table
prog-mode-abbrev-table))
(abbrev-table-put table
:parents (list my-text-abbrev-table)))
(defun my-text-abbrev-table-init (abbrevs-org-list)
"Parse 'name: expansion' pairs from an org list and insert into abbrev table."
(message "Creating text-abbrev table...")
(dolist (abbrev abbrevs-org-list)
(let ((name (nth 0 abbrev))
(expansion (nth 1 abbrev)))
;; (print (cons name expansion))
(define-abbrev my-text-abbrev-table name expansion nil :system t))))
;;(my-text-abbrev-table-init my-text-abbrevs) ; BUG: only work in org-mode
[2015-05-26 Tue 12:13]
English is my second language, and I am trying to avoid certain guarding term in writing. The following snipts I get it from Sachua will highlight the word like shuold or I think, which reminds to confirm with what I am not sure about, and have more confidence in what I am saying.
(use-package artbollocks-mode)
(add-hook 'text-mode-hook 'artbollocks-mode)
(setq artbollocks-weasel-words-regex
(concat "\\b" (regexp-opt
'("should"
"just"
"sort of"
"a lot"
"probably"
"maybe"
"perhaps"
"I think"
"really"
"nice") t) "\\b"))
add synosaurus
;; [2015-02-12 Thu 21:14]
;; https://github.com/rootzlevel/synosaurus
;; synosaurus-lookup
;; synosaurus-choose-and-replace
;; brew install wordnet
(require 'synosaurus)
(setq synosaurus-choose-method "popup")
;; synosaurus-lookup C-c s l
;; synosaurus-choose-and-replace C-c s r
(setq synosaurus-backend 'synosaurus-backend-wordnet)
(setq synosaurus-choose-method 'popup)
Title Case
(defun xah-title-case-region-or-line (φbegin φend)
"Title case text between nearest brackets, or current line, or text selection.
Capitalize first letter of each word, except words like {to, of, the, a, in, or, and, …}. If a word already contains cap letters such as HTTP, URL, they are left as is.
When called in a elisp program, φbegin φend are region boundaries.
URL `http://ergoemacs.org/emacs/elisp_title_case_text.html'
Version 2015-05-07"
(interactive
(if (use-region-p)
(list (region-beginning) (region-end))
(let (
ξp1
ξp2
(ξskipChars "^\"<>(){}[]“”‘’‹›«»「」『』【】〖〗《》〈〉〔〕"))
(progn
(skip-chars-backward ξskipChars (line-beginning-position))
(setq ξp1 (point))
(skip-chars-forward ξskipChars (line-end-position))
(setq ξp2 (point)))
(list ξp1 ξp2))))
(let* (
(ξstrPairs [
[" A " " a "]
[" And " " and "]
[" At " " at "]
[" As " " as "]
[" By " " by "]
[" Be " " be "]
[" Into " " into "]
[" In " " in "]
[" Is " " is "]
[" It " " it "]
[" For " " for "]
[" Of " " of "]
[" Or " " or "]
[" On " " on "]
[" Via " " via "]
[" The " " the "]
[" That " " that "]
[" To " " to "]
[" Vs " " vs "]
[" With " " with "]
[" From " " from "]
["'S " "'s "]
]))
(save-excursion
(save-restriction
(narrow-to-region φbegin φend)
(upcase-initials-region (point-min) (point-max))
(let ((case-fold-search nil))
(mapc
(lambda (ξx)
(goto-char (point-min))
(while
(search-forward (aref ξx 0) nil t)
(replace-match (aref ξx 1) 'FIXEDCASE 'LITERAL)))
ξstrPairs))))))
Based on Bernt Hansen’s Org Mode - Organize Your Life In Plain Text!.
[2015-07-20 Mon 14:57]Define the TODO keywords and their colour.
(setq org-todo-keywords
(quote ((sequence "TODO(t)" "NEXT(n)" "WIP(w)" "SOMEDAY" "|" "DONE(d)")
(sequence "WAITING(W@/!)" "HOLD(h@/!)" "|" "CANCELLED(c@/!)" "MEETING"))))
(setq org-todo-keyword-faces
(quote (("TODO" :foreground "red" :weight bold)
("NEXT" :foreground "red" :weight bold)
("DONE" :foreground "forest green" :weight bold)
("WAITING" :foreground "orange" :weight bold)
("HOLD" :foreground "magenta" :weight bold)
("CANCELLED" :foreground "forest green" :weight bold)
("MEETING" :foreground "forest green" :weight bold))))
Define an event when a TODO status changes, for example, if changed to HOLD, add HOLD tag and remove WAITING tag. If changed to DONE, remove both HOLD and WAITING tags.
(setq org-todo-state-tags-triggers
(quote (("CANCELLED" ("CANCELLED" . t))
("WAITING" ("WAITING" . t))
("HOLD" ("WAITING") ("HOLD" . t))
(done ("WAITING") ("HOLD"))
("TODO" ("WAITING") ("CANCELLED") ("HOLD"))
("NEXT" ("WAITING") ("CANCELLED") ("HOLD"))
("DONE" ("WAITING") ("CANCELLED") ("HOLD")))))
Especially, when a task is marked as DONE, a timestamp is added to the LOGBOOK drawer.
- when a task is marked as DONE, a timestamp is added below the
headline, for exmaple,
CLOSED: [2023-03-19 Sun 08:54]
(setq org-log-done (quote time))
(setq org-log-into-drawer t) ; t means LOGBOOK
(setq org-log-state-notes-insert-after-drawers nil)
Add a cross line for the headline with DONE status. Note currently it is disabled before of the performance issues in OS X.
(defun yt/modify-org-done-face ()
(setq org-fontify-done-headline t)
(set-face-attribute 'org-done nil :strike-through nil)
(set-face-attribute 'org-headline-done nil
:strike-through t
:foreground "light gray"))
;; turn it off for now.
;; (add-hook 'org-mode-hook 'yt/modify-org-done-face)
;; (setq org-fontify-done-headline t)
;; (set-face-attribute 'org-done nil :strike-through t)
;; (set-face-attribute 'org-headline-done nil :strike-through t)
[2015-07-20 Mon 14:57]
Use C-c c
anywhere to quickly create a org headline and save it to a
default place.
(global-set-key (kbd "C-c c") 'org-capture)
[2015-07-20 Mon 14:57]
Set the refile targets, they are all level 1 2 3 in current buffer and all the files in org-agenda-files.
(setq org-refile-targets
'((nil :maxlevel . 3)
(org-agenda-files :maxlevel . 3)))
(setq org-outline-path-complete-in-steps nil)
but exclude DONE state tasks from refile targets
(defun bh/verify-refile-target ()
"Exclude todo keywords with a done state from refile targets"
(not (member (nth 2 (org-heading-components)) org-done-keywords)))
(setq org-refile-target-verify-function 'bh/verify-refile-target)
Provide refile targets as paths. So a level 3 headline will be available as level1/level2/level3.
(setq org-refile-use-outline-path t)
Speed up the process by using cache.
(setq org-refile-use-cache t)
Save the running clock and all clock history when exiting Emacs, load it on startup. this is useful when i forget closing the clock, or crash.
(setq org-clock-persist t)
Resume clocking task when Emacs starts, and if continue to count on this task.
(org-clock-persistence-insinuate)
(setq org-clock-in-resume t)
;; Do not prompt to resume an active clock
;; (setq org-clock-persist-query-resume nil)
;; Save clock data and state changes and notes in the LOGBOOK drawer
(setq org-clock-into-drawer t)
;; Sometimes I change tasks I'm clocking quickly - this removes clocked tasks with 0:00 duration
(setq org-clock-out-remove-zero-time-clocks t)
;; Clock out when moving task to a done state
(setq org-clock-out-when-done t)
;; Enable auto clock resolution for finding open clocks
(setq org-clock-auto-clock-resolution (quote when-no-clock-is-running))
;; Include current clocking task in clock reports
(setq org-clock-report-include-clocking-task t)
highlight the clocking info in mode line.
(set-face-attribute 'org-mode-line-clock nil
:weight 'bold :box '(:line-width 1 :color "#FFBB00") :foreground "white" :background "#FF4040")
List recently clocked headline and clock in.
;; Show lot of clocking history so it's easy to pick items off the C-F11 list
(setq org-clock-history-length 23)
;; ;; http://stackoverflow.com/questions/6156286/emacs-lisp-call-function-with-prefix-argument-programmatically
When clock in to a TODO headline, turn the keywords into NEXT.
;; Change tasks to NEXT when clocking in
(setq org-clock-in-switch-to-state 'bh/clock-in-to-next)
(defun bh/clock-in-to-next (kw)
"Switch a task from TODO to NEXT when clocking in.
Skips capture tasks"
(when (not (and (boundp 'org-capture-mode) org-capture-mode))
(if (member (org-get-todo-state) (list "TODO"))
"NEXT")))
punch-in into a default org-mode headline.
(defun yt/punch-in ()
(interactive)
(org-with-point-at (org-id-find "1b586ec1-fa8a-4bd1-a44c-faf3aa2adf51" 'marker)
(org-clock-in)
))
(global-set-key (kbd "<f9> I") 'yt/punch-in)
remove empty clock entrys at checkout.
(add-hook 'org-clock-out-hook 'org-clock-remove-empty-clock-drawer 'append)
[2015-07-20 Mon 14:57]
I don’t use org-tags.
(setq org-tag-alist (quote ((:startgroup)
("@office" . ?O)
("@home" . ?H)
(:endgroup)
("WAITING" . ?w)
("HOLD" . ?h)
("PERSONAL" . ?P)
("WORK" . ?W)
("NOTE" . ?n)
("READ" .?r)
("CANCELLED" . ?c)
)))
;; Allow setting single tags without the menu
(setq org-fast-tag-selection-single-key (quote expert))
(setq org-agenda-tags-todo-honor-ignore-options t)
(global-set-key (kbd "<f12>") 'org-agenda)
;; Do not dim blocked tasks
(setq org-agenda-dim-blocked-tasks nil)
(setq org-agenda-dim-blocked-tasks 'invisible)
;; Compact the block agenda view
(setq org-agenda-compact-blocks nil)
;; Limit restriction lock highlighting to the headline only
(setq org-agenda-restriction-lock-highlight-subtree nil)
;; Always hilight the current agenda line
(add-hook 'org-agenda-mode-hook
'(lambda () (hl-line-mode 1))
'append)
;;;; * agenda ignore items
;; Keep tasks with dates on the global todo lists
(setq org-agenda-todo-ignore-with-date nil)
;; Keep tasks with deadlines on the global todo lists
(setq org-agenda-todo-ignore-deadlines nil)
;; Keep tasks with scheduled dates on the global todo lists
(setq org-agenda-todo-ignore-scheduled nil)
;; Keep tasks with timestamps on the global todo lists
(setq org-agenda-todo-ignore-timestamp nil)
;; Remove completed deadline tasks from the agenda view
(setq org-agenda-skip-deadline-if-done t)
;; Remove completed scheduled tasks from the agenda view
(setq org-agenda-skip-scheduled-if-done t)
;; Remove completed items from search results
(setq org-agenda-skip-timestamp-if-done t)
(setq org-agenda-include-diary nil)
(setq org-agenda-insert-diary-extract-time t)
;; Include agenda archive files when searching for things
(setq org-agenda-text-search-extra-files (quote (agenda-archives)))
;; Show all future entries for repeating tasks
(setq org-agenda-repeating-timestamp-show-all t)
;; Show all agenda dates - even if they are empty
(setq org-agenda-show-all-dates t)
;; Sorting order for tasks on the agenda
(setq org-agenda-sorting-strategy
(quote ((agenda habit-down time-up user-defined-up effort-up category-keep)
(todo category-up effort-up)
(tags category-up effort-up)
(search category-up))))
;; (setq org-agenda-tags-column -102)
;; Use sticky agenda's so they persist
;; (setq qorg-agenda-sticky t)
Enable display of the time grid so we can see the marker for the current time
(setq org-agenda-time-grid (quote ((daily today require-timed)
(600 630 700 730 800 830 900 930 1000 1030 1200 1400 1600 1800 2000)
"......" "----------------")))
Start the weekly agenda on Monday.
(setq org-agenda-span 'week)
(setq org-agenda-start-on-weekday 1)
show the items 30 prior to their deadline. sounds bit too much. how about 7 days?
(setq org-deadline-warning-days 30)
highlight clock entries that are either too long (more than 4 hours) or too short (less than 5 mins). those entries requires manual checks.
(setq org-agenda-clock-consistency-checks
(quote (:max-duration "4:00" ;; highligh clock entries longer than 5 hours.
:min-duration "00:05" ;; highlight clock smaller than 5 mins
:max-gap "00:05" ;; highlight clock gap loger than 5 mins.
:gap-ok-around ("4:00"))))
(setq org-read-date-prefer-future 'time)
Agenda reminder
;; Erase all reminders and rebuilt reminders for today from the agenda
(defun bh/org-agenda-to-appt ()
(interactive)
(setq appt-time-msg-list nil)
(setq appt-display-format 'window) ;; YT: show notification in separate window
(org-agenda-to-appt))
;; Rebuild the reminders everytime the agenda is displayed
(add-hook 'org-finalize-agenda-hook 'bh/org-agenda-to-appt 'append)
;; This is at the end of my .emacs - so appointments are set up when Emacs starts
;; (bh/org-agenda-to-appt)
[2015-01-29 Thu 14:16] define a list of supported language.
(org-babel-do-load-languages
(quote org-babel-load-languages)
(quote ((emacs-lisp . t) ;; TODO: simplifiy this list
(R . t)
(shell . t)
(org . t)
(dot . t)
(python .t)
;; (ipython .t)
;; (bibtex .t)
(octave . t)
(latex . t)
(jupyter . t)
(sql . t))))
(setq org-confirm-babel-evaluate nil)
;; (use-package conda
;; ;; :straight t
;; :config
;; (setq conda-anaconda-home (expand-file-name "/home/yitang/miniconda3/"))
;; (setq conda-env-home-directory (expand-file-name "/home/yitang/miniconda3/"))
;; (setq conda-env-subdirectory "envs"))
;; (unless (getenv "CONDA_DEFAULT_ENV")
;; (conda-env-activate "latest"))
;; (defun my/jupyter-refresh-kernelspecs ()
;; "Refresh Jupyter kernelspecs"
;; (interactive)
;; (jupyter-available-kernelspecs t))
;; (setq jupyter-use-zmq nil)
define default header for all and specific language
(setq org-babel-default-header-args (append org-babel-default-header-args '((:colnames . "yes"))))
(setq org-babel-default-header-args:R
'((:session . "R")
(:colnames . "yes")))
(setq org-babel-default-header-args:bash
'((:session . "*shell*")))
(setq org-src-window-setup 'current-window)
(setq org-src-fontify-natively t)
(setq org-src-preserve-indentation nil)
(setq org-edit-src-content-indentation 0)
(setq org-catch-invisible-edits 'error)
(setq org-export-coding-system 'utf-8)
(prefer-coding-system 'utf-8)
(set-charset-priority 'unicode)
(setq default-process-coding-system '(utf-8-unix . utf-8-unix))
(setq org-babel-results-keyword "results")
display inline image after execute src-block, useful for src block that generate inline images.
(defun bh/display-inline-images ()
(condition-case nil
(org-display-inline-images)
(error nil)))
(add-hook 'org-babel-after-execute-hook 'bh/display-inline-images 'append)
when switch to the bash session, if does not exists, create a new one. a workaround would be to run a simple function, ls for example first, and then switch to the interactive session.
;; copy of org-sh-bash-initiate-session in ob-shell.el but with different name
;; per https://emacs.stackexchange.com/questions/55957/error-no-org-babel-initiate-session-function-for-bash
(defun org-babel-bash-initiate-session (&optional session _params)
"Initiate a session named SESSION according to PARAMS."
(when (and session (not (string= session "none")))
(save-window-excursion
(or (org-babel-comint-buffer-livep session)
(progn
(shell session)
;; Needed for Emacs 23 since the marker is initially
;; undefined and the filter functions try to use it without
;; checking.
(set-marker comint-last-output-start (point))
(get-buffer (current-buffer)))))))
use python3 in org-babel.
(setq org-babel-python-command "python3")
[2015-02-04 Wed 12:23]
Add export back-end, I need HTML, PDF, MarkDown, and Ascii.
(setq org-export-backends '(ascii html latex md org))
(require 'ox-md) ;; somehow this does not work. i don't know why.
General export options, it applys to all the export-backend.
(setq org-export-with-toc nil
org-export-with-todo-keywords t
org-export-with-sub-superscripts nil
org-export-with-planning nil
org-export-with-author t
org-export-with-timestamps nil
org-export-babel-evaluate t
org-export-with-drawers nil)
(setq org-image-actual-width '(400))
Set the default format when exporting table to CSV.
(setq org-table-export-default-format "orgtbl-to-csv")
[2015-01-19 Mon 15:45]
define the latex export process, by default, it uses latexmk.
below i define the process as list of three shell commands, which will run in sequentially. multiple calls are neeed to ensure bibliograph etc works. i can also clean up the files, for example, remove the intermediary files. need to test those.
;; ;;;; comple pdf
(setq org-latex-pdf-process
'("xelatex -shell-escape -interaction=nonstopmode -output-directory %o %f"
"xelatex -shell-escape -interaction=nonstopmode -output-directory %o %f"
"xelatex -shell-escape -interaction=nonstopmode -output-directory %o %f"))
define customised latex-class which will be use when export org-mode to LaTeX. the latex-class can be defined somewhere else.
;; http://emacs-fu.blogspot.co.uk/2011/04/nice-looking-pdfs-with-org-mode-and.html
;; 'djcb-org-article' for export org documents to the LaTex 'article', using
;; XeTeX and some fancy fonts; requires XeTeX (see org-latex-to-pdf-process)
(require 'ox-latex)
(add-to-list 'org-latex-classes
'("yt/org-article"
"
\\documentclass[11pt,a4paper]{article}
\\usepackage{graphicx} %% demo mode is a must when .img does not exists.
\\usepackage[T1]{fontenc}
\\usepackage{fontspec}
\\usepackage{hyperref}
\\hypersetup{
colorlinks = true,
citecolor = gray
}
\\usepackage{amsmath}
\\usepackage{amstext}
\\usepackage{amssymb} %% checkbox
\\usepackage{commath}
\\usepackage{physics} %% \\pdv for derivative operators https://tex.stackexchange.com/questions/225523/how-to-write-partial-differential-equation-ex-dq-dt-ds-dt-with-real-partial-d
\\DeclareMathOperator*{\\argmin}{\\arg\\!\\min} %% use $\\argmin_{b}$
\\DeclareMathOperator*{\\argmax}{\\arg\\!\\max}
%% \\DeclareMathOperator{\\E}{\\mathbb{E}}
\\newcommand{\\E}[1]{{\\mathbb E}\\left[ #1 \\right]}
\\newcommand{\\Var}{\\mathrm{Var}}
%% \\DeclareMathOperator{\\P}{\\mathbb{Pr}}
\\usepackage{minted}
\\defaultfontfeatures{Mapping=tex-text}
% \\setromanfont[BoldFont={Gentium Basic Bold},
% ItalicFont={Gentium Basic Italic}]{Gentium Plus}
\\setsansfont{Charis SIL}
\\setmonofont[Scale=0.8]{DejaVu Sans Mono}
\\usepackage{geometry}
%% \\geometry{a4paper, textwidth=6.5in, textheight=10in,
%% marginparsep=7pt,
%% marginparwidth=1.2in, %% make sure it less than right=1.5in,
%% otherwise, will go out of the paper
%% right=1.5in, left=0.6in}
\\geometry{a4paper, textwidth=6.5in, textheight=10in,
marginparsep=7pt, marginparwidth=.6in}
\\pagestyle{empty}
%% package from org-latex-default-packages-alist
\\usepackage{setspace}
\\onehalfspacing
\\usepackage{textcomp}
\\usepackage{marvosym}
\\usepackage{wasysym}
\\usepackage{ulem}
\\usepackage{amsthm}
\\theoremstyle{definition}
\\newtheorem{definition}{Definition}[section]% Conjecture is numbered
% within \section
\\newtheorem{lemma}[definition]{Lemma}
\\newtheorem{theorem}[definition]{Theorem}
\\newcommand{\\twodots}{\\mathinner {\\ldotp \\ldotp}}
%% \\renewcommand\\texttt[1]{{\\mint{cl}|#1|}}
\\usepackage{environ}
\\NewEnviron{note}{\\marginpar{\\footnotesize \\BODY}}
%% algorithm
\\usepackage{xcolor}
\\usepackage[linesnumbered]{algorithm2e}
\\newcommand\\mycommfont[1]{\\footnotesize\\ttfamily\\textcolor{blue}{#1}}
\\makeatletter
\\renewcommand{\\@algocf@capt@plain}{above}% formerly {bottom}
\\makeatother
\\title{}
[NO-DEFAULT-PACKAGES]
[NO-PACKAGES]"
("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\subsubsection{%s}" . "\\subsubsection*{%s}")
("\\paragraph{%s}" . "\\paragraph*{%s}")
("\\subparagraph{%s}" . "\\subparagraph*{%s}")))
(setq org-latex-default-class "yt/org-article")
(add-to-list 'org-latex-classes
'("yt/beamer"
"\\documentclass[aspectratio=169]{beamer}
\\usepackage[T1]{fontenc}
\\usepackage{fontspec}
\\usetheme[faculty=fi]{fibeamer}
\\usepackage[utf8]{inputenc}
\\usepackage[
main=english, %% By using `czech` or `slovak` as the main locale
%% instead of `english`, you can typeset the
%% presentation in either Czech or Slovak,
%% respectively.
czech, slovak %% The additional keys allow foreign texts to be
]{babel} %% typeset as follows:
[NO-DEFAULT-PACKAGES]
[NO-PACKAGES]
"
("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\subsubsection{%s}" . "\\subsubsection*{%s}")))
;; (use-package ox-beamer)
;; code highlights using minted package
(add-to-list 'org-latex-packages-alist '("" "minted"))
(setq org-latex-listings 'minted)
(setq org-latex-minted-options
'(("frame" "lines")
("fontsize" "\\scriptsize")))
;; ("linenos" "")))
Remove keys
;; remove C-TAB
(define-key org-mode-map (kbd "C-S-<right>") 'mc/mark-next-like-this)
(define-key org-mode-map (kbd "C-S-<left>") 'mc/mark-previous-like-this)
(org-defkey org-mode-map (kbd "C-c [") nil)
(org-defkey org-mode-map (kbd "C-c ]") nil)
(org-defkey org-mode-map (kbd "C-TAB") nil)
(org-defkey org-mode-map (kbd "<f8>") nil)
Show org-mode bullets as UTF-8 characters.
Add markup wrapper for org-mode. to turn a word into bold, wrapper in
a selected region, by using expand-region, which is bound to C-=
then type *.
(sp-local-pair 'org-mode "=" "=") ; select region, hit = then region -> =region= in org-mode
(sp-local-pair 'org-mode "*" "*") ; select region, hit * then region -> *region* in org-mode
(sp-local-pair 'org-mode "/" "/") ; select region, hit / then region -> /region/ in org-mode
(sp-local-pair 'org-mode "_" "_") ; select region, hit _ then region -> _region_ in org-mode
(sp-local-pair 'org-mode "+" "+") ; select region, hit + then region -> +region+ in org-mode
(sp-local-pair 'org-mode "$" "$") ; select region, hit $ then region -> $region$ in org-mode
[2015-07-20 Mon 14:57]
;;;; * Custom Key Bindings
(setq org-agenda-clockreport-parameter-plist
(quote (:link t :maxlevel 5 :fileskip0 t :compact t :narrow 80)))
;; Set default column view headings: Task Effort Clock_Summary
(setq org-columns-default-format "%80ITEM(Task) %10Effort(Effort){:} %10CLOCKSUM")
;; global Effort estimate values
;; global STYLE property values for completion
(setq org-global-properties (quote (("Effort_ALL" . "0:05 0:15 0:30 0:45 1:00 2:00 3:00 4:00 5:00 6:00 0:00")
("STYLE_ALL" . "habit"))))
(setq org-agenda-log-mode-items (quote (clock)))
(setq org-use-speed-commands t)
(defun bh/insert-inactive-timestamp ()
(interactive)
(org-insert-time-stamp nil t t nil nil nil))
(global-set-key (kbd "<f9> t") 'bh/insert-inactive-timestamp)
(defun yt/insert-ts-as-file ()
(interactive)
(insert (format-time-string "%Y-%m-%d--%H-%M-%S"))
)
(global-set-key (kbd "<f9> T") 'yt/insert-ts-as-file)
(defun bh/insert-heading-inactive-timestamp ()
(save-excursion
(org-return)
(org-cycle)
(bh/insert-inactive-timestamp)))
;; (add-hook 'org-insert-heading-hook 'bh/insert-heading-inactive-timestamp 'append)
(setq org-file-apps (quote ((auto-mode . emacs)
("\\.png\\'" . emacs)
("\\.svg\\'" . system)
("\\.mm\\'" . system)
("\\.x?html?\\'" . system)
("\\.pdf\\'" . "evince %s"))))
; Overwrite the current window with the agenda
(setq org-agenda-window-setup 'current-window)
(setq org-time-clocksum-format
'(:hours "%d" :require-hours t :minutes ":%02d" :require-minutes t))
(add-hook 'org-mode-hook (lambda () (abbrev-mode 1)))
(setq org-reverse-note-order t) ;; refiled headline will be the first under the taget
(setq org-archive-location "::* Archived Tasks") ;;in-file archive
;; (setq org-habit-show-all-today t)
;; (setq org-habit-show-habits nil)
;; (setq org-habit-graph-column 80)
;; add the following
(setq org-time-stamp-custom-formats '("<%A %d %B %Y>" . "<%A %d %B %Y %H:%M>"))
(setq org-agenda-tags-column 120)
(setq org-columns-default-format "%80ITEM(Task) %10Effort(Effort){:} %10CLOCKSUM %10Mindfullness")
Start up options
(setq org-startup-folded "showall"
org-hide-block-startup t
org-startup-indented nil)
C-c C-l org-insert-link by default. found it is easier to have C-c l as store link.
(global-set-key (kbd "C-c l") 'org-store-link)
trying to remove closed item in org-agenda. it does not work, might be a bug in org-mode.
;; https://emacs.stackexchange.com/questions/51755/org-mode-link-files-with-ids-and-not-filenames
;; create id property whenver link a headline -
;; see - https://emacs.stackexchange.com/questions/51755/org-mode-link-files-with-ids-and-not-filenames
(setq org-id-link-to-org-use-id t)
;; by defualt, agenda log mode shows when a taks is closed. i don't wanna that.
(setq org-agenda-log-mode-items '(clock))
add a created timestamp property to each header.
(defvar org-created-property-name "CREATED"
"The name of the org-mode property that stores the creation date of the entry")
(defun org-set-created-property (&optional active NAME)
"Set a property on the entry giving the creation time.
By default the property is called CREATED. If given the `NAME'
argument will be used instead. If the property already exists, it
will not be modified."
(interactive)
(let* ((created (or NAME org-created-property-name))
(fmt (if active "<%s>" "[%s]"))
(now (format fmt (format-time-string "%Y-%m-%d %a %H:%M"))))
(unless (org-entry-get (point) created nil)
(org-set-property created now))))
(add-hook 'org-insert-heading-hook 'org-set-created-property 'append)
(add-hook 'org-capture-prepare-finalize-hook 'org-set-created-property 'append)
I write blog posts in org-mode format, export to Markdown, and let Jekyll render it in HTML over the web.
I have the org/ folder to keep the blog posts and drafts. They are exporting to the blog/_posts and blog/_drafts folder.
(defvar jekyll-source-directory (expand-file-name "~/matrix/learning/mywebsite/org/")
"root directory of org files.")
;; replace those two with jekyll-source-drafts-dir, jekyll-source-post-dir
(defvar jekyll-source-drafts-dir (file-name-concat jekyll-source-directory "_drafts/")
"Relative path to drafts directory.")
(defvar jekyll-source-posts-dir (file-name-concat jekyll-source-directory "_posts/")
"Relative path to posts directory.")
(defvar jekyll-site-dir "~/matrix/learning/mywebsite/blog/"
"root directory of the Jekyll site.")
;; TODO: remove this variable, use jekyll-sit-post-dir instead
;; (defvar jekyll-publish-dir (concat jekyll-site-dir "_posts/")
;; "Relative path to posts directory.")
;; (defvar jekyll-assets-dir (file-name-concat jekyll-site-dir "assets/")
;; "Relative path to assets directory.")
(defvar jekyll-site-posts-dir (file-name-concat jekyll-site-dir "_posts/")
"Relative path to posts directory.")
(defvar jekyll-site-drafts-dir (file-name-concat jekyll-site-dir "_drafts/")
"Relative path to posts directory.")
(defvar jekyll-site-assets-dir (file-name-concat jekyll-site-dir "assets/")
"Relative path to assets directory.")
(defvar jekyll-post-ext ".org"
"File extension of Jekyll posts.")
The jekyll-post-template contains the frontmatter Jekyll requires, a short HTML snippet for MathJax (might not need at all), and org-mode snippets to control the exporting.
This template is used when creating a post/draft in org-mode, the title will be populated.
(defvar jekyll-post-template
"
#+begin_export html
---
layout: post
title: %s
# date: add publish date when ready
excerpt:
categories:
-
tags:
-
comments: true
---
#+END_export
#+begin_export html
<script type=\"text/javascript\"
src=\"http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML\">
</script>
#+end_export
# #+call: GetLastUpdatedDate[:exports none]()[:results org]
#+BIND: org-md-toplevel-hlevel 2
#+TOC: headlines 4
* COMMENT checklist
- [ ] check title
- [ ] check gramamr
- [ ] check tags,
- [ ] check dates, publish front matter
- [ ] promote in social media
"
"Default template for Jekyll posts. %s will be replace by the post title.")
(defun jekyll-yaml-escape (s)
"Escape a string for YAML."
(if (or (string-match ":" s)
(string-match "\"" s))
(concat "\"" (replace-regexp-in-string "\"" "\\\\\"" s) "\"")
s))
The jekly-ymal-escape
function is used just to handle the quote and : characters in the title field.
Then in starting a blog post, I fill the title, and there file will be served in the org/_drafts folder, and insert the YMAL. Note in jeklly, the title be part of html file name and therefore part of the URL. So strange characters must been removed.
(defun blog-draft-post (title)
"Create a new Jekyll blog post."
(interactive "sPost Title: ")
(let ((draft-file (concat jekyll-source-drafts-dir
(jekyll-make-slug title)
jekyll-post-ext)))
(if (file-exists-p draft-file)
(find-file draft-file)
(find-file draft-file)
(insert (format jekyll-post-template (jekyll-yaml-escape title))))))
(defun jekyll-make-slug (s)
"Turn a string into a slug."
(replace-regexp-in-string
" " "-" (downcase
(replace-regexp-in-string
"[^A-Za-z0-9 ]" "" s))))
Once I think the article is read to be publish, the
blog-publish-post
function will move the editing draft into
org/_posts folder and prepend the file name with today’s date in
%Y-%m-%d format. it is required by Jeklly.
(defun blog-publish-post ()
"Move a draft post to the posts directory, and rename it so that it
contains the date."
(interactive)
(cond
((not (yt/jekyll-is-draft-p))
(message "This is not a draft post."))
((buffer-modified-p)
(message "Can't publish post; buffer has modifications."))
(t
;; TODO: use a utlity function to for `filename`, find publish file?
(let ((filename
(concat jekyll-source-posts-dir
(format-time-string "%Y-%m-%d-")
(file-name-nondirectory
(buffer-file-name (current-buffer)))))
(draft-file-exported (yt/jekyll-find-export))
(old-point (point)))
(delete-file draft-file-exported)
(rename-file (buffer-file-name (current-buffer))
filename)
(kill-buffer nil)
(find-file filename)
(set-window-point (selected-window) old-point)))))
I bound C-c j n
and C-c j P
for making a draft and publishing a draft.
Then convert all the org files in org/_posts into Markdown and save in the _posts/ folder. I used to use the
org-publish-project
function, it was great. Now i switched to exporting explicitly blog post while working
on it.
the yt/jekyll--export-to-md
functions does that, for example, org/2023-12-31-example.org to
blog/_posts/2023-12-31-example.md.
I prefer to Markdown format for its simplicity, and stopped using HTML format.
(defun yt/jekyll--export-to-md ()
"export draft/post to markdown"
(interactive)
(let* ((export-file (yt/jekyll-find-export)))
(message "Exporting to %s" export-file)
(org-export-to-file 'jekyll-md export-file nil nil nil t)))
(defun yt/jekyll--export-to-html ()
;; export current posts in org-mode to html.
(interactive)
(message "not implemented. use yt/jekyll--export-to-md (markdown) instead."))
(defun yt/jekyll-is-draft-p ()
"if the file is inside of the draft directory, it is a draft.
can also implmenet as (file-name-directory (buffer-file-name (current-buffer))) equals to jekyll-source-drafts-dir
"
(let ((draft-dir (file-truename jekyll-source-drafts-dir))
(filepath (file-truename (buffer-file-name))))
(string-prefix-p draft-dir filepath)))
(defun yt/jekyll-find-export ()
"find the full path to the exported file of the current post."
(let* ((src-file (file-name-nondirectory (buffer-file-name)))
(dest-file (file-name-with-extension src-file ".md")))
(if (yt/jekyll-is-draft-p)
(file-name-concat jekyll-site-drafts-dir dest-file)
(file-name-concat jekyll-site-posts-dir dest-file))))
yt/jekyll
is the command centre: it provides a entry point to all the functionalities I need while working
on my personal blog project.
it is binds to F5 in a .dir-locals.el.
(transient-define-prefix yt/jekyll ()
""
["Jekyll Blog"
[("n" "new draft" blog-draft-post)
("p" "publish post" blog-publish-post)
("dd" "Dired - drafts (org)" (lambda () (interactive) (find-file jekyll-source-drafts-dir)))
("dp" "Dired - posts (org)" (lambda () (interactive) (find-file jekyll-source-posts-dir)))
("dP" "Dired - published posts" (lambda () (interactive) (find-file jekyll-site-posts-dir)))
("m" "Export as Markdown" yt/jekyll--export-to-md)
("i" "Insert Image (Liquid Template)" yt/jekyll-insert-image)
;; ("eh" "Export as HTML" yt/jekyll--export-to-html)
;; ("u" "Update post title/date" yt/jekyll-update-post-name)
("s" "Jekyll Server" (lambda () (interactive) (yt/compile "*jekyll-sever*" "jekyll s --watch --drafts" jekyll-site-dir)))
("S" "Sync website" (lambda () (interactive) (yt/compile "*jekyll-sync*" "bash script.sh" "~/matrix/learning/mywebsite")))
]])
wrap src block into highlight block in Jekyll. it search for src block, and replace the header with {% highlight python %} for example. run this as pre-export hook.
The org-mode documentation provides a elegant solution to this problem: simplify define a new export backend that inherent from the markdown backend, but only change the src code block.
(defun my-jekyll-src-block (src-block contents info)
"Transcode a SRC-BLOCK element from Org to ASCII.
CONTENTS is nil. INFO is a plist used as a communication
channel."
(concat
(format "{%% highlight %s %%} \n%s\n{%% endhighlight %%}"
(org-element-property :language src-block)
(org-element-normalize-string
(org-export-format-code-default src-block info)))))
(require 'ox) ;; because blogging.el loadded first, before org-mode. need to load after org-mode.
(require 'ox-md) ;;
(org-export-define-derived-backend 'jekyll-html 'html
:translate-alist '((src-block . my-jekyll-src-block)))
(org-export-define-derived-backend 'jekyll-md 'md
:translate-alist '((src-block . my-jekyll-src-block)))
When publishing, the org-file is firstly exported to html file, and when Jekyll build the website, the html file will be saved in to some folder that depends on the YMAL. Then the relative path to image files are broken. To solve that, according to the Jeklyy web site, is to save all the image or downloade files in assets/ folder. Then those image files are referende by org-mode.
First, define a img link, that when exporting, the image a_img.png will be set to linked to /assets/a_img.png. when I click, it wil open the img file in Emacs.
(defun org-custom-link-img-follow (path)
(org-open-file-with-emacs
(format "../../assets/%s" path)))
(defun org-custom-link-img-export (path desc format)
(cond
((eq format 'html)
(format "<img src=\"/assets/%s\" alt=\"%s\"/>" path desc))))
(org-add-link-type "img" 'org-custom-link-img-follow 'org-custom-link-img-export)
i can also use liquid template for insetting images as follows:
{% include image.html src="/assets/temp.png" caption="Threadripper 3970x vs i5-13600k: Train LightGBM Models on CPU" %}
- src
- is the path to the image i want to include.
- caption
- is the caption on the top of the image.
- image.html
- is the liquid template in _includes/image.html
this image is centred with caption on the top. i cannot control the image size here. image preview is lacking in org buffer.
(defvar jekyll-insert-image-liquid-template
"
{%% include image.html
src=\"/assets/%s\"
caption=\"%s\"
width=450
%%}
"
"insert image using liquid template.")
(defun yt/jekyll-insert-image (src caption)
(interactive (list (read-file-name "images to include: " jekyll-site-assets-dir)
(read-string "Caption: ")))
(insert (format jekyll-insert-image-liquid-template (file-name-nondirectory src) caption))
)
(defun yt/jekyll-copy-to-assets-folder (file)
"TODO: copy a file to the assets folder. if file not provided,
interactively select file, start with org-download-image-dir.
jekyll-make-slug to normalise the file name. jekyll does not like
_ in the file name.
"
(interactive (list (read-file-name "file to copy: " org-download-image-dir)))
(let* ((ext (file-name-extension file ))
(base (file-name-base file))
(dest-base (jekyll-make-slug base))
(dest-file (expand-file-name (file-name-with-extension dest-base ext) jekyll-site-assets-dir)))
(copy-file file dest-file)
dest-file))
(defun yt/jekyll-copy-insert-image (file caption)
(interactive (list (read-file-name "file to copy: " org-download-image-dir)
(read-string "Caption: ")))
(yt/jekyll-insert-image (yt/jekyll-copy-to-assets-folder file) caption)
)
[2015-07-18 Sat 09:15]
magit
;; from https://lists.gnu.org/archive/html/emacs-orgmode/2009-08/msg00460.html
;; magit link in org-mode
(defun org-magit-store-link ()
"Store a link to a directory to open with magit."
(when (eq major-mode 'magit-mode)
(let* ((dir default-directory)
(link (org-make-link "magit:" dir))
(desc (abbreviate-file-name dir)))
(org-store-link-props :type "magit" :link link :description desc)
link)))
(defun org-magit-open (dir)
"Follow a magit link to DIR."
(magit-status dir))
(org-add-link-type "magit" 'org-magit-open nil)
(add-hook 'org-store-link-functions 'org-magit-store-link)
[2015-07-21 Tue 10:59]
the idea is to include a link to post in org foramt, i.e.
2022-01-01-awesome-blog-post.org,
when export to jekyll, the link becomes
blog.yitang.uk/2022/01/01-awesome-blog-post
this works if category is null. to make it fully working, it needs to translate the filename into url. it is doable, but not strightfoward. because the url depends on few attributes of the blog setup, and front matter.
(defun org-jekyll-post-link-follow (path)
(org-open-file-with-emacs path))
(defun org-jekyll-post-link-export (path desc format)
(cond
((eq format 'html)
(format "<a href=\"{%% post_url %s %%}\">%s</a>" path desc))))
(org-add-link-type "jekyll-post" 'org-jekyll-post-link-follow 'org-jekyll-post-link-export)
I found the default font size for headline is too big. instead of tweaking the Jekyll/HTML, I did the trick of changing the level of headline while exporting to markdown. so the top level headline becomes 2nd, or 3rd, and therefore the fontsize is smaller.
use the bind keywords to set the variable org-md-toplevel-hlevel to either 2 or 3. it only effects the exporting.
according to the documentation, I also need to set org-export-allow-bind-keywords to true.
(setq org-export-allow-bind-keywords t)
See this question I asked: https://emacs.stackexchange.com/questions/76544/org-mode-export-to-markdown-respect-the-level-of-headlines
A handy function to update the title and date in the filename and also front matter, see http://yitang.uk/2023/12/18/jekyll-in-emacs-update-blog-post-title-and-date/
(defun yt/jekyll-update-post-title-and-date ()
"it update the post filename with a new title and today's date.
it also update the font matter."
(interactive)
(let* ((title (read-string "new title: "))
(ext (file-name-extension (buffer-file-name))) ;; as of now, the ext is always .org.
;; the new filename is in the format of {date}-{new-title}.org
(filename (concat
(format-time-string "%Y-%m-%d-")
(file-name-with-extension (jekyll-make-slug title) ext)))
;; normalise the filename.
(filename (expand-file-name filename))
;; keep the current point which we will go back to after editing.
(old-point (point))
)
(rename-file (buffer-file-name) filename) ;; update the filename
(kill-buffer nil) ;; kill the current buffer, i.e. the old file.
(find-file filename) ;; open the new file.
(set-window-point (selected-window) old-point) ;; set the cursor to where i was in the old file.
;; udpate title field.
;; note jekyll-yaml-escape is called to ensure the title field is yaml friendly.
(yt/jekyll-update-frontmatter--title (jekyll-yaml-escape title))
)
)
(defun yt/jekyll-update-frontmatter--title (title)
"Update the title field in the front matter.
title case is used.
"
(let* ((old-point (point)))
;; ensure expand all the code/headers/drawers before editing.
(org-show-all)
;; go to the first occurence of 'title:'.
(goto-char (point-min))
(search-forward "title: ")
;; update the title field with the new title.
(beginning-of-line)
(kill-line)
(insert (format "title: %s" title))
;; ensure the title is in title case
(xah-title-case-region-or-line (+ (line-beginning-position) 7) (line-end-position))
;; save and reset cursor back to where it started.
(save-buffer)
(goto-char old-point)
))
so that the headline is used in URL instead of a randomly generated link, see my blog post: http://yitang.uk/2023/12/19/jekyll-in-emacs-align-headline-with-url/\[Jekyll in Emacs - Align URL with Headline]]
http://yitang.uk/2023/12/13/trx4-3970x/#org59a1ed6
vs.
http://yitang.uk/2023/12/13/trx4-3970x/#The%20Problem
alternatively, use NAME keyword, based on the documentation of org-html-prefer-user-labels, custom_id is used whenever it exists.
below I have a function to create/update the custom_id property whose value is literally the headline.
I tweaked the function API a bit so it is used as export hook just as an experiment. It is only ran when exporting using jekyll-md. it works on the exported buffer so it leaves the original org file unchanged.
(defun yt/jekyll--create-or-update-custom_id-field ()
"so that the CUSTOM_ID property is the same as the headline and
the URL reflects the headline.
by default, the URL to a section will be a random number."
(org-entry-put nil "CUSTOM_ID" (org-entry-get nil "ITEM"))
)
(defun yt/jekyll--create-or-update-custom_id-field-buffer (backend)
(when (eq backend 'jekyll-md)
(org-map-entries 'yt/jekyll--create-or-update-custom_id-field)
))
(add-hook 'org-export-before-processing-functions 'yt/jekyll--create-or-update-custom_id-field-buffer)
http://tex.stackexchange.com/questions/50827/a-simpletons-guide-to-tex-workflow-with-emacs
http://tex.stackexchange.com/questions/29813/setup-synctex-with-emacs
http://www.stefanom.org/setting-up-a-nice-auctex-environment-on-mac-os-x/
;; AucTeX
(setq TeX-auto-save t)
(setq TeX-parse-self t)
(setq-default TeX-master nil)
(add-hook 'LaTeX-mode-hook 'visual-line-mode)
(add-hook 'LaTeX-mode-hook 'flyspell-mode)
(add-hook 'LaTeX-mode-hook 'LaTeX-math-mode)
(add-hook 'LaTeX-mode-hook 'turn-on-reftex)
(setq reftex-plug-into-AUCTeX t)
(setq TeX-PDF-mode t)
;; make latexmk available via C-c C-c
(add-hook 'LaTeX-mode-hook (lambda ()
(push
'("latexmk" "latexmk -pdf %s" TeX-run-TeX nil t
:help "Run latexmk on file")
TeX-command-list)))
(add-hook 'TeX-mode-hook '(lambda () (setq TeX-command-default "latexmk")))
(setq TeX-view-program-selection '((output-pdf "evince")))
(if (string= system-type "darwin")
(setq TeX-view-program-selection '((output-dvi "open")
(output-pdf "open")
(output-html "open"))))
(add-hook 'LaTeX-mode-hook #'outline-minor-mode)
(use-package company-auctex)
(company-auctex-init)
;;; Brent.Longborough's .emacs
;; (global-visual-line-mode 1); Proper line wrapping
;; (global-hl-line-mode 1); Highlight current row
;; (show-paren-mode 1); Matches parentheses and such in every mode
;; (set-fringe-mode '(0 . 0)); Disable fringe because I use visual-line-mode
;; (set-face-background hl-line-face "#f2f1f0"); Same color as greyness in gtk
;; (setq inhibit-splash-screen t); Disable splash screen
;; (setq visible-bell t); Flashes on error
;; (setq calendar-week-start-day 1); Calender should start on Monday
;; (add-to-list 'default-frame-alist '(height . 59)); Default frame height.
;;; AUCTeX
;; Customary Customization, p. 1 and 16 in the manual, and http://www.emacswiki.org/emacs/AUCTeX#toc2
(setq TeX-parse-self t); Enable parse on load.
(setq TeX-auto-save t); Enable parse on save.
(setq-default TeX-master nil)
(setq TeX-PDF-mode t); PDF mode (rather than DVI-mode)
(add-hook 'TeX-mode-hook 'flyspell-mode); Enable Flyspell mode for TeX modes such as AUCTeX. Highlights all misspelled words.
(add-hook 'TeX-mode-hook
(lambda () (TeX-fold-mode 1))); Automatically activate TeX-fold-mode.
(setq LaTeX-babel-hyphen nil); Disable language-specific hyphen insertion.
;; " expands into csquotes macros (for this to work babel must be loaded after csquotes).
(setq LaTeX-csquotes-close-quote "}"
LaTeX-csquotes-open-quote "\\enquote{")
;; LaTeX-math-mode http://www.gnu.org/s/auctex/manual/auctex/Mathematics.html
(add-hook 'TeX-mode-hook 'LaTeX-math-mode)
;;; RefTeX
;; Turn on RefTeX for AUCTeX http://www.gnu.org/s/auctex/manual/reftex/reftex_5.html
(add-hook 'TeX-mode-hook 'turn-on-reftex)
(eval-after-load 'reftex-vars; Is this construct really needed?
'(progn
(setq reftex-cite-prompt-optional-args t); Prompt for empty optional arguments in cite macros.
;; Make RefTeX interact with AUCTeX, http://www.gnu.org/s/auctex/manual/reftex/AUCTeX_002dRefTeX-Interface.html
(setq reftex-plug-into-AUCTeX t)
;; So that RefTeX also recognizes \addbibresource. Note that you
;; can't use $HOME in path for \addbibresource but that "~"
;; works.
(setq reftex-bibliography-commands '("bibliography" "nobibliography" "addbibresource"))
; (setq reftex-default-bibliography '("UNCOMMENT LINE AND INSERT PATH TO YOUR BIBLIOGRAPHY HERE")); So that RefTeX in Org-mode knows bibliography
(setcdr (assoc 'caption reftex-default-context-regexps) "\\\\\\(rot\\|sub\\)?caption\\*?[[{]"); Recognize \subcaptions, e.g. reftex-citation
(setq reftex-cite-format; Get ReTeX with biblatex, see http://tex.stackexchange.com/questions/31966/setting-up-reftex-with-biblatex-citation-commands/31992#31992
'((?t . "\\textcite[]{%l}")
(?a . "\\autocite[]{%l}")
(?c . "\\cite[]{%l}")
(?s . "\\smartcite[]{%l}")
(?f . "\\footcite[]{%l}")
(?n . "\\nocite{%l}")
(?b . "\\blockcquote[]{%l}{}")))))
;; Fontification (remove unnecessary entries as you notice them) http://lists.gnu.org/archive/html/emacs-orgmode/2009-05/msg00236.html http://www.gnu.org/software/auctex/manual/auctex/Fontification-of-macros.html
(setq font-latex-match-reference-keywords
'(
;; biblatex
("printbibliography" "[{")
("addbibresource" "[{")
;; Standard commands
;; ("cite" "[{")
("Cite" "[{")
("parencite" "[{")
("Parencite" "[{")
("footcite" "[{")
("footcitetext" "[{")
;; ;; Style-specific commands
("textcite" "[{")
("Textcite" "[{")
("smartcite" "[{")
("Smartcite" "[{")
("cite*" "[{")
("parencite*" "[{")
("supercite" "[{")
; Qualified citation lists
("cites" "[{")
("Cites" "[{")
("parencites" "[{")
("Parencites" "[{")
("footcites" "[{")
("footcitetexts" "[{")
("smartcites" "[{")
("Smartcites" "[{")
("textcites" "[{")
("Textcites" "[{")
("supercites" "[{")
;; Style-independent commands
("autocite" "[{")
("Autocite" "[{")
("autocite*" "[{")
("Autocite*" "[{")
("autocites" "[{")
("Autocites" "[{")
;; Text commands
("citeauthor" "[{")
("Citeauthor" "[{")
("citetitle" "[{")
("citetitle*" "[{")
("citeyear" "[{")
("citedate" "[{")
("citeurl" "[{")
;; Special commands
("fullcite" "[{")))
(setq font-latex-match-textual-keywords
'(
;; biblatex brackets
("parentext" "{")
("brackettext" "{")
("hybridblockquote" "[{")
;; Auxiliary Commands
("textelp" "{")
("textelp*" "{")
("textins" "{")
("textins*" "{")
;; supcaption
("subcaption" "[{")))
(setq font-latex-match-variable-keywords
'(
;; amsmath
("numberwithin" "{")
;; enumitem
("setlist" "[{")
("setlist*" "[{")
("newlist" "{")
("renewlist" "{")
("setlistdepth" "{")
("restartlist" "{")))
It is a good practise to group all the file management related commands together using hydra.
(use-package hydra)
(defhydra hydra-file-management (:color red
:hint nil)
"
_o_pen file
_O_pen file as Sudo user
copy file _P_ath to kill ring
copy file _p_ath relative to project dir to kill ring
_r_ename buffer-visiting file
_d_elete buffer-visiting file
open with _e_xternal application
_g_it sync"
("o" find-file)
("O" yt/sudo-find-file)
("P" yt/copy-full-path-to-kill-ring)
("p" yt/copy-rel-path-to-kill-ring)
("r" yt/rename-current-buffer-file)
("c" yt/copy-file-to)
("d" yt/delete-this-buffer-and-file)
("e" prelude-open-with)
("g" yt/git-up))
(global-set-key [f3] 'hydra-file-management/body)
(defhydra yt-hydra/help (:color blue :hint nil)
"
_f_unction: Documentation for a function
_v_ariable: Documentation for a variable
_i_nfo: info mode
_d_ictionary: search meaning of a word
_V_ocabulary: add to or visit vocablary
"
("f" describe-function)
("v" describe-variable)
("d" osx-dictionary-search-input)
;; ("s" get-synonyms)
("i" helm-info)
;; ("G" helm-google-suggest)
("s" synosaurus-lookup)
;; ("d" voca-builder/search-popup)
("V" yt/add-vocabulary)
)
(global-set-key (kbd "<f1>") 'yt-hydra/help/body)
;;; package --- Query thesaurus.com for synonyms of a given word.
;;; Copyright (C) 2021 by Anselm Coogan
;;; URL: https://github.com/AnselmC/thesaurus
;;; Version: 0.1
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;;; Uses the Elisp request library (https://github.com/tkf/emacs-request) and the thesaurus.com API to fetch synonyms
;;; Code:
(require 'cl-lib)
(require 'request)
(defun parse-synonyms-in-response (payload)
"Parse JSON PAYLOAD to extract synonyms from response."
(let* ((data (assoc-default 'data payload))
(definition-data (if data
(assoc-default 'definitionData data)
'()))
(definitions-list (if definition-data
(assoc-default 'definitions definition-data)
'()))
(definitions (if definitions-list
(aref definitions-list 0)
'()))
(synonyms (if definitions
(cl-map 'vector
#'(lambda (e) (assoc-default 'term e))
(assoc-default 'synonyms definitions))
(vector))))
synonyms))
(defun ask-thesaurus-for-synonyms (word)
"Ask thesaurus.com for synonyms for WORD and return vector of synonyms (possibly empty)."
(let* ((thesaurus-base-url "https://tuna.thesaurus.com/pageData/")
(request-string (concat thesaurus-base-url word))
(response (request-response-data (request request-string
:parser 'json-read
:sync t))))
(if response
(parse-synonyms-in-response response)
(vector))))
(defun get-synonyms()
"Interactively get synonyms for symbol at active region or point."
(interactive)
(let* ((bounds (if (use-region-p)
(cons (region-beginning) (region-end))
(bounds-of-thing-at-point 'symbol)))
(word (buffer-substring-no-properties (car bounds) (cdr bounds)))
(replace-text (completing-read
(format "Select synonym for %S: " word)
(append (ask-thesaurus-for-synonyms word) '()))))
(when bounds
(delete-region (car bounds) (cdr bounds))
(insert replace-text))))
(provide 'thesaurus)
;;; thesaurus.el ends here
[2021-06-07 Mon 12:40]
use hydra to define a function that use most frequently
;; https://github.com/abo-abo/hydra/wiki/Org-clock
(defhydra hydra-org-clock (:color blue :hint nil)
"
Clock In/out^ ^Edit^ ^Summary Doc(_?_)
---------------------------------------------------
_i_n _e_dit
_h_istory _c_ontinue _q_uit _d_isplay
_g_oto _o_ut ^ ^ _r_eport
"
("i" org-clock-in)
("o" org-clock-out)
("c" org-clock-in-last)
("e" org-clock-modify-effort-estimate)
("q" org-clock-cancel)
("g" org-clock-goto)
("d" org-clock-display)
("r" org-clock-report)
;; ("j" org-clock-jump-to-current-clock)
("h" yt/org-clock-in-select)
("?" (org-info "Clocking commands")))
(global-set-key (kbd "<f11>") 'hydra-org-clock/body)
(defun yt/org-clock-in-select ()
(interactive)
(setq current-prefix-arg '(4)) ;; C-u,
(call-interactively 'org-clock-in))
(use-package pyvenv)
(add-hook 'python-mode-hook 'flyspell-prog-mode)
(add-hook 'python-mode-hook 'elpy-mode)
(setq python-fill-docstring-style 'django)
(use-package elpy
:ensure t
:init)
(elpy-enable)
;; ;; (elpy-use-ipython "ipython3")
;; (setq elpy-rpc-python-command "python3")
;; (global-set-key (kbd "M-*") 'pop-tag-mark)
;; ;; (setq elpy-test-discover-runner-command '("python3" "-m" "unittest"))
;; (setq elpy-test-pytest-runner-command '("py.test" "--maxfail=100" "-s"))
;; (setq elpy-rpc-backend "jedi")
;; make elpy more like ESS
(define-key elpy-mode-map (kbd "<C-return>") 'elpy-shell-send-statement-and-step)
(define-key elpy-mode-map (kbd "<C-c C-f>") 'python-shell-send-defun)
(define-key elpy-mode-map (kbd "<C-c C-b>") 'elpy-shell-send-region-or-buffer)
;; for new elpy version
(setq elpy-shell-starting-directory 'project-root) ;; set to project directory.
(setq elpy-rpc-virtualenv-path 'current) ;; rpc is in the python dev env
Use Jupyter for python interactive shell.
(setq python-shell-interpreter "jupyter"
python-shell-interpreter-args "console --simple-prompt"
python-shell-prompt-detect-failure-warning nil)
(require 'python)
(add-to-list 'python-shell-completion-native-disabled-interpreters
"jupyter")
(setq python-shell-interpreter "ipython"
python-shell-interpreter-args "-i --simple-prompt")
(add-to-list 'python-shell-completion-native-disabled-interpreters
"ipython")
TODO: replace this by using native elpy function.
this allows me to run multiple python process and switch between them.
(setq elpy-dedicated-shells nil) ; Ensure no conflict with dedicated shells
(defvar elpy-shell-python-shell-names '("Python")
"List of existing python shell names.")
;; (define-key elpy-mode-map (kbd "C-c C-s") 'elpy-shell-set-local-shell)
[2020-08-22 Sat 19:03]
replace elpy by LSP mode for python dev..
;; this requires pip install -U jedi-language-server
(use-package lsp-mode
:config
(add-hook 'python-mode-hook 'lsp))
;; (use-package company-lsp)
(use-package lsp-ui)
;; (use-package lsp-jedi
;; :ensure t
;; :config
;; (with-eval-after-load "lsp-mode"
;; (add-to-list 'lsp-disabled-clients 'pyls)
;; (add-to-list 'lsp-enabled-clients 'jedi)))
(use-package lsp-pyright
:ensure t
:hook (python-mode . (lambda ()
(require 'lsp-pyright)
(lsp)))) ; or lsp-deferred
[2016-06-03 Fri 15:33]
(use-package sphinx-doc
:ensure t
:hook (python-mode . (lambda ()
(require 'sphinx-doc)
(sphinx-doc-mode t))))
(cl-defstruct sphinx-doc-doc
(summary "FIXME: briefly describe function") ; summary line that fits on the first line
before-fields ; list of comments before fields
after-fields ; list of comments after fields
fields) ; list of field objects
(use-package jupyter)
quickly filter out non-work tasks in org-agenda.
(defun yt/filter-life-agenda (tag)
(concat "-" "life"))
(defun yt/filter-office-agenda (tag)
(concat "-" "@office"))
(if (eq system-type 'darwin)
(setq org-agenda-auto-exclude-function 'yt/filter-office-agenda)
(setq org-agenda-auto-exclude-function 'yt/filter-life-agenda))
open this gnome-terminal here
(defun yt/open-terminal ()
(interactive)
(shell-command (concat "gnome-terminal "
"--working-directory="
(file-truename default-directory)
)))
;; (global-set-key (kbd "<f5>") 'yt/open-terminal)
use consult-line
to replace default isearch
(global-set-key "\C-s" 'consult-line)
use snakemake-mode for smake file.
(use-package snakemake-mode
:ensure t
:mode ("\\.sfile\\'" "\\.Snakemake\\'"))
(defun yt/sh-chunk-args ()
(interactive)
(replace-string " -" " \\\n -")
)
insert git sha1 value into current point.
(defun yt/insert-git-hash-value ()
(interactive)
(insert (shell-command-to-string (concat "git rev-parse HEAD"))))
(global-set-key (kbd "<f9> s") 'yt/insert-git-hash-value)
(use-package which-key)
(which-key-mode)
copied following configuration from https://github.com/Alexander-Miller/treemacs with no additional editing.
(use-package treemacs
:ensure t
:defer t
:init
(with-eval-after-load 'winum
(define-key winum-keymap (kbd "M-0") #'treemacs-select-window))
:config
(progn
(setq treemacs-collapse-dirs (if treemacs-python-executable 3 0)
treemacs-deferred-git-apply-delay 0.5
treemacs-directory-name-transformer #'identity
treemacs-display-in-side-window t
treemacs-eldoc-display 'simple
treemacs-file-event-delay 5000
treemacs-file-extension-regex treemacs-last-period-regex-value
treemacs-file-follow-delay 0.2
treemacs-file-name-transformer #'identity
treemacs-follow-after-init t
treemacs-expand-after-init t
treemacs-find-workspace-method 'find-for-file-or-pick-first
treemacs-git-command-pipe ""
treemacs-goto-tag-strategy 'refetch-index
treemacs-indentation 2
treemacs-indentation-string " "
treemacs-is-never-other-window nil
treemacs-max-git-entries 5000
treemacs-missing-project-action 'ask
treemacs-move-forward-on-expand nil
treemacs-no-png-images nil
treemacs-no-delete-other-windows t
treemacs-project-follow-cleanup nil
treemacs-persist-file (expand-file-name ".cache/treemacs-persist" "~/matrix/tools/.emacs.d/")
treemacs-position 'left
treemacs-read-string-input 'from-child-frame
treemacs-recenter-distance 0.1
treemacs-recenter-after-file-follow nil
treemacs-recenter-after-tag-follow nil
treemacs-recenter-after-project-jump 'always
treemacs-recenter-after-project-expand 'on-distance
treemacs-litter-directories '("/node_modules" "/.venv" "/.cask")
treemacs-show-cursor nil
treemacs-show-hidden-files t
treemacs-silent-filewatch nil
treemacs-silent-refresh nil
treemacs-sorting 'alphabetic-asc
treemacs-select-when-already-in-treemacs 'move-back
treemacs-space-between-root-nodes t
treemacs-tag-follow-cleanup t
treemacs-tag-follow-delay 1.5
treemacs-text-scale nil
treemacs-user-mode-line-format nil
treemacs-user-header-line-format nil
treemacs-wide-toggle-width 70
treemacs-width 35
treemacs-width-increment 1
treemacs-width-is-initially-locked t
treemacs-workspace-switch-cleanup nil)
;; The default width and height of the icons is 22 pixels. If you are
;; using a Hi-DPI display, uncomment this to double the icon size.
;;(treemacs-resize-icons 44)
(treemacs-follow-mode t)
(treemacs-filewatch-mode t)
(treemacs-fringe-indicator-mode 'always)
(pcase (cons (not (null (executable-find "git")))
(not (null treemacs-python-executable)))
(`(t . t)
(treemacs-git-mode 'deferred))
(`(t . _)
(treemacs-git-mode 'simple)))
(treemacs-hide-gitignored-files-mode nil))
;; :bind
;; (:map global-map
;; ("M-0" . treemacs-select-window)
;; ("C-x t 1" . treemacs-delete-other-windows)
;; ("C-x t t" . treemacs)
;; ("C-x t d" . treemacs-select-directory)
;; ("C-x t B" . treemacs-bookmark)
;; ("C-x t C-t" . treemacs-find-file)
;; ("C-x t M-t" . treemacs-find-tag))
)
(use-package treemacs-evil
:after (treemacs evil)
:ensure t)
(use-package treemacs-projectile
:after (treemacs projectile)
:ensure t)
(use-package treemacs-icons-dired
:hook (dired-mode . treemacs-icons-dired-enable-once)
:ensure t)
(use-package treemacs-magit
:after (treemacs magit)
:ensure t)
;; (use-package treemacs-persp ;;treemacs-perspective if you use perspective.el vs. persp-mode
;; :after (treemacs persp-mode) ;;or perspective vs. persp-mode
;; :ensure t
;; :config (treemacs-set-scope-type 'Perspectives))
;; (use-package treemacs-tab-bar ;;treemacs-tab-bar if you use tab-bar-mode
;; :after (treemacs)
;; :ensure t
;; :config (treemacs-set-scope-type 'Tabs))
https://depp.brause.cc/nov.el/
(add-to-list 'auto-mode-alist '("\\.epub\\'" . nov-mode))
(setq nov-text-width t)
(setq visual-fill-column-center-text t)
(add-hook 'nov-mode-hook 'visual-line-mode) ;; word-wrap and also use visual-line, not logical (actual) line.
(add-hook 'nov-mode-hook 'visual-fill-column-mode) ;; center the text, looks good. have to call it again when change window size.
(add-hook 'nov-mode-hook '(lambda () (blink-cursor-mode 0))) ;; blinking cursor is distracting.
(defun yt/read-mode ()
(visual-line-mode)
(visual-fill-column-mode))
(setq visual-fill-column-width 120)
(setq line-number-display-limit-width 2000000) ;; https://emacs.stackexchange.com/questions/3824/what-piece-of-code-in-emacs-makes-line-number-mode-print-as-line-number-i
(use-package org-download)
(add-hook 'dired-mode-hook 'org-download-enable)
(setq-default org-download-image-dir "~/Pictures/org-download")
(setq-default org-download-heading-lvl nil) ;; flat file systme, otherwise, would be confusing.
(if (eq system-type 'darwin)
(setq org-download-screenshot-method "screencapture -i %s"))
;; (setq emacsql-sqlite-executable "/usr/bin/sqlite3")
;; (use-package emacsql-sqlite-builtin)
;; ;; (setq org-roam-database-connector 'sqlite3)
;; (setq org-roam-database-connector 'sqlite-builtin)
;; (setq org-roam-database-connector 'sqlite)
(use-package org-roam
:ensure t
:init
(setq org-roam-v2-ack t)
:custom
(org-roam-completion-everywhere t)
(org-roam-dailies-capture-templates
'(("d" "default" entry "* %<%H:%M>: %?"
:if-new (file+head "%<%Y-%m-%d>.org" "#+title: %<%Y-%m-%d>\n"))))
(org-roam-dailies-directory "daily")
;; ; change the timestmap aslightly..
;; (org-roam-capture-templates
;; '(("d" "default" plain "%?"
;; :target (file+head "%<%Y%m%d_%H%M%S>-${slug}.org"
;; "#+title: ${title}\n")
;; :unnarrowed t)))
:bind (("C-c n l" . org-roam-buffer-toggle)
("C-c n f" . org-roam-node-find)
("C-c n i" . org-roam-node-insert)
:map org-mode-map
("C-M-i" . completion-at-point)
:map org-roam-dailies-map
("Y" . org-roam-dailies-capture-yesterday)
("T" . org-roam-dailies-capture-tomorrow))
:bind-keymap
("C-c n d" . org-roam-dailies-map)
:config
(require 'org-roam-dailies) ;; Ensure the keymap is available
(org-roam-db-autosync-mode))
(defun yt/dailies ()
"global function for creating daries"
(interactive)
(let ((org-roam-directory "~/git/org/diary"))
(org-roam-dailies-capture-today)
)
)
(use-package epa-file
:ensure nil
:config
(setq epa-file-encrypt-to '("[email protected]"))
:custom
(epa-file-select-keys nil) ;; seems there's a bug in gpg. it always asks for which key.
)
(setq epa-file-encrypt-to "[email protected]")
(setq epg-gpg-program "gpg2")
(require 'epa-file)
(epa-file-enable) ;; decrypt the buffer, may or may not ask for passphase.
;; ;; to open gpg file in binary mode, i.e. no decryptions, use
;; (epa-file-disable)
(setq password-cache-expiry (* 15 60))
;; loopback means to re-direct the dialog to the caller, here, it
;; means passpharse via Emacs's minibuffer instead of external
;; program.
(setq epa-pinentry-mode 'loopback)
by default, ask for setting up local dir variables. this is useful in debugging.
(setq enable-local-variables t)
called rsync in dired. useful in copy files between servers.
(use-package dired-rsync
:demand t
:after dired
:bind (:map dired-mode-map ("r" . dired-rsync))
:config (add-to-list 'mode-line-misc-info '(:eval dired-rsync-modeline-status 'append)))
(use-package yaml-mode
:ensure t
:mode ("\\.yaml\\'" "\\.yml\\'")
:bind (("C-m" . newline-and-indent))
)
if i do a lot of yaml file editing, use yaml-pro.
(use-package yaml-pro
:ensure t)
(setq org-export-with-broken-links t) ;; broken links are fine in exporting.
;; (setq org-latex-prefer-user-labels t) ;; fix labels, otherwise, randomly generated, not git friendly.
;; somehow relative path doesn't work in osx when export org to other format. so use abslute path.
(setq org-download-abbreviate-filename-function #'expand-file-name)
(setq org-link-file-path-type 'absolute)
(defun yt/execute-src-org-file (filename)
"run the src babel block in a given file"
(interactive)
(with-current-buffer (get-buffer-create (concat "*buffer:" filename))
(erase-buffer)
(insert-file-contents filename)
(let ((default-directory (file-name-directory filename)))
(org-babel-execute-buffer))
)
)
for the visiting buffer, create a new compilation buffer if not exists, otherwise, switch to.
(defun yt/bind-to-compliation ()
"bind current file-visiting buffer to a dedicated compilation buffer"
(interactive)
(let* ((filename (buffer-file-name))
(default-directory (file-name-directory filename))
(output-buffer-name (concat "*compilation*:" filename)))
(compile "ls -l")
(when (get-buffer output-buffer-name)
(kill-buffer output-buffer-name))
(with-current-buffer "*compilation*"
(rename-buffer output-buffer-name)))
)
(setq compilation-scroll-output 'first-error)
(defun yt/kill-buffer (name)
"if buffer exists, kill, otherwise, do nothing"
(when (get-buffer name)
(kill-buffer name)
))
(defun yt/compile (output-id cmd &optional working-directory)
(let ((default-directory (or working-directory default-directory))
(buffer-name (concat "*compilation*" output-id)))
(progn
(compile cmd)
(when (get-buffer buffer-name)
(kill-buffer buffer-name))
(with-current-buffer "*compilation*"
(rename-buffer buffer-name)))))
fix colour in compilation buffer - otherwise, there’s some strange characters in the compilation buffer
;;;; colorize output in compile buffer
(require 'ansi-color)
(defun colorize-compilation-buffer ()
(ansi-color-apply-on-region compilation-filter-start (point-max)))
(add-hook 'compilation-filter-hook 'colorize-compilation-buffer)
(global-set-key (kbd "M-i") 'ibuffer)
(setq ibuffer-saved-filter-groups
'(("home"
("shell" (mode . shell-mode))
;; ("emacs-config" (or (filename . ".emacs.d")
;; (filename . "emacs-config")))
;; ("martinowen.net" (filename . "martinowen.net"))
("compilation" (mode . compilation-mode))
("dired" (mode . dired-mode))
("planner" (or
(name . "^\\*Calendar\\*$")
(name . "^\\*Org Agenda\\*")))
("python" (mode . python-mode))
("Org" (or (mode . org-mode)
(filename . "OrgMode")))
;; ("code" (filename . "code"))
;; ("Web Dev" (or (mode . html-mode)
;; (mode . css-mode)))
;; ("Subversion" (name . "\*svn"))
("Magit" (name . "\\*magit"))
;; ("Magit2" (name . "magit"))
;; ("ERC" (mode . erc-mode))
;; ("Help" (or (name . "\*Help\*")
;; (name . "\*Apropos\*")
;; (name . "\*info\*")))
)))
(setq ibuffer-expert t)
(setq ibuffer-show-empty-filter-groups nil)
(add-hook 'ibuffer-mode-hook
'(lambda ()
(ibuffer-auto-mode 1)
(ibuffer-switch-to-saved-filter-groups "home")))
(keymap-set ibuffer-mode-map "M-o" nil)
;; nearly all of this is the default layout
(setq ibuffer-formats
'((mark modified read-only " "
(name 30 30 :left :elide) ; change: 30s were originally 18s
" "
(size 9 -1 :right)
" "
(mode 16 16 :left :elide)
" " filename-and-process)
(mark " "
(name 16 -1)
" " filename)))
flush bookmarks immediately.
(setq bookmark-save-flag 1) ; save bookmark file everytime.
highlight TODO, FIXME or other in programming mode.
(add-hook 'prog-mode-hook
(lambda ()
(font-lock-add-keywords nil
'(("\\<\\(YT\\|FIXME\\|TODO\\|BUG\\):" 1 font-lock-warning-face t)))))
we usually have long scripts, and in Subimetext, one cold folder and
unfolder a function. in Emacs, this feature could be extended to
furture, by define folder-characters. at this statge, I tented to used
the deafault, I.e. folder functions only. in the folliwng setting, I
could press F3
to folder/unfolder a function, C-F3
or S-F3
to
folder/unfolder all functions.
One potentially solution is to use outshine
package, to show/hide
the whole section.
;; (add-hook 'prog-mode-hook 'hs-minor-mode)
;; (defalias 'fold-toggle 'hs-toggle-hiding)
;; (global-set-key (kbd "<f4>") 'hs-toggle-hiding)
;; (global-set-key (kbd "S-<f4>") 'hs-show-all) ;; S->show
;; (global-set-key (kbd "C-<f4>") 'hs-hide-all)
;; ;; hs-hide-block C-c @ C-h
;; ;; hs-show-block C-c @ C-s
;; ;; hs-hide-all C-c @ C-M-h
;; ;; hs-show-all C-c @ C-M-s
;; ;; hs-hide-level C-c @ C-l
;; ;; hs-toggle-hiding
;; ;; hs-mouse-toggle-hiding [(shift mouse-2)]
;; ;; hs-hide-initial-comment-block
(global-set-key (kbd "C-d") 'comment-region) ;; overwite delete-char
(global-set-key (kbd "C-S-d") 'uncomment-region)
(defhydra hydra-fold (:pre (hs-minor-mode 1))
"fold"
("t" hs-toggle-hiding "toggle")
("s" hs-show-all "hide-all")
("h" hs-hide-all "show-all")
("q" nil "quit"))
(global-set-key (kbd "<f4>") 'hydra-fold/body)
use subword-mode then ThisPhase has two word, and I can use C-DEL
it will remove the Phase and left This. Very useful in CamerCase.
(subword-mode 1)
Highlights the text/code after 80 characters, a visual guide to avoid writing long code.
(use-package whitespace
:ensure t
:config
(setq whitespace-line-column 120)
(setq whitespace-style '(face lines-tail))
:hook (prog-mode-hook . whitespace-mode))
Rainbow-delimiters. constantly have problem with package, and tired of fixing it, so I turned it off at this stage.
(use-package rainbow-delimiters
:ensure t
:hook (prog-mode-hook . rainbow-delimiters-mode))
(show-paren-mode t) ;; highlight matched parentheses
use f8 to remove the R process buffer.
(defun yt/prog-previous-output-region ()
"return start/end points of previous output region"
(save-excursion
(beginning-of-line)
(setq sp (point))
(comint-previous-prompt 1)
(next-line)
(beginning-of-line)
(setq ep (point))
(cons sp ep)))
(defun yt/prog-kill-output-backwards ()
(interactive)
(save-excursion
(let ((reg (yt/prog-previous-output-region)))
(delete-region (car reg) (cdr reg))
(goto-char (cdr reg))
(insert "*** output flushed ***\n"))))
;; (global-set-key (kbd "<f8>") 'yt/prog-kill-output-backwards)
(use-package vertico
:bind (("C-x M-r" . vertico-repeat)
:map vertico-map
("C-l" . vertico-directory-delete-word)
("M-g" . vertico-multiform-grid)
("M-q" . vertico-multiform-flat))
:init (vertico-mode 1)
:config (progn
(add-hook 'minibuffer-setup-hook #'vertico-repeat-save)
(vertico-mouse-mode 1)
(vertico-multiform-mode 1)
(setq vertico-multiform-categories '((consult-grep buffer))
vertico-multiform-commands '((tmm-menubar flat)
(tmm-shortcut flat)))))
(use-package orderless
:after vertico
:config (progn
(setq orderless-matching-styles '(orderless-regexp
orderless-initialism
orderless-prefixes)
orderless-component-separator #'orderless-escapable-split-on-space)
;; Use the built-in "partial-completion" style to complete
;; file inputs such as "/e/ni/co.nix" into
;; "/etc/nixos/configuration.nix". The "basic" style is
;; needed to support the hostname completion in the TRAMP
;; inputs such as "/sshx:HOSTNAME".
(setq completion-category-defaults nil
completion-category-overrides '((file (styles basic partial-completion))))
(setq completion-styles '(orderless))
(defun vifon/orderless-without-if-bang (pattern index total)
(when (string-prefix-p "!" pattern)
`(orderless-without-literal . ,(substring pattern 1))))
(defun vifon/orderless-literal-if-equal (pattern index total)
(when (string-suffix-p "=" pattern)
`(orderless-literal . ,(substring pattern 0 -1))))
(setq orderless-style-dispatchers '(vifon/orderless-without-if-bang
vifon/orderless-literal-if-equal))))
(use-package embark
:bind (("C-c o" . embark-act)
("C-." . embark-act)
:map minibuffer-local-map
("M-o" . embark-act)
:map embark-command-map
;; Unbind the dangerous `global-set-key' and `local-set-key'
;; actions. It's far too easy to accidentally bind over some
;; `self-insert-command' binding or even over
;; \\[keyboard-quit].
("g" . nil)
("l" . nil))
:config (progn
(setq embark-mixed-indicator-delay 2)
;; Make the eval action editable. Evaluating code
;; in-place is simple enough without Embark, if I invoke
;; it with Embark, I almost definitely want to edit the
;; expression beforehand. And even if not, I can
;; just confirm.
(cl-pushnew 'embark--allow-edit
(alist-get 'pp-eval-expression embark-target-injection-hooks))
;; Reload the project list after using
;; C-u `embark-act' with `project-forget-project'.
(cl-pushnew 'embark--restart
(alist-get 'project-forget-project embark-post-action-hooks))
(defun embark-act-with-eval (expression)
"Evaluate EXPRESSION and call `embark-act' on the result."
(interactive "sExpression: ")
(with-temp-buffer
(let ((expr-value (eval (read expression))))
(insert (if (stringp expr-value)
expr-value
(format "%S" expr-value))))
(embark-act)))
(dolist (keymap (list embark-variable-map embark-expression-map))
(define-key keymap (kbd "v") #'embark-act-with-eval))
;; Source: https://github.com/oantolin/embark/wiki/Additional-Actions#attaching-file-to-an-email-message
(autoload 'gnus-dired-attach "gnus-dired" nil t)
(defun embark-attach-file (file)
"Attach FILE to an email message."
(interactive "fAttach: ")
(gnus-dired-attach (list file)))
(bind-key "a" #'embark-attach-file embark-file-map)))
(use-package embark-consult
:after (embark consult))
(use-package marginalia
:after vertico
:demand t ; :demand applies to :bind but not
; :after. We want to eagerly load
; marginalia once vertico is loaded.
:bind (:map minibuffer-local-map
("C-o" . marginalia-cycle))
:config (marginalia-mode 1))
(use-package corfu
:init (global-corfu-mode 1))
;;; https://with-emacs.com/posts/tutorials/customize-completion-at-point/
(autoload 'ffap-file-at-point "ffap")
(add-hook 'completion-at-point-functions
(defun complete-path-at-point+ ()
(let ((fn (ffap-file-at-point))
(fap (thing-at-point 'filename)))
(when (and (or fn (equal "/" fap))
(save-excursion
(search-backward fap (line-beginning-position) t)))
(list (match-beginning 0)
(match-end 0)
#'completion-file-name-table :exclusive 'no))))
'append)
;;; Add prompt indicator to `completing-read-multiple'.
;;; We display [CRM<separator>], e.g., [CRM,] if the separator is a comma.
;;;
;;; Taken from the Vertico docs.
(defun crm-indicator (args)
(cons (format "[CRM%s] %s"
(replace-regexp-in-string
"\\`\\[.*?]\\*\\|\\[.*?]\\*\\'" ""
crm-separator)
(car args))
(cdr args)))
(advice-add #'completing-read-multiple :filter-args #'crm-indicator)
(setq enable-recursive-minibuffers t)
(minibuffer-depth-indicate-mode 1)
;;; Use the completing-read UI for the M-tab completion unless
;;; overridden (for example by `corfu').
(setq-default completion-in-region-function
(lambda (&rest args)
(apply (if vertico-mode
#'consult-completion-in-region
#'completion--in-region)
args)))
consult
;; Example configuration for Consult
(use-package consult
;; Replace bindings. Lazily loaded due by `use-package'.
:bind (;; C-c bindings in `mode-specific-map'
("C-c M-x" . consult-mode-command)
("C-c h" . consult-history)
("C-c k" . consult-kmacro)
("C-c m" . consult-man)
("C-c i" . consult-info)
([remap Info-search] . consult-info)
;; C-x bindings in `ctl-x-map'
("C-x M-:" . consult-complex-command) ;; orig. repeat-complex-command
("C-x b" . consult-buffer) ;; orig. switch-to-buffer
("C-x 4 b" . consult-buffer-other-window) ;; orig. switch-to-buffer-other-window
("C-x 5 b" . consult-buffer-other-frame) ;; orig. switch-to-buffer-other-frame
("C-x t b" . consult-buffer-other-tab) ;; orig. switch-to-buffer-other-tab
("C-x r b" . consult-bookmark) ;; orig. bookmark-jump
("C-x p b" . consult-project-buffer) ;; orig. project-switch-to-buffer
;; Custom M-# bindings for fast register access
("M-#" . consult-register-load)
("M-'" . consult-register-store) ;; orig. abbrev-prefix-mark (unrelated)
("C-M-#" . consult-register)
;; Other custom bindings
("M-y" . consult-yank-pop) ;; orig. yank-pop
;; M-g bindings in `goto-map'
("M-g e" . consult-compile-error)
("M-g f" . consult-flymake) ;; Alternative: consult-flycheck
("M-g g" . consult-goto-line) ;; orig. goto-line
("M-g M-g" . consult-goto-line) ;; orig. goto-line
("M-g o" . consult-outline) ;; Alternative: consult-org-heading
("M-g m" . consult-mark)
("M-g k" . consult-global-mark)
("M-g i" . consult-imenu)
("M-g I" . consult-imenu-multi)
;; M-s bindings in `search-map'
("M-s d" . consult-find) ;; Alternative: consult-fd
("M-s c" . consult-locate)
("M-s g" . consult-grep)
("M-s G" . consult-git-grep)
("M-s r" . consult-ripgrep)
("M-s l" . consult-line)
("M-s L" . consult-line-multi)
("M-s k" . consult-keep-lines)
("M-s u" . consult-focus-lines)
;; Isearch integration
("M-s e" . consult-isearch-history)
:map isearch-mode-map
("M-e" . consult-isearch-history) ;; orig. isearch-edit-string
("M-s e" . consult-isearch-history) ;; orig. isearch-edit-string
("M-s l" . consult-line) ;; needed by consult-line to detect isearch
("M-s L" . consult-line-multi) ;; needed by consult-line to detect isearch
;; Minibuffer history
:map minibuffer-local-map
("M-s" . consult-history) ;; orig. next-matching-history-element
("M-r" . consult-history)) ;; orig. previous-matching-history-element
;; Enable automatic preview at point in the *Completions* buffer. This is
;; relevant when you use the default completion UI.
:hook (completion-list-mode . consult-preview-at-point-mode)
;; The :init configuration is always executed (Not lazy)
:init
;; Optionally configure the register formatting. This improves the register
;; preview for `consult-register', `consult-register-load',
;; `consult-register-store' and the Emacs built-ins.
(setq register-preview-delay 0.5
register-preview-function #'consult-register-format)
;; Optionally tweak the register preview window.
;; This adds thin lines, sorting and hides the mode line of the window.
(advice-add #'register-preview :override #'consult-register-window)
;; Use Consult to select xref locations with preview
(setq xref-show-xrefs-function #'consult-xref
xref-show-definitions-function #'consult-xref)
;; Configure other variables and modes in the :config section,
;; after lazily loading the package.
:config
;; Optionally configure preview. The default value
;; is 'any, such that any key triggers the preview.
;; (setq consult-preview-key 'any)
;; (setq consult-preview-key "M-.")
;; (setq consult-preview-key '("S-<down>" "S-<up>"))
;; For some commands and buffer sources it is useful to configure the
;; :preview-key on a per-command basis using the `consult-customize' macro.
(consult-customize
consult-theme :preview-key '(:debounce 0.2 any)
consult-ripgrep consult-git-grep consult-grep
consult-bookmark consult-recent-file consult-xref
consult--source-bookmark consult--source-file-register
consult--source-recent-file consult--source-project-recent-file
;; :preview-key "M-."
:preview-key '(:debounce 0.4 any))
;; Optionally configure the narrowing key.
;; Both < and C-+ work reasonably well.
(setq consult-narrow-key "<") ;; "C-+"
;; Optionally make narrowing help available in the minibuffer.
;; You may want to use `embark-prefix-help-command' or which-key instead.
;; (define-key consult-narrow-map (vconcat consult-narrow-key "?") #'consult-narrow-help)
;; By default `consult-project-function' uses `project-root' from project.el.
;; Optionally configure a different project root function.
;;;; 1. project.el (the default)
;; (setq consult-project-function #'consult--default-project--function)
;;;; 2. vc.el (vc-root-dir)
;; (setq consult-project-function (lambda (_) (vc-root-dir)))
;;;; 3. locate-dominating-file
;; (setq consult-project-function (lambda (_) (locate-dominating-file "." ".git")))
;;;; 4. projectile.el (projectile-project-root)
;; (autoload 'projectile-project-root "projectile")
;; (setq consult-project-function (lambda (_) (projectile-project-root)))
;;;; 5. No project support
;; (setq consult-project-function nil)
)
;; https://www.reddit.com/r/emacs/comments/tv022a/smooth_scrolling_on_emacs_29_is_a_dream_come_true/
(pixel-scroll-precision-mode 1)
(defhydra hydra/smerge ()
"open file: "
("n" (smerge-next) "Jump to next confclit")
("p" (smerge-prev) "Jump to previous conflict")
("c" (smerge-keep-current) "keep current")
("u" (smerge-keep-upper) "keep upper version")
("l" (smerge-keep-lower) "keep lower version")
("a" (smerge-keep-all) "keep both versions")
)
(global-set-key (kbd "<f7>") 'hydra/smerge/body)
mark two files in dired, run ediff.
(setq ediff-keep-variants nil) ;; ask before close the file.
(setq ediff-keep-variants t) ;; show buffer after exit.
(defun mkm/ediff-marked-pair ()
"Run ediff-files on a pair of files marked in dired buffer
copied from https://stackoverflow.com/questions/18121808/emacs-ediff-marked-files-in-different-dired-buffers"
(interactive)
(let* ((marked-files (dired-get-marked-files nil nil))
(other-win (get-window-with-predicate
(lambda (window)
(with-current-buffer (window-buffer window)
(and (not (eq window (selected-window)))
(eq major-mode 'dired-mode))))))
(other-marked-files (and other-win
(with-current-buffer (window-buffer other-win)
(dired-get-marked-files nil)))))
(cond ((= (length marked-files) 2)
(ediff-files (nth 0 marked-files)
(nth 1 marked-files)))
((and (= (length marked-files) 1)
(= (length other-marked-files) 1))
(ediff-files (nth 0 marked-files)
(nth 0 other-marked-files)))
(t (error "mark exactly 2 files, at least 1 locally")))))
(define-key dired-mode-map (kbd "C-c e") 'mkm/ediff-marked-pair)
(defalias 'open 'find-file)
;; from emacs-reddit
;; (defun eshell-here ()
;; "Opens up a new shell in the directory associated with the current buffer's file."
;; (interactive)
;; (let* ((parent (file-name-directory (buffer-file-name)))
;; (name (car
;; (last
;; (split-string parent "/" t)))))
;; (split-window-vertically)
;; (other-window 1)
;; (eshell "new")
;; (rename-buffer (concat "*eshell: " name "*"))
;; (insert (concat "ls"))
;; (eshell-send-input)))
(defun eshell-here ()
"Opens up a new shell in the directory associated with the current buffer's file."
(interactive)
(let* ((parent (if (buffer-file-name)
(file-name-directory (buffer-file-name))
default-directory))
(name (car (last (split-string parent "/" t)))))
(split-window-vertically)
(other-window 1)
(eshell "new")
(rename-buffer (concat "*eshell: " name "*"))
(insert (concat "ls"))
(eshell-send-input)))
(global-set-key (kbd "C-!") 'eshell-here)
(defun delete-single-window (&optional window)
"Remove WINDOW from the display. Default is `selected-window'.
If WINDOW is the only one in its frame, then `delete-frame' too."
(interactive)
(save-current-buffer
(setq window (or window (selected-window)))
(select-window window)
(kill-buffer)
(if (one-window-p t)
(delete-frame)
(delete-window (selected-window)))))
(defun eshell/x (&rest args)
(delete-single-window))
Magit provides an interface to Git, and it is really pleasant to use. The reference card lists useful key-bindings and commands.
(use-package magit
:ensure t
:config
(magit-auto-revert-mode nil) ;; why disbale it?
(global-auto-revert-mode t) ;; i think it's a good idea to have auto revert.
:bind (("<f9> g" . magit-status)))
Occasionally my office machine goes down because I run R with big data, and it consumes all the memory. If that happens, I potentially lose the newsiest version of scripts, which is bit annoy. The following snippets will save all buffers in every hours.
(defun yt/save-all-buffers ()
"save all files-visiting buffers without user confirmation"
(interactive)
(save-some-buffers t nil)
(message "save all buffers... done"))
(run-at-time "05:59" 3600 'yt/save-all-buffers)
Sometimes I have to leave at the last minutes, then what I do is call a functions that commits and upload to the repo so that I can continue work at home.
The yt/git-up
function will do
- pull from the remote repo, and make sure the local repo is always up-to-date.
- add everything and commit with a timesamp.
- push local changes to the remote repo.
Here is the snippets.
(defun yt/git-backup ()
(let ((git-sh-scripts "
echo Start to Sync: $(date)
REPOS=\"org\"
for REPO in $REPOS
do
echo
echo \"Repository: $REPO\"
cd ~/git/$REPO
# update
git pull
# Remove deleted files
git ls-files --deleted -z | xargs -0 git rm >/dev/null 2>&1
# Add new files
git add -A . >/dev/null 2>&1
git commit -m \"$(date)\"
git push origin main
done
echo Finished Sync: $(date)
"))
(async-shell-command git-sh-scripts))
(message "all git sync... done"))
(defun yt/git-up ()
(interactive)
(yt/save-all-buffers)
(yt/git-backup))
Few times I did some important work over the weenend, but once I arrived office I realised I forgot uploading, These situations are quick frustrating. The following snippets will start to uploads once every three hours on my MacbookPro, but I don’t use it anymore, since I can get most of my work done in the office.
Note this workflow is suspended for it’s unsafe.
;; (cond ((eq system-type 'darwin)
;; (run-at-time "05:59" 10800 'yt/git-up)))