emacs-config
文件大小: unknow
源码售价: 5 个金币 积分规则     积分充值
资源说明:My personal dot-emacs
#+TITLE: Colin's Emacs Configuration
#+AUTHOR: Colin Alstad
#+EMAIL: colin.alstad@gmail.com

#+PROPERTY: header-args:emacs-lisp :results none

* Emacs Configuration
This is my "dot emacs" configuration using =org-mode=.  It has been heavily influenced/stolen from [[https://github.com/abedra/emacs.d][Aaron Bedra's emacs config]].
** Global Configuration
*** Constants
These are constants that are used throughout the configuration
(mostly for file path locations).

Where we persist files between emacs sessions.
#+BEGIN_SRC emacs-lisp
  (setq calstad/persistence-dir
        (expand-file-name "persistence/" user-emacs-directory))
#+END_SRC

The directory that will sync files across all machines.
#+BEGIN_SRC emacs-lisp
  (setq calstad/sync-dir "~/Dropbox")
#+END_SRC

The directory for all things =org-mode= related.
#+BEGIN_SRC emacs-lisp
  (setq calstad/org-dir (expand-file-name "org" calstad/sync-dir))
#+END_SRC

Where we keep capture templates for =org-mode= and related packages.
#+BEGIN_SRC emacs-lisp
  (setq calstad/org-capture-templates
        (expand-file-name "org_capture_templates/" user-emacs-directory))
#+END_SRC

The location of my reference library including bibliographies and PDFs.
#+BEGIN_SRC emacs-lisp
  (setq calstad/ref-lib-dir (expand-file-name "library" calstad/sync-dir)
        calstad/lib-bib (expand-file-name "library.bib" calstad/ref-lib-dir)
        calstad/lib-docs (expand-file-name "documents/" calstad/ref-lib-dir))
#+END_SRC

Directory where we keep all of the =org-roam= files.
#+BEGIN_SRC emacs-lisp
  (setq calstad/org-roam-dir
        (expand-file-name "roam" calstad/org-dir))
#+END_SRC
*** User details
Emacs will normally pick this up automatically, but this way I can be sure the right information is always present.
#+BEGIN_SRC emacs-lisp
  (setq user-full-name "Colin Alstad"
        user-mail-address "colin.alstad@gmail.com")
#+END_SRC
*** Packages
We use the [[https://github.com/raxod502/straight.el][straight]] package manager to take care of dependency management. The straight package is bootstrapped in the [[file:init.el::;; Install straight.el to manage packages][init file]] so that the [[https://github.com/raxod502/straight.el#the-wrong-version-of-my-package-was-loaded][wrong version]] of =org-mode= is not loaded.

Next we setup straight to use the [[https://github.com/jwiegley/use-package][use-package]] macro for package configuration.
#+BEGIN_SRC emacs-lisp
  ;; Use straight to install use-package
  (straight-use-package 'use-package)
  ;; Tell use-package to always install from straight
  (setq straight-use-package-by-default t)
#+END_SRC
*** UI
**** Skip splash screen on startup
#+BEGIN_SRC emacs-lisp
  (setq initial-buffer-choice t)
#+END_SRC
**** GUI options
#+BEGIN_SRC emacs-lisp
  (when window-system
    (setq frame-title-format '(buffer-file-name "%f" ("%b")))
    (tooltip-mode -1)       ; dont need mouse tootips!
    (mouse-wheel-mode t)    ; stupid mice
    (blink-cursor-mode -1)  ; about to give me seizures
    (tool-bar-mode -1))
#+END_SRC
**** Terminal options
#+BEGIN_SRC emacs-lisp
  (menu-bar-mode -1)
#+END_SRC
**** Set a color theme
#+BEGIN_SRC emacs-lisp
  (use-package zenburn-theme
    :config (load-theme 'zenburn t))
#+END_SRC
**** Turn off visual and audio bells
#+BEGIN_SRC emacs-lisp
  (setq visible-bell t
        ring-bell-function 'ignore)
#+END_SRC
**** Add indication at bottom of buffer for empty lines
#+BEGIN_SRC emacs-lisp
  (set-default 'indicate-empty-lines t)
#+END_SRC
**** Mode line settings
#+BEGIN_SRC emacs-lisp
  (line-number-mode t)
  (column-number-mode t)
  (size-indication-mode t)
#+END_SRC
**** Enable y/n answers
#+BEGIN_SRC emacs-lisp
  (fset 'yes-or-no-p 'y-or-n-p)
#+END_SRC
**** Confirm exiting Emacs
#+BEGIN_SRC emacs-lisp
  (setq confirm-kill-emacs 'y-or-n-p)
#+END_SRC
*** Editing
**** Key bindings
Miscellaneous editing keybindings
#+BEGIN_SRC emacs-lisp
  (global-set-key (kbd "RET") 'newline-and-indent)
  (global-set-key (kbd "C-;") 'comment-or-uncomment-region)
  (global-set-key (kbd "C-+") 'text-scale-increase)
  (global-set-key (kbd "C--") 'text-scale-decrease)
#+END_SRC
**** Marking text
Be able to write over the marked region and also highlight the
marked region.
#+BEGIN_SRC emacs-lisp
  (delete-selection-mode t)
  (transient-mark-mode t)
#+END_SRC
**** Filling
***** Add auto fill to certain modes
#+BEGIN_SRC emacs-lisp
  (add-hook 'text-mode-hook 'visual-line-mode)
#+END_SRC
***** Unfill a region
#+BEGIN_SRC emacs-lisp
  (defun calstad/unfill-region ()
    (interactive)
    (let ((fill-column (point-max)))
      (fill-region (region-beginning) (region-end) nil)))
#+END_SRC
**** Spell check
Use =ispell= as the spell checker
#+BEGIN_SRC emacs-lisp
  (setq ispell-program-name "ispell")
#+END_SRC

Check spelling on the fly
#+BEGIN_SRC emacs-lisp
  (add-hook 'text-mode-hook 'flyspell-mode)
  (add-hook 'prog-mode-hook 'flyspell-prog-mode)
#+END_SRC

Use a shared dictionary
#+BEGIN_SRC emacs-lisp
  (setq ispell-personal-dictionary (expand-file-name "flyspell_dictionary" calstad/org-dir))
#+END_SRC
Remap keybinding
#+BEGIN_SRC emacs-lisp
  (eval-after-load 'flyspell
    '(define-key flyspell-mode-map (kbd "C-;") nil))
#+END_SRC
**** Death to tabs
#+BEGIN_SRC emacs-lisp
  (setq-default indent-tabs-mode nil)
#+END_SRC
**** Highlight matching parens and auto pair
#+BEGIN_SRC emacs-lisp
  (show-paren-mode t)
  (setq show-paren-style 'parenthesis)
  (electric-pair-mode)
#+END_SRC
**** Enable Disabled commands
These commands are disabled by default and I would like to use
them.
#+BEGIN_SRC emacs-lisp
  (put 'upcase-region 'disabled nil)
  (put 'downcase-region 'disabled nil)
#+END_SRC
*** Windows and Buffers
**** Use better buffer list
=IBuffer= is a more feature rich buffer list than =Buffer Menu=.
#+BEGIN_SRC emacs-lisp
  (global-set-key (kbd "C-x C-b") 'ibuffer)
#+END_SRC
**** Swap windows
If I have two windows open, it swaps them.
#+BEGIN_SRC emacs-lisp
  (defun calstad/swap-windows ()
    (interactive)
    (if (/= (count-windows) 2)
        (message "You need exactly 2 windows to do this.")
      (let* ((w1 (first (window-list)))
             (w2 (second (window-list)))
             (b1 (window-buffer w1))
             (b2 (window-buffer w2))
             (s1 (window-start w1))
             (s2 (window-start w2)))
        (set-window-buffer w1 b2)
        (set-window-buffer w2 b1)
        (set-window-start w1 s2)
        (set-window-start w2 s1)))
    (other-window 1))
#+END_SRC
***** Keybinding
#+BEGIN_SRC emacs-lisp
  (global-set-key (kbd "C-c s") 'calstad/swap-windows)
#+END_SRC
**** Kill other buffers
Kills all the buffers but the current one.  Doesent mess with
earmuffed buffers.
#+BEGIN_SRC emacs-lisp
  (defun calstad/kill-other-buffers ()
    (interactive)
    (dolist (buffer (buffer-list))
      (unless (or (eql buffer (current-buffer)) (not (buffer-file-name buffer)))
        (kill-buffer buffer))))
#+END_SRC
**** Kill the buffer and delete file
Kills the current buffer and deletes the file it is visiting.
#+BEGIN_SRC emacs-lisp
  (defun calstad/delete-file-and-buffer ()
    (interactive)
    (let ((filename (buffer-file-name)))
      (when filename
        (delete-file filename)
        (message "Deleted file %s" filename)))
    (kill-buffer))
#+END_SRC
**** Revert buffers automatically when underlying files change
#+BEGIN_SRC emacs-lisp
  (global-auto-revert-mode t)
#+END_SRC
***** Keybinding
#+BEGIN_SRC emacs-lisp
  (global-set-key (kbd "C-c C-k") 'calstad/delete-file-and-buffer)
#+END_SRC

**** Rename buffers
#+BEGIN_SRC emacs-lisp
  (global-set-key (kbd "C-c r") 'rename-buffer)
#+END_SRC
**** Unique buffer names
Make it so that buffers have unique names if the files dont.
#+BEGIN_SRC emacs-lisp
  (require 'uniquify)
  (setq uniquify-buffer-name-style 'forward
        uniquify-separator "/"
        uniquify-after-kill-buffer-p t ; rename after killing uniquified
        uniquify-ignore-buffers-re "^\\*" ; don't muck with special buffers
        )
#+END_SRC
*** Encrypting/Decrypting Files
Enable the =EasyPG= package
#+BEGIN_SRC emacs-lisp
  (epa-file-enable)
#+END_SRC

Specify the GPG key to use to encrypt/decrypt files.
#+BEGIN_SRC emacs-lisp
  (setq epa-file-encrypt-to "me@colinalstad.com")
#+END_SRC

Specify which GPG program to use.
#+BEGIN_SRC emacs-lisp
  (setq epg-gpg-program "gpg2")
  (setf epa-pinentry-mode 'loopback)
#+END_SRC
*** Persistence Files
Several Emacs major modes use files for persistence between
sessions and I keep them all in the same directory.
#+BEGIN_SRC emacs-lisp
  (unless (file-exists-p calstad/persistence-dir)
    (make-directory calstad/persistence-dir t))
#+END_SRC
**** Save settings from Customize into seperate file
By default, settings changed through the Customize UI are added to
the =init.el= file.  This saves those customizations into a
separate file.
#+BEGIN_SRC emacs-lisp
  (setq custom-file (expand-file-name "custom.el" calstad/persistence-dir))
  (unless (file-exists-p custom-file)
    (write-region "" nil custom-file))
  (load custom-file)
#+END_SRC
**** Recently accessed files
#+BEGIN_SRC emacs-lisp
  (setq recentf-save-file (expand-file-name "recentf" calstad/persistence-dir))
#+END_SRC
**** Bookmarks
#+BEGIN_SRC emacs-lisp
  (setq bookmark-default-file (expand-file-name "bookmarks" calstad/persistence-dir))
#+END_SRC
**** URL Cache, Cookies, and History
#+BEGIN_SRC emacs-lisp
  (setq url-configuration-directory (expand-file-name "url/" calstad/persistence-dir))
#+END_SRC
**** Tramp Connections
#+BEGIN_SRC emacs-lisp
  (setq tramp-persistency-file-name (expand-file-name "tramp" calstad/persistence-dir))
#+END_SRC
**** Forget backup and temporary files
Dont create backup or temporary files
#+BEGIN_SRC emacs-lisp
  (setq make-backup-files nil
        backup-directory-alist `((".*" . ,temporary-file-directory))
        auto-save-file-name-transforms `((".*" ,temporary-file-directory t))
        auto-save-list-file-prefix nil)
#+END_SRC
** System Specific Configuration
*** Mac OS X
**** Set meta to apple key
#+BEGIN_SRC emacs-lisp
  (setq mac-command-modifier 'meta)
#+END_SRC
**** Set font
#+BEGIN_SRC emacs-lisp
  (if window-system
      (setq default-frame-alist '((font . "-*-Monaco-medium-r-normal--15-0-72-72-m-0-iso10646-1"))))
#+END_SRC
**** Setup path for GUI emacs
#+BEGIN_SRC emacs-lisp
  (use-package exec-path-from-shell
    :config (exec-path-from-shell-initialize))
#+END_SRC
** Mode and Language Specific Configuration
*** All the Icons
#+BEGIN_SRC emacs-lisp
  (use-package all-the-icons)
#+END_SRC
*** Anki
#+BEGIN_SRC emacs-lisp
  (use-package anki-editor
    :after org-noter
    :config
    (setq anki-editor-create-decks 't))
#+END_SRC
*** Company
[[http://company-mode.github.io][company-mode]] is a text completion framework for Emacs. The name
stands for "complete anything". It uses pluggable back-ends and
front-ends to retrieve and display completion candidates.
#+BEGIN_SRC emacs-lisp
  (use-package company
    :bind (("" . company-complete)
           :map company-active-map ("M-d" . company-show-doc-buffer))
    :init (add-hook 'after-init-hook 'global-company-mode))
#+END_SRC
*** Dired
**** Use =a= to reuse dired buffer
The command =dired-find-alternate-file= is disabled by default so
we enable it which allows us to use the =a= key to reuse the
current dired buffer
#+BEGIN_SRC emacs-lisp
  (put 'dired-find-alternate-file 'disabled nil)
#+END_SRC
**** Human readable file sizes
#+BEGIN_SRC emacs-lisp
  (setq dired-listing-switches "-alh")
#+END_SRC
*** Docker
#+BEGIN_SRC emacs-lisp
  (use-package dockerfile-mode)
#+END_SRC
*** Eglot
[[https://github.com/joaotavora/eglot][Emacs Polyglot]] is a [[https://microsoft.github.io/language-server-protocol/][LSP]] client for Emacs.
#+BEGIN_SRC emacs-lisp
  (use-package eglot)
#+END_SRC
*** Emacs Lisp
Add hooks for navigation and documentation
#+BEGIN_SRC emacs-lisp
  (use-package elisp-slime-nav
    :init
    (dolist (hook '(emacs-lisp-mode-hook ielm-mode-hook))
      (add-hook hook 'turn-on-elisp-slime-nav-mode)))

  (use-package paredit
    :init
    (add-hook 'emacs-lisp-mode-hook 'enable-paredit-mode))

  (add-hook 'emacs-lisp-mode-hook 'turn-on-eldoc-mode)
#+END_SRC

Key bindings
#+BEGIN_SRC emacs-lisp
  (define-key read-expression-map (kbd "TAB") 'lisp-complete-symbol)
  (define-key lisp-mode-shared-map (kbd "RET") 'reindent-then-newline-and-indent)
#+END_SRC
*** Eshell
Start eshell or switch to it if it's active.
#+BEGIN_SRC emacs-lisp
  (global-set-key (kbd "C-x m") 'eshell)
#+END_SRC

Start a new eshell even if one is active.
#+BEGIN_SRC emacs-lisp
  (global-set-key (kbd "C-x M")
                  (lambda ()
                    (interactive)
                    (eshell t)))
#+END_SRC

Save eshell persistence files out of the way
#+BEGIN_SRC emacs-lisp
  (setq eshell-directory-name (expand-file-name "eshell/" calstad/persistence-dir))
#+END_SRC
*** Env Files
Major mode for editing =.env= files, which are used for storing
environment variables.
#+BEGIN_SRC emacs-lisp
  (use-package dotenv-mode
    :mode "\\.env\\..*\\'")
#+END_SRC
*** Helm
[[https://github.com/emacs-helm/helm][Helm]] is an Emacs framework for incremental completions and
narrowing selections.  There is a good tutorial [[http://tuhdo.github.io/helm-intro.html][here]] and the [[https://github.com/emacs-helm/helm/wiki][wiki]]
is also very helpful.  The old =ido= and =smex= configuration can
be found at commit [[https://github.com/calstad/emacs-config/commit/667cbdcf10517f3495767536739e3fc74ffa7ac7][667cbdc]].
#+BEGIN_SRC emacs-lisp
  (use-package helm
    :bind (("M-x" . helm-M-x)
           ("C-x C-f" . helm-find-files)
           ("C-x b" . helm-mini)
           ("C-x r b" . helm-filtered-bookmarks))
    :config
    (helm-mode 1)
    (helm-autoresize-mode 1))
#+END_SRC
**** Helm BibTex
[[https://github.com/tmalsburg/helm-bibtex][Helm-bibtex]] is a [[*Helm][Helm]] interface for managing BibTex
bibliographies.
#+BEGIN_SRC emacs-lisp
  (use-package helm-bibtex
    :custom
    (bibtex-completion-bibliography calstad/lib-bib)
    (bibtex-completion-library-path calstad/lib-docs)
    (bibtex-completion-pdf-symbol "⌘")
    (bibtex-completion-notes-symbol "✎")
    (bibtex-completion-additional-search-fields '(keywords)))
#+END_SRC

Sort BibTex entries in order they are in the BibTex file
#+BEGIN_SRC emacs-lisp
  (advice-add 'bibtex-completion-candidates
              :filter-return 'reverse)
#+END_SRC
*** Jupyter
[[https://github.com/dzop/emacs-jupyter][emacs-jupyter]] is an interface to communicate with Jupyter
kernels with built-in REPL and =org-mode= frontends.
#+BEGIN_SRC emacs-lisp
  (use-package jupyter)
#+END_SRC
*** Latex
**** AUCTeX
[[https://www.emacswiki.org/emacs/AUCTeX][AUCTeX]] is a comprehensive customizable integrated environment for
writing input files for TeX/LaTeX/ConTeXt/Texinfo using Emacs.
#+BEGIN_SRC emacs-lisp
  (use-package tex
    :straight auctex
    :custom
    ;; Treat environments defined in other packages as math envs
    (TeX-parse-self 't)
    ;; Follow underscores and carets by brackets
    (TeX-electric-sub-and-superscript 't))
#+END_SRC
**** CDLaTex
[[https://orgmode.org/manual/CDLaTeX-mode.html#CDLaTeX-mode][CDLaTex]] is a minor mode for fast input methods for LaTex
environments and math.
#+BEGIN_SRC emacs-lisp
  (use-package cdlatex
    :init
    (add-hook 'org-mode-hook 'turn-on-org-cdlatex))
#+END_SRC
**** Auto pair "$"
#+BEGIN_SRC emacs-lisp
  (add-hook 'TeX-mode-hook
            '(lambda ()
               (define-key LaTeX-mode-map (kbd "$") 'self-insert-command)))
#+END_SRC
*** Magit
#+BEGIN_SRC emacs-lisp
  (use-package magit
    :bind ("C-x g" . magit-status)
    :config
    ;; Keep file revert warning from showing everytime magit starts
    (setq magit-last-seen-setup-instructions "1.4.0"))
#+END_SRC
*** Markdown
#+BEGIN_SRC emacs-lisp
  (use-package markdown-mode)
#+END_SRC
*** Olivetti
#+BEGIN_SRC emacs-lisp
  (use-package olivetti)
#+END_SRC
*** Org
=org-mode= is one of the most powerful and amazing features of
Emacs. I use it for task managment, notes, journal, habit tracker,
latex, and development environment.
#+BEGIN_SRC emacs-lisp
  (use-package org
    :bind (("C-c a" . org-agenda)
           ("C-c b" . org-iswitchb)
           ("C-c c" . org-capture)
           ("C-c l" . org-store-link))
    :custom
                                          ; UI
    (org-startup-indented t)
    (org-hide-emphasis-markers t)
    (org-emphasis-alist '(("*" bold)
                          ("/" italic)
                          ("_" underline)
                          ("=" org-verbatim verbatim)
                          ("~" org-code verbatim)
                          ("+" (:strike-through nil))))
    (org-startup-folded t)
                                          ; Behavior
    (org-list-allow-alphabetical t)
    (org-insert-heading-respect-content t)
                                          ; File locations
    (org-archive-location "%s_archive::datetree/")
    (org-id-locations-file (expand-file-name "org-id-locations" calstad/persistence-dir))
    :hook
    (org-mode . visual-line-mode))
#+END_SRC
**** UI
#+BEGIN_SRC emacs-lisp
  (use-package org-bullets
      :config
      (add-hook 'org-mode-hook (lambda () (org-bullets-mode 1))))
#+END_SRC

#+BEGIN_SRC emacs-lisp
  (custom-theme-set-faces
   'user
   '(variable-pitch ((t (:family "CMU Serif" :height 1.25 :weight thin)))))
#+END_SRC

#+BEGIN_SRC emacs-lisp
  ;; (let* ((variable-tuple
  ;;         (cond ((x-list-fonts "ETBembo")         '(:font "ETBembo"))
  ;;               ((x-list-fonts "Source Sans Pro") '(:font "Source Sans Pro"))
  ;;               ((x-list-fonts "Lucida Grande")   '(:font "Lucida Grande"))
  ;;               ((x-list-fonts "Verdana")         '(:font "Verdana"))
  ;;               ((x-family-fonts "Sans Serif")    '(:family "Sans Serif"))
  ;;               (nil (warn "Cannot find a Sans Serif Font.  Install Source Sans Pro."))))
  ;;        (base-font-color     (face-foreground 'default nil 'default))
  ;;        (headline           `(:inherit default :weight bold :foreground ,base-font-color)))

  ;;   (custom-theme-set-faces
  ;;    'user
  ;;    `(org-level-8 ((t (,@headline ,@variable-tuple))))
  ;;    `(org-level-7 ((t (,@headline ,@variable-tuple))))
  ;;    `(org-level-6 ((t (,@headline ,@variable-tuple))))
  ;;    `(org-level-5 ((t (,@headline ,@variable-tuple))))
  ;;    `(org-level-4 ((t (,@headline ,@variable-tuple :height 1.1))))
  ;;    `(org-level-3 ((t (,@headline ,@variable-tuple :height 1.25))))
  ;;    `(org-level-2 ((t (,@headline ,@variable-tuple :height 1.5))))
  ;;    `(org-level-1 ((t (,@headline ,@variable-tuple :height 1.75))))
  ;;    `(org-document-title ((t (,@headline ,@variable-tuple :height 2.0))))))
#+END_SRC

#+BEGIN_SRC emacs-lisp
  ;; (use-package mixed-pitch)

#+END_SRC
**** Agenda
Set where agenda items are pulled from
#+BEGIN_SRC emacs-lisp
  (defun calstad/refresh-org-agenda-files ()
    (interactive)
    (setq org-agenda-files (directory-files-recursively calstad/org-roam-dir "\\.org\\($\\|\\.gpg$\\)")))
  (calstad/refresh-org-agenda-files)
#+END_SRC

Have todo items with no associated timestamp show up at the top
of the agenda view above the time slots instead of below.
#+BEGIN_SRC emacs-lisp
  (setq org-agenda-sort-notime-is-late nil)
#+END_SRC

Default the agenda view to the daily instead of weekly view.
#+BEGIN_SRC emacs-lisp
  (setq org-agenda-span 'day)
#+END_SRC

Show breadcrumbs for nested headline todos in the agenda views.
#+BEGIN_SRC emacs-lisp
  ;; (setq org-agenda-prefix-format
  ;;       '((agenda . " %i %-12:c%?-12t% s")
  ;;         (timeline . "  % s")
  ;;         (todo .
  ;;               " %i %-12:c %(concat \"[ \"(org-format-outline-path (org-get-outline-path)) \" ]\") ")
  ;;         (tags .
  ;;               " %i %-12:c %(concat \"[ \"(org-format-outline-path (org-get-outline-path)) \" ]\") ")
  ;;         (search . " %i %-12:c")))
#+END_SRC

Configure how the time grid is shown in the daily agenda view
#+BEGIN_SRC emacs-lisp
  (setq org-agenda-time-grid
        '((daily today require-timed remove-match)
          (700 730 800 830 900 930 1000 1030 1100 1130 1200 1230 1300 1330
               1400 1430 1500 1530 1600 1630 1700 1730 1800 1830 1900 1930
               2000 2030 2100 2130 2200 2230 2300)
          "......" "----------------"))
#+END_SRC

Remove time slots from the agenda if they fall into the range of one of the agenda items' timestamps.  This code is modified from [[https://emacs.stackexchange.com/questions/35865/org-agenda-remove-time-grid-lines-that-are-in-an-appointment?noredirect=1&lq=1][this StackExchange post]].
#+BEGIN_SRC emacs-lisp
  (defun calstad/org-time-to-minutes (time)
    "Convert an HHMM time to minutes"
    (+ (* (/ time 100) 60) (% time 100)))

  (defun calstad/org-time-from-minutes (minutes)
    "Convert a number of minutes to an HHMM time"
    (+ (* (/ minutes 60) 100) (% minutes 60)))

  (defun calstad/extract-time-window (line)
    "Gets the start and end times of each block in the agenda"
    (let ((start (get-text-property 1 'time-of-day line))
          (dur (get-text-property 1 'duration line)))
      (cond
       ((and start dur)
        (cons start
              (calstad/org-time-from-minutes
               (truncate
                (+ dur (calstad/org-time-to-minutes start))))))
       (start start)
       (t nil))))

  (defun calstad/remove-spanned-time-slots (orig-fun &rest args)
    "Removes time slots that fall within a scheduled block"
    (let* ((list (car args))
           (windows (delq nil (mapcar 'calstad/extract-time-window list)))
           (org-agenda-time-grid
            (list
             (car org-agenda-time-grid)
             (cl-remove-if
              (lambda (time)
                (cl-find-if (lambda (w)
                              (if (numberp w)
                                  (equal w time)
                                (and (>= time (car w))
                                     (< time (cdr w)))))
                            windows))
              (cadr org-agenda-time-grid) )
             (caddr org-agenda-time-grid)
             (cadddr org-agenda-time-grid)
             ))
           (res (apply orig-fun args)))
      res))

  (advice-add 'org-agenda-add-time-grid-maybe :around #'calstad/remove-spanned-time-slots)
#+END_SRC

Change the agenda sort order to implement [[https://www.calnewport.com/blog/2013/12/21/deep-habits-the-importance-of-planning-every-minute-of-your-work-day/][time block planning]].  The idea for this came from [[https://emacs.stackexchange.com/questions/38742/implement-scheduling-as-suggested-in-deep-work-using-emacs-org-mode][this StackExchange thread]].
#+BEGIN_SRC emacs-lisp
  (setq org-agenda-sorting-strategy '((agenda habit-down time-up ts-down
                                              priority-down category-keep)
                                      (todo priority-down category-keep)
                                      (tags priority-down category-keep)
                                      (search category-keep)))
#+END_SRC
**** Todo Items
***** Todo States
#+BEGIN_SRC emacs-lisp
  (setq org-todo-keywords
        '((sequence "TODO(t)" "IN-PROGRESS(p)" "WAITING(w@/!)" "|" "DONE(d!)" "CANCELLED(c@)")))
#+END_SRC

Log state changes into a property drawer
#+BEGIN_SRC emacs-lisp
  (setq org-log-into-drawer t)
#+END_SRC

Add a =CLOSED= timestamp to todo items
#+BEGIN_SRC emacs-lisp
  (setq org-log-done t)
#+END_SRC
***** Enable inline tasks
#+BEGIN_SRC emacs-lisp
  (require 'org-inlinetask)
  (setq org-inlinetask-min-level 10)
#+END_SRC
***** Enable habit tracking
#+BEGIN_SRC emacs-lisp
  (add-to-list 'org-modules 'org-habit)
  ;; (add-to-list 'org-modules 'org-checklist)
#+END_SRC
**** org-ref
Org-ref is a library for org-mode that provides rich support for
citations, labels, and cross-references in org-mode.
#+BEGIN_SRC emacs-lisp
  (use-package org-ref
    :custom
    (org-ref-insert-link-function 'org-ref-insert-link-hydra/body)
    (org-ref-insert-cite-function 'org-ref-cite-insert-helm)
    (org-ref-insert-label-function 'org-ref-insert-label-link)
    (org-ref-insert-ref-function 'org-ref-insert-ref-link)
    (org-ref-cite-onclick-function (lambda (_) (org-ref-citation-hydra/body)))
    :bind ("" . org-ref-cite-insert-helm))
  (require 'org-ref-helm)

#+END_SRC

Update the color of =org-ref= cite links to be the same as other =org-mod=
links instead of white.
#+BEGIN_SRC emacs-lisp
  (set-face-foreground
   'org-ref-cite-face
   (cdr (assoc "zenburn-yellow-2" zenburn-default-colors-alist)))
#+END_SRC
**** org-roam
#+BEGIN_SRC emacs-lisp
  (use-package org-roam
    :straight (:host github :repo "org-roam/org-roam"
                     :files (:defaults "extensions/*"))
    :custom
    (org-roam-v2-ack t)
    (org-roam-directory (file-truename calstad/org-roam-dir))
    (org-roam-db-location (expand-file-name "org-roam.db" calstad/persistence-dir))
    (org-roam-mode-sections
     (list #'org-roam-backlinks-section
           #'org-roam-reflinks-section
           ;; #'org-roam-unlinked-references-section
           ))
    (org-roam-dailies-directory "daily/")
    (org-roam-capture-templates
     '(("d" "default" plain "%?"
        :if-new (file+head "%<%Y%m%d%H%M%S%2N>.org.gpg"
                           "# -*- epa-file-encrypt-to: (\"me@colinalstad.com\") -*-\n#+TITLE: ${title}\n")
        :unnarrowed t)
       ("b" "bibliography reference" plain "%?"
        :if-new (file+head "%<%Y%m%d%H%M%S%2N>.org.gpg"
                           "# -*- epa-file-encrypt-to: (\"me@colinalstad.com\") -*-\n#+TITLE: ${title}

  ,* Notes
  :PROPERTIES:
  :CUSTOM_ID: ${citekey}
  :AUTHOR: ${author-or-editor}
  :NOTER_DOCUMENT: %(orb-process-file-field \"${citekey}\")
  :NOTER_PAGE:
  :END:")
        :unnarrowed t)))
    (org-roam-capture-ref-templates
     '(("r" "ref" plain "%?"
        :if-new (file+head "%<%Y%m%d%H%M%S%2N>.org.gpg"
                           "# -*- epa-file-encrypt-to: (\"me@colinalstad.com\") -*-\n#+TITLE: ${title}")
        :jump-to-captured t)))
    (org-roam-dailies-capture-templates
     '(("d" "default" entry
        "** %<%H:%M> %i%?\n"
        :if-new (file+head+olp "%<%Y-%m-%d>.org.gpg"
                               "# -*- epa-file-encrypt-to: (\"me@colinalstad.com\") -*-
  ,#+CATEGORY: daily
  ,#+TITLE: %<%A, %m/%d/%y>

  ,* Time Block Plan
  ,* Journal"
                               ("Journal"))
        :jump-to-captured t)))
    :bind (("C-c n l" . org-roam-buffer-toggle)
           ("C-c n f" . org-roam-node-find)
           ("C-c n g" . org-roam-graph)
           ("C-c n i" . org-roam-node-insert)
           ("C-c n c" . org-roam-capture)
           ;; Dailies
           ("C-c n j" . org-roam-dailies-capture-today)
           ("C-c n d" . org-roam-dailies-goto-today)
           ("C-c n D" . org-roam-dailies-goto-date))
    :config
    (org-roam-db-autosync-mode)
    (cl-defmethod org-roam-node-hierarchy ((node org-roam-node))
      "Return the hierarchy for the node."
      (let* ((title (org-roam-node-title node))
             (olp (mapcar (lambda (s) (if (> (length s) 10) (concat (substring s 0 10)  "…") s)) (org-roam-node-olp node)))
             (level (org-roam-node-level node))
             (filetitle (org-roam-node-file-title node))
             (shortentitle (if (> (length filetitle) 20) (concat (substring filetitle 0 20)  "...") filetitle))
             (separator (concat " " (all-the-icons-material "chevron_right") " "))
             )
        (cond
         ((>= level 1) (concat (all-the-icons-material "list" :face 'all-the-icons-green :v-adjust 0.02 :height 0.8) " "
                               (propertize shortentitle 'face 'org-roam-dim)
                               (propertize separator 'face 'org-roam-dim)
                               title))
         ;; ((> level 1) (concat (all-the-icons-material "list" :face 'all-the-icons-dpurple :v-adjust 0.02 :height 0.8)
         ;;                      " "
         ;;                      (propertize (concat shortentitle separator (string-join olp separator)) 'face 'org-roam-dim)
         ;;                      (propertize separator 'face 'org-roam-dim)
         ;;                      title))
         (t (concat (all-the-icons-faicon "file-text-o" :face 'all-the-icons-lyellow :v-adjust 0.02 :height 0.7) " " title))
         )
        ))
    (setq org-roam-node-display-template
          "${hierarchy:60} ${tags:10}"))
#+END_SRC
***** TODO Fix org-roam org-protocol capture
**** org-roam-bibtex
#+BEGIN_SRC emacs-lisp
  (use-package org-roam-bibtex
    :after org-roam
    :demand t
    :hook (org-roam-mode . org-roam-bibtex-mode)
    :custom
    (orb-insert-interface 'helm-bibtex)
    (orb-note-actions-interface 'helm)
    (orb-preformat-keywords
     '(("citekey" . "=key=") "title" "file" "author-or-editor" "year"))
    :config
    (require 'org-ref)
    (org-roam-bibtex-mode))
#+END_SRC
**** org-noter
#+BEGIN_SRC emacs-lisp
  (use-package org-noter
    :custom
    (org-noter-doc-property-in-notes t)
    (org-noter-always-create-frame nil)
    (org-noter-auto-save-last-location t))
#+END_SRC
**** elfeed-org
#+BEGIN_SRC emacs-lisp
  (use-package elfeed-org
    :custom
    (rmh-elfeed-org-files
     (list (expand-file-name "feeds.org" calstad/org-dir)))
    :config
    (elfeed-org))
#+END_SRC
**** org-chef
[[https://github.com/Chobbes/org-chef][org-chef]] is a package for managing recipes in org-mode. One of the
main features is that it can automatically extract recipes from
websites like allrecipes.com
#+BEGIN_SRC emacs-lisp
  (use-package org-chef)
#+END_SRC
**** Capture
#+BEGIN_SRC emacs-lisp
  (setq org-default-notes-file (expand-file-name "roam/tasks/inbox.org.gpg" calstad/org-dir))
  (setq org-capture-templates
        '(("c" "OrgProtocol capture" entry (file+headline org-default-notes-file "Links")
           "* TODO [[%:link][%:description]]\n%i"
           :immediate-finish t)
          ("t" "Task" entry (file+headline org-default-notes-file "Tasks")
           "* TODO %i%?")))
#+END_SRC
**** Refile
#+BEGIN_SRC emacs-lisp
  (setq org-refile-targets '((nil :maxlevel . 3)
                             (org-agenda-files :maxlevel . 3)))
  (setq org-outline-path-complete-in-steps nil)         ; Refile in a single go
  (setq org-refile-use-outline-path t)                  ; Show full paths for refiling


  (defun calstad/verify-refile-target ()
    "Exclude task headings from refile target list"
    (or (not (member (nth 2 (org-heading-components)) org-todo-keywords)))
    (save-excursion (org-goto-first-child)))

  (setq org-refile-target-verify-function 'calstad/verify-refile-target)
#+END_SRC
**** LaTeX
Highlight LaTeX source in org documents
#+BEGIN_SRC emacs-lisp
  (setq org-highlight-latex-and-related '(latex entites))
#+END_SRC

Use [[https://tex.stackexchange.com/questions/78501/change-size-of-the-inline-image-for-latex-fragment-in-emacs-org-mode][this tip]] to increase the scale of inline LaTeX images
#+BEGIN_SRC emacs-lisp
  (plist-put org-format-latex-options :scale 1.5)
#+END_SRC

Save all LaTeX preview images in the same temp directory.
#+BEGIN_SRC emacs-lisp
  (setq org-preview-latex-image-directory "/tmp/org_latex_prevs/")
#+END_SRC

Automatically preview LaTeX when opening an =org-mode= file.
#+BEGIN_SRC emacs-lisp
  ;; (setq org-startup-with-latex-preview t)
#+END_SRC

Automatically [[https://github.com/io12/org-fragtog][toggle]] LaTeX fragments when the cursor enters/leaves a
fragment.
#+BEGIN_SRC emacs-lisp
  (use-package org-fragtog
    :custom
    (org-fragtog-preview-delay 0.5)
    ;; :hook
    ;; (org-mode . org-fragtog-mode)
    )
#+END_SRC

Load these LaTeX packages by default in all org-mode documents.
#+BEGIN_SRC emacs-lisp
  (add-to-list 'org-latex-packages-alist '("" "amsthm" t))
  (add-to-list 'org-latex-packages-alist '("" "tikz-cd" t))
#+END_SRC

#+BEGIN_SRC emacs-lisp
  (setq org-preview-latex-default-process 'imagemagick)
#+END_SRC
**** org-babel
[[https://orgmode.org/worg/org-contrib/babel/][Babel]] is Org-mode's ability to execute source code within
Org-mode documents.
***** Language Support
#+BEGIN_SRC emacs-lisp
  (org-babel-do-load-languages
   'org-babel-load-languages
   '((emacs-lisp . t)
     (shell . t)
     (latex . t)
     (python . t)
     (jupyter . t)))

  (use-package ob-sagemath
    :custom
    (org-babel-default-header-args:sage '((:session . t)
                                          (:results . "output"))))
#+END_SRC
****** Use Jupyter for Python Source Blocks
#+BEGIN_SRC emacs-lisp
  (org-babel-jupyter-override-src-block "python")
#+END_SRC
***** Syntax highlighting for code blocks
#+BEGIN_SRC emacs-lisp
  (setq org-src-fontify-natively t)
#+END_SRC
***** Don't confirm executing source blocks
#+BEGIN_SRC emacs-lisp
  (setq org-confirm-babel-evaluate nil)
#+END_SRC
***** Tangle Source Blocks
According to [[https://www.reddit.com/r/orgmode/comments/5elk0z/prevent_org_from_tangling_certain_sections/][this]] reddit post, this needs to be done to allow
setting =:tangle no= as a =header-args= property for
sub-headings.
#+BEGIN_SRC emacs-lisp
  (setq org-use-property-inheritance t)
#+END_SRC
***** Inline Images
Display images generated by source blocks.
#+BEGIN_SRC emacs-lisp
  (setq org-startup-with-inline-images t)
  (add-hook 'org-babel-after-execute-hook 'org-redisplay-inline-images)
#+END_SRC
**** Importing
[[https://github.com/tecosaur/org-pandoc-import][org-pandoc-import]] converts all types of buffers to =org-mode= buffers
so I never have to leave =org-mode=!
#+BEGIN_SRC emacs-lisp
  (use-package org-pandoc-import
    :straight (:host github
                     :repo "tecosaur/org-pandoc-import"
                     :files ("*.el" "filters" "preprocessors")))
#+END_SRC
**** Exporting
Only export "a_{b}" as a subscript instead of "a_b".
#+BEGIN_SRC emacs-lisp
  (setq org-export-with-sub-superscripts '{})
#+END_SRC
***** Beamer
Have earmuffs be =bold= like normal instead of =alert=.
#+BEGIN_SRC emacs-lisp
  (defun calstad/beamer-bold (contents backend info)
    (when (eq backend 'beamer)
      (replace-regexp-in-string "\\`\\\\[A-Za-z0-9]+" "\\\\textbf" contents)))
  (add-to-list 'org-export-filter-bold-functions 'calstad/beamer-bold)
#+END_SRC
***** LaTex
Define the command to use for creating PDFs
#+BEGIN_SRC emacs-lisp
  ;; (setq org-latex-pdf-process '("latexmk -pdflatex='%latex -shell-escape -bibtex -interaction nonstopmode' -pdf -output-directory=%o -f %f"))
  (setq org-latex-pdf-process (list "latexmk -shell-escape -bibtex -output-directory=%o -cd -f -pdf %f"))
#+END_SRC

Use the =tabularx= package for exporting org-mode tables
#+BEGIN_SRC emacs-lisp
  (add-to-list 'org-latex-packages-alist '("" "tabularx"))
#+END_SRC
***** Markdown
This package allows for GitHub flavored markdown
#+BEGIN_SRC emacs-lisp
  (use-package ox-gfm
    :after ox)
#+END_SRC
***** Pandoc
[[https://github.com/kawabata/ox-pandoc][ox-pandoc]] is an =org-mode= exporter backend that utilizes
=pandoc= for exporting to multiple formats.
#+BEGIN_SRC emacs-lisp
  (use-package ox-pandoc
    :after ox)
#+END_SRC
**** External Applications
Tell =org-mode= to open certain file types using an external
application.
#+BEGIN_SRC emacs-lisp
  (mapcar
   (lambda (file-type) (add-to-list 'org-file-apps file-type :append))
   '(("\\.docx" . default)
     ("\\.pptx" . default)))
#+END_SRC
**** Saving Org Buffers
Use =advice= to save all the current =org-mode= buffers before/certain
actions are taken.
#+BEGIN_SRC emacs-lisp
  (setq calstad/org-save-funcs
        '((:before . (org-agenda-quit))
          (:after . (org-todo
                     org-store-log-note
                     org-deadline
                     org-schedule
                     org-time-stamp
                     org-refile
                     org-archive-subtree))))
#+END_SRC

In order to apply the advice to save all =org-mode= buffers to
interactivce functions, we need all to allow the save function to
take arbitrary arguments.  See this [[https://emacs.stackexchange.com/a/52897][SO answer]] for more details.
#+BEGIN_SRC emacs-lisp
  (defun calstad/org-save-all-org-buffers (&rest _ignore)
    "Apply `org-save-all-org-buffers' ignoring all arguments."
    (org-save-all-org-buffers))
#+END_SRC

Now we use our custom save function to advise the previously
specified =org-mode= functions.
#+BEGIN_SRC emacs-lisp
  (defun calstad/advise-org-funcs (org-func-alist)
    (mapcar
     (lambda (elem)
       (let ((action (car elem))
             (org-funcs (cdr elem)))
         (mapcar (lambda (org-func)
                   (advice-add org-func action 'calstad/org-save-all-org-buffers))
                 org-funcs)))
     org-func-alist))

  (calstad/advise-org-funcs calstad/org-save-funcs)
#+END_SRC

Save buffers after capture has finished
#+BEGIN_SRC emacs-lisp
  (add-hook 'org-capture-after-finalize-hook 'org-save-all-org-buffers)
#+END_SRC
*** PDF Tools
[[https://github.com/politza/pdf-tools][PDF Tools]] is, among other things, a replacement of DocView for PDF
files. The key difference is that pages are not pre-rendered by
e.g. ghostscript and stored in the file-system, but rather created
on-demand and stored in memory.
#+BEGIN_SRC emacs-lisp
  (use-package pdf-tools
    :mode ("\\.pdf\\'" . pdf-view-mode)
    :config (pdf-tools-install))
#+END_SRC
*** Pyvenv
Use [[https://github.com/jorgenschaefer/pyvenv][pyvenv]] to manage python and conda virtual environments.
#+BEGIN_SRC emacs-lisp
  (setenv "WORKON_HOME" "/usr/local/Caskroom/miniforge/base/envs")
  (use-package pyvenv
    :config
    (pyvenv-mode 1))
#+END_SRC
*** Rest Client
[[https://github.com/pashky/restclient.el][Restclient]] is a major mode for exploring HTTP REST web services.
#+BEGIN_SRC emacs-lisp
  (use-package restclient)
#+END_SRC
*** SageMath
[[http://www.sagemath.org][Sage]] is an open source mathematics software system that wraps a
lot of different math packages.
#+BEGIN_SRC emacs-lisp
  (use-package sage-shell-mode)
#+END_SRC
*** YAML
#+BEGIN_SRC emacs-lisp
  (use-package yaml-mode)
#+END_SRC
*** YASnippet
=yasnippet= is a template system for Emacs that allows type an
abbreviation and automatically expand it into function templates.

Load =yasnippet= on programming langauge major modes.
#+BEGIN_SRC emacs-lisp
  (use-package yasnippet
    :config
    (setq yas-snippet-dirs '("~/.emacs.d/snippets"))
    (yas-global-mode 1))
#+END_SRC
* Emacs Server
Start the emacs server so that clients can connect
#+BEGIN_SRC emacs-lisp
  (server-start)
  (require 'org-protocol)
#+END_SRC

本源码包内暂不包含可直接显示的源代码文件,请下载源码包。