24 May 2022

An Emacs Configuration

stupa.png

Introduction

I was organising my Emacs configuration file recently and thought I would also share it here. This is partly to accompany a previous post on writing with org-mode, written with the mindset of a humanities student. Although still rudimentary, the configuration below will hopefully provide insight for other students in terms of customising Emacs. Learning to use Emacs over the past two years has been very rewarding to say the least, and I have a lot of basics still to grasp. Immediate future tasks would involve getting a better working knowledge of Elisp to avoid simply copying over bits of code here and there (not that I am not grateful, Stack Exchange!). Another objective would be to organise this configuration file with Babel and org-Mode to make it slightly more streamlined.

.emacs

;-----------------------------------------------------------------------;
; PACKAGES                                                              ;
;-----------------------------------------------------------------------;
(require 'package)
(add-to-list 'package-archives
             '("melpa" . "https://melpa.org/packages/") t)
(package-initialize)

;-----------------------------------------------------------------------;
; GENERAL SETTINGS                                                      ;
;-----------------------------------------------------------------------;
;; -- emacs settings
(setq initial-buffer-choice "~/org/org-todo/todo.org"
      inhibit-startup-screen t
      next-line-add-newlines t
      system-time-locale "C"
      tramp-verbose 1
      auth-sources '("~/.authinfo.gpg" "~/.authinfo" "~/.netrc")
      ring-bell-function 'ignore)

;; -- deleting stuff
(setq undo-limit 800000
      undo-strong-limit 12000000
      undo-outer-limit 120000000
      kill-ring-max 9999
      delete-by-moving-to-trash t)

;; -- writing general
(setq synosaurus-choose-method 'popup
      wc-modeline-format "WC[%W%w/%tw%gw]"
      ispell-dictionary "en_GB")

;; -- writegood
(setq writegood-weasel-words
      '("many" "various" "very" "fairly"
        "several" "extremely" "exceedingly" "quite"
        "remarkably" "few" "surprisingly" "mostly"
        "largely" "huge" "tiny" "are a number"
        "is a number" "excellent" "interestingly" "significantly"
        "substantially" "clearly" "vast" "relatively"
        "completely" "literally" "not rocket science" "pretty"
        "outside the box" "In this regard" "With this in mind"
        "With the above in mind" "In this sense" "variety"))

;; -- olivetti
(setq olivetti-body-width 0.50
      olivetti-minimum-body-width 72
      olivetti-recall-visual-line-mode-entry-state t)

;; -- programming
(setq electric-pair-preserve-balance nil)
(add-hook 'emacs-lisp-mode-hook #'aggressive-indent-mode)

;; -- misc modes
(electric-pair-mode 1)
(menu-bar-mode -1)
(show-paren-mode 1)
(delete-selection-mode t)
(xclip-mode 1)
(tool-bar-mode -1)
(set-default 'truncate-lines t)
(global-centered-cursor-mode +1)
(global-auto-revert-mode)
(scroll-bar-mode -1)

;; -- hooks for programming
(add-hook 'prog-mode-hook 'display-line-numbers-mode)
(add-hook 'prog-mode-hook 'electric-indent-mode)
(add-hook 'prog-mode-hook 'hl-line-mode)

;; -- hooks for text
(add-hook 'text-mode-hook 'writegood-mode)
(add-hook 'text-mode-hook 'wc-mode)
(add-hook 'text-mode-hook 'synosaurus-mode)
(add-hook 'text-mode-hook 'olivetti-mode)
(add-hook 'text-mode-hook 'palimpsest-mode)
(add-hook 'text-mode-hook #'flyspell-mode)

;; -- dired 
(put 'dired-find-alternate-file 'disabled nil)
(add-hook 'dired-mode-hook 'dired-hide-details-mode)

;; -- no popup for async shell command
(add-to-list 'display-buffer-alist
             (cons "\\*Async Shell Command\\*.*" (cons #'display-buffer-no-window nil)))

;-----------------------------------------------------------------------;
; GLOBAL KEYBINDINGS                                                    ;
;-----------------------------------------------------------------------;
;; -- general
(global-set-key (kbd "C-c s") #'flyspell-buffer)
(global-set-key (kbd "C-c w") 'count-words-region)
(global-set-key (kbd "<f5>" ) 'async-shell-command)
(global-set-key (kbd "C-c v") 'visual-line-mode)
(global-set-key (kbd "C-c y") 'helm-show-kill-ring)
(global-set-key (kbd "C-c c") 'comment-region)
(global-set-key (kbd "C-c u") 'uncomment-region)
(global-set-key (kbd "C-c k") 'clone-indirect-buffer)
(global-set-key (kbd "C-c h") 'helm-descbinds)
(global-set-key (kbd "C-c 1") 'elfeed)
(global-set-key (kbd "C-c l") #'flyspell-popup-correct)

;; -- org
(global-set-key (kbd "C-c b") #'org-capture-at-point)
(global-set-key (kbd "C-c a") 'org-agenda)
(global-set-key (kbd "C-c p") 'org-pomodoro)
(global-set-key (kbd "<f6>" ) 'org-capture)
(global-set-key (kbd "C-c o") 'org-wc-display)
(global-set-key (kbd "C-c 0") 'org-insert-structure-template)
(global-set-key (kbd "C-c g") 'org-schedule)
(global-set-key (kbd "C-c d") 'org-deadline)
(global-set-key (kbd "C-c q") 'org-insert-heading-after-current)

;; -- org-roam
(global-set-key (kbd "C-c n l") 'org-roam-buffer-toggle)
(global-set-key (kbd "C-c n f") 'org-roam-node-find)
(global-set-key (kbd "C-c n g") 'org-roam-graph)
(global-set-key (kbd "C-c n i") 'org-roam-node-insert)
(global-set-key (kbd "C-c n c") 'org-roam-capture)
(global-set-key (kbd "C-c n j") 'org-roam-dailies-capture-today)
(global-set-key (kbd "C-c n d") 'org-journal-new-entry)
(global-set-key (kbd "C-c n r") 'org-journal-search-forever)
(global-set-key (kbd "C-c n p") 'completion-at-point)
(global-set-key (kbd "C-c n s") 'deft)

;; -- engine mode
(engine-mode t)
(defengine duckduckgo "https://duckduckgo.com/?q=%s"
  :keybinding "d")
(defengine google "http://www.google.com/search?ie=utf-8&oe=utf-8&q=%s"
  :keybinding "g")
(defengine wikipedia "http://www.wikipedia.org/search-redirect.php?language=en&go=Go&search=%s"
  :keybinding "w" :docstring "Searchin' the wikis.")

;-----------------------------------------------------------------------;
; ORG MODE                                                              ;
;-----------------------------------------------------------------------;
;; -- ox extras
(require 'ox-extra)
(require 'ox-latex)
(require 'ox-bibtex) ;; ox-bibtex has to be loaded before org-ref

;; -- ignore tag for export
(ox-extras-activate
 '(ignore-headlines))

;; -- org general
(setq org-directory "~/org"
      org-file-apps '((auto-mode . emacs)
                      ("\\.x?html?\\'" . "firefox %s")
                      ("\\.pdf\\'" . "evince \"%s\"")
                      ("\\.pdf::\\([0-9]+\\)\\'" . "evince \"%s\" -p %1"))
      org-startup-folded t
      org-startup-indented t
      org-indent-mode t
      org-log-into-drawer t
      org-hide-emphasis-markers nil
      org-startup-truncated t)

;; -- org-ref
(require 'org-ref)
(setq org-ref-bibliography-notes "~/bibliography/bibliography-notes.org"
      org-ref-default-bibliography '("~/bibliography/bibliography.bib"))

;; -- org-pomodoro
(setq org-pomodoro-audio-player "/usr/bin/mpv"
      org-pomodoro-play-sounds t)

;; -- org latex export
(setq org-latex-toc-command "\\tableofcontents \\clearpage"
      org-latex-compiler "xelatex"
      org-latex-pdf-process '("xelatex -shell-escape -interaction nonstopmode -output-directory %o %f"
                              "bibtex %b" "xelatex -shell-escape -interaction nonstopmode -output-directory %o %f"
                              "xelatex -shell-escape -interaction nonstopmode -output-directory %o %f"))

;; -- org export general
(setq org-export-with-smart-quotes t
      org-export-preserve-breaks t
      org-export-with-toc nil
      org-export-with-section-numbers nil
      org-html-footnotes-section "<div id=\"footnotes\">
                                        <h2 class=\"footnotes\">%s </h2>
                                                <div id=\"text-footnotes\">%s</div>
                                  </div>")

;; -- org agenda
(setq org-agenda-start-on-weekday nil
      org-agenda-window-setup 'only-window)

;; -- org source blocks
(setq org-src-tab-acts-natively t
      org-confirm-babel-evaluate nil)

;; -- org capture
(setq org-capture-templates '(("n" "note-at-point" plain (file "") " - (%^{location}) Here it says that %^{Here it says that...}.")
                             ("w" "weekly-review-at-point" plain (file "~/org/notes.org") (file "~/org/org-templates/weekly-review.txt"))
                             ("d" "diary-at-point" plain (file "~/org/notes.org") (file "~/org/org-templates/daily-diary.txt"))
                             ("t" "scheduled-todo" entry (file+headline "~/org/org-todo/todo.org" "TASK-INDEX") (file "~/org/org-templates/scheduled-todo.txt"))
                             ("r" "rss todo" entry (file+olp "~/org/org-todo/todo.org" "TASK-INDEX") "* TODO %^{Description} %^g:RSS:\nSCHEDULED: %^t\n\n %a\n\n %i")))

;; -- capture at point, for notes and stuff
(defun org-capture-at-point () (interactive)
       (org-capture 0))

;; -- babel
(org-babel-do-load-languages
 'org-babel-load-languages '((emacs-lisp . t)
                             (python . t)
                             (lua . t)))

(add-to-list 'org-latex-classes
             '("letter" "\\documentclass{letter}"
               ("\\section{%s}" . "\\section*{%s}")
               ("\\subsection{%s}" . "\\subsection*{%s}")
               ("\\subsubsection{%s}" . "\\subsubsection*{%s}")))

;; -- org bullets
(require 'org-bullets)
(add-hook 'org-mode-hook
          (lambda () (org-bullets-mode 1)))

;-----------------------------------------------------------------------;
; NOTIFICATION THINGY                                                   ;
;-----------------------------------------------------------------------;
(appt-activate t)

(setq appt-message-warning-time 5
      appt-display-interval appt-message-warning-time
      appt-display-mode-line nil)

(require 'appt)

(defun my-org-agenda-to-appt () (interactive)
       (setq appt-time-msg-list nil)(org-agenda-to-appt))

(my-org-agenda-to-appt)

(add-hook 'after-save-hook '(lambda ()
                              (if (string= (buffer-file-name)
                                           (concat (getenv "HOME") "/org/org-todo/todo.org"))
                                  (my-org-agenda-to-appt))))

(setq appt-disp-window-function 'my-appt-display
      appt-delete-window-function (lambda () t)
      my-appt-notification-app (concat (getenv "HOME") "/bin/appt-notification"))

(defun my-appt-display (min-to-app new-time msg)
  (if (atom min-to-app)
      (start-process "my-appt-notification-app" nil my-appt-notification-app min-to-app msg)
    (dolist (i (number-sequence 0 (1- (length min-to-app))))
      (start-process "my-appt-notification-app" nil my-appt-notification-app (nth i min-to-app) (nth i msg)))))

;; -- align tags thingy
(defun my-org-align-tags () (interactive) (org-align-tags 0))
(add-hook 'org-mode-hook
          (lambda ()
            (add-hook 'after-save-hook 'my-org-align-tags nil 'make-it-local)))

;-----------------------------------------------------------------------;
; WEBSITE                                                               ;
;-----------------------------------------------------------------------;
(setq org-static-blog-publish-title "Ilmari Koria"
      org-static-blog-publish-url "https://ilmarikoria.com"
      org-static-blog-publish-directory "~/org/org-blog/html"
      org-static-blog-posts-directory "~/org/org-roam/blog"
      org-static-blog-drafts-directory "~/org/org-blog/blog-drafts"
      org-static-blog-enable-tags nil
      org-static-blog-preview-ellipsis ""
      org-static-blog-use-preview t
      org-static-blog-preview-start ""
      org-static-blog-preview-end "")

(setq org-static-blog-index-front-matter "<div id=\"recent-posts\">
                                                <h2>recent posts</h2>
                                          </div>")      

(setq org-static-blog-page-header "<meta name=\"author\" content=\"Ilmari Koria\">
                                   <meta name=\"referrer\" content=\"no-referrer\">
                                   <meta name=\"viewport\" content=\"initial-scale=1.0,maximum-scale=1.0,user-scalable=no\" />
                                   <link href= \"static/style.css\" rel=\"stylesheet\" type=\"text/css\" />
                                   <link rel=\"icon\" href=\"data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏞</text></svg>\">")

(setq org-static-blog-page-preamble "<div id=\"banner\">
                                        <div id=\"top-nav\">
                                                <p style=\"text-align:left;\">ilmari koria blog 
                                                        <span style=\"float:right;\">
                                                                <a href=\"https://ilmarikoria.com\">home</a> | <a href=\"https://ilmarikoria.com/archive.html\">posts</a> | <a href=\"https://ilmarikoria.com/contact.html\">contact</a>
                                                        </span>
                                                </p>
                                        </div>
                                     </div>")      

(setq org-static-blog-page-postamble "<hr>
                                      <div id=\"bottom-nav\">
                                        <a href=\"https://ilmarikoria.com/rss.xml\">rss</a> | <a href=\"https://creativecommons.org/licenses/by-nc/4.0/\">license</a>
                                      </div>")

;-----------------------------------------------------------------------;
; ORG ROAM                                                              ;
;-----------------------------------------------------------------------;
;; -- org-roam automatically uses whatever completion engine is on
(add-hook 'after-init-hook 'helm-mode)
(helm-mode t)
(setq helm-truncate-lines t)

;; -- roam basic
(setq org-roam-directory (file-truename "~/org/org-roam")
      org-roam-v2-ack t
      org-roam-completion-everywhere t)

(org-roam-db-autosync-mode)

;; -- roam ui visualiser 
(setq org-roam-ui-sync-theme t
      org-roam-ui-follow t
      org-roam-ui-update-on-save t
      org-roam-ui-open-on-start t)

;; -- roam templates
(setq org-roam-capture-templates
      '(("p" "permanent-note" plain "%?" :target (file+head "permanent-notes/%<%Y-%m-%d>-permanent-${slug}.org" "#+title: ${title}\n#+filetags: %^{TAGS}\n # ~ REMEMBER: max 200 words") :unnarrowed t)
        ("b" "blog" plain "%?" :target (file+head "blog-drafts/%<%Y-%m-%d>-blog-${slug}.org" "#+title: ${title}\n#+filetags: %^{TAGS}\n#+DESCRIPTION: %^{short description}\n#+date: <%<%Y-%m-%d %H:%M>>\n# ~ REMEMBER: max 5-6 citations\n* Introduction\n* par2\n* par3\n* par4\n* par5\n* par6\n* par7\n* Conclusion\n* References :ignore:\n#+BIBLIOGRAPHY: bibliography.bib plain option:-a option:-noabstract option:-heveaurl limit:t\n* Footnotes :ignore:\n* Text-dump :noexport:") :unnarrowed t)
        ("r" "reference-note" plain "%?" :target (file+head "reference-notes/%<%Y-%m-%d>-reference-${citekey}.org" "#+title: ${citekey} - ${title}\n#+filetags: %^{TAGS}\n\n--\n *") :unnarrowed t)
        ("m" "misc-note" plain "%?" :target (file+head "misc-notes/%<%Y-%m-%d>-misc-${slug}.org" "#+title: ${title}\n#+filetags: %^{TAGS}") :unnarrowed t)
        ("o" "project-note" plain "%?" :target (file+head "project-notes/%<%Y-%m-%d>-project-${slug}.org" "#+title: ${title}\n#+filetags: %^{TAGS}") :unnarrowed t)
        ("l" "lecture-note" plain "%?" :target (file+head "lecture-notes/%<%Y-%m-%d>-lecture-${slug}.org" "#+title: ${title}\n#+filetags: %^{TAGS}") :unnarrowed t)))

;; -- dailies
(setq org-roam-dailies-directory "~/org/org-roam/fleeting-notes"
      org-roam-dailies-capture-templates '(("f" "fleeting-notes" entry "\n* %<%Y-%m-%d %H:%M> - %?" :target (file "fleeting-notes.org"))))

;; -- deft
(setq deft-recursive t
      deft-use-filter-string-for-filename t
      deft-default-extension "org"
      deft-directory org-roam-directory)

;; -- journal
(require 'org-journal)
(setq org-journal-dir "~/org/org-roam/org-journal"
      org-journal-date-format "%Y-%m-%d"
      org-journal-file-format "%Y-%m-journal.org"
      org-journal-enable-agenda-integration t
      org-journal-file-type 'monthly
      org-journal-file-header "#+title: Journal %Y-%m\n#+filetags: diary")

;; -- org roam bibtex
(add-to-list 'load-path "~/.emacs.d/my-packages/org-roam-bibtex")
(require 'org-roam-bibtex)
(add-hook 'after-init-hook 'org-roam-bibtex-mode)
(setq orb-insert-follow-link t)

;; -- add "type" node
(cl-defmethod org-roam-node-type ((node org-roam-node))
  "Return the TYPE of NODE."
  (condition-case nil
      (file-name-nondirectory (directory-file-name
                               (file-name-directory
                                (file-relative-name (org-roam-node-file node) org-roam-directory))))
    (error "")))
(setq org-roam-node-display-template "${type:20} ${tags:50} ${title:*}")

;-----------------------------------------------------------------------;
; ELFEED RSS                                                            ; 
;-----------------------------------------------------------------------;
;; -- basic setup
(setq elfeed-search-filter "@3-days-ago +unread"
      elfeed-search-title-max-width 100
      elfeed-search-title-min-width 100
      url-queue-timeout 30
      elfeed-use-curl t)

;; -- styling hooks
(add-hook 'elfeed-show-mode-hook 'olivetti-mode)
(add-hook 'elfeed-show-mode-hook 'visual-line-mode)

;; -- elfeed-org
(require 'elfeed-org)
(elfeed-org)
(setq rmh-elfeed-org-files (list "~/org/org-todo/rss.org"))

;; -- youtube mpv
(defun ga/play-with-mpv (start end)
"Play the link in the region with mpv"
(interactive "r")
(async-shell-command (concat "yt-dlp " (buffer-substring start end) " -o  - | mpv --no-terminal - \&"))) 
(define-key elfeed-show-mode-map (kbd "C-c o") 'ga/play-with-mpv)

;; -- quick macro to open vid
(fset 'rss-youtube
      (kmacro-lambda-form [?\M-a ?\C-s ?L ?i ?n ?k ?: ?  return ?\C-  ?\C-e ?\C-c ?o] 0 "%d"))
(global-set-key (kbd "C-c 2") 'rss-youtube)

;-----------------------------------------------------------------------;
; STYLING/THEMES                                                        ; 
;-----------------------------------------------------------------------;
;; -- org styling
(set-face-underline 'org-ellipsis nil)

;----------------------------------------------------------------------;
; ADDED BY EMACS                                                       ; 
;----------------------------------------------------------------------;
(custom-set-variables
 '(custom-enabled-themes '(modus-operandi))
 '(custom-safe-themes
   '("c414f69a02b719fb9867b41915cb49c853489930be280ce81385ff7b327b4bf6" "02fff7eedb18d38b8fd09a419c579570673840672da45b77fde401d8708dc6b5" default))
 '(helm-completion-style 'helm)
 '(org-agenda-files
   '("~/org/org-todo/todo.org" "~/org/org-roam/org-journal/2022-05-journal.org"))
 '(package-selected-packages
   '(aggressive-indent modus-themes elfeed-org srefactor org-static-blog org-bullets lua-mode adaptive-wrap deft org-msg flyspell-popup helm-bibtex wc-mode mu4e-alert elfeed helm-descbinds palimpsest xclip olivetti org-roam-ui org-roam engine-mode synosaurus centered-cursor-mode org-wc writegood-mode org-contrib org-journal org-pomodoro notmuch)))

(custom-set-faces
 '(default ((t (:family "Noto Sans Mono" :foundry "GOOG" :slant normal :weight normal :height 120 :width normal))))
 '(flyspell-incorrect ((t (:foreground "red"))))
 '(minibuffer-prompt ((t (:inherit modus-themes-prompt))))
 '(writegood-duplicates-face ((t (:underline (:color "deep sky blue" :style wave)))))
 '(writegood-passive-voice-face ((t (:underline (:color "magenta" :style wave)))))
 '(writegood-weasels-face ((t (:underline (:color "green yellow" :style wave))))))

rss | license | debian hosted