So this is fun. I can now use literate programming to configure my OS..err text editor.
Pleas note that a HUGE chunk of this file was shamelessly stolen from the snippets in https://writequit.org/eos. I am standing on the shoulders of giants.
Let’s get started by adding my custom folders to my load path:
(setq debug-on-error nil)
Here’s where I install local packages:
(let ((default-directory "~/.emacs.d/customizations/packages/"))
(normal-top-level-add-subdirs-to-load-path))
(add-to-list 'load-path "~/.emacs.d/customizations/packages/")
To load these local packages, I add a code block to this document that looks something like this:
(if (not (require 'some-addon nil t)) (message "Package `some-addon' not found") (some-additional-config t))
I even created the require-local-package.yasnippet snippet to help.
The nice thing about the code snippet above is that if the manually-installed package isn’t installed nothing will error out. A message is written to the Messages buffer just in case I want so see what wasn’t loaded.
However, for whatever reason, this doesn’t work if the parent folder name for the
add-on ends in .el
. For example, I have a package I like to use called sx.el
. It
simply won’t load using the code above.
So what do I need to do then? Well, this works just wonderfully:
(use-package some-addon ;; or whatever the main el package name is :load-path "customizations/packages/some-addon.el")
Please note - I’m not pointing at a file called some-addon.el. That’s the folder name.
These values have to be set before starting exwm
or calling
package-initialize
:
(setq mouse-autoselect-window t
focus-follows-mouse t)
I guess I’ll add the melpa stuff. All of the cool kids seem to be using the non-stable version of melpa, but I had a lot of issues with that, so I’m just using boring-old stable + org.
(require 'package) ;; You might already have this line
(add-to-list 'package-archives
'("melpa" . "http://melpa.org/packages/")
'("org" . "https://orgmode.org/elpa/"))
(package-initialize) ;; You might already have this line
And finally, use-package
:
;; This is only needed once, near the top of the file
(eval-when-compile
(require 'use-package))
Quelpa is a package manager that you can use to install packages directly from Git. I try not to do this because it usually ends in tears sooner or later, but some cool packages (like Burly) require it.
First let’s install it:
(unless (package-installed-p 'quelpa)
(with-temp-buffer
(url-insert-file-contents "https://raw.githubusercontent.com/quelpa/quelpa/master/quelpa.el")
(eval-buffer)
(quelpa-self-upgrade)))
…and let’s integrate it with use-package
:
(quelpa
'(quelpa-use-package
:fetcher git
:url "https://github.com/quelpa/quelpa-use-package.git"))
(require 'quelpa-use-package)
Open everything in the preferred browser:
(cond
((string-equal system-type "windows-nt") ; Microsoft Windows
(progn
(setq browse-url-browser-function 'browse-url-generic
browse-url-generic-program "C:/Program Files (x86)/Google/Chrome/Application/chrome.exe")))
((string-equal system-type "gnu/linux") ; linux
(progn
(setq browse-url-browser-function 'browse-url-generic
browse-url-generic-program "/usr/bin/chromium")))
)
Now on to Org
Since I usually don’t start Emacs from the command line I need to append some of my custom apps to the Emacs path.
You need t update two variables: exec-path
and PATH
. Let’s first update exec-path
:
(cond
((string-equal system-type "windows-nt")
(progn
(setq chocolatey-root "c:/ProgramData/chocolatey")
(setq chocolatey-lib
(concat chocolatey-root "/" "lib"))
(setq chocolatey-bin
(concat chocolatey-root "/" "bin"))
(setq exec-path (append '("C:/Python27"
"c:/ProgramData/chocolatey/bin"
"C:/Users/tom.purl/AppData/Local/Programs/Python/Python36/Scripts")
exec-path))))
((string-equal system-type "gnu/linux")
(progn
(setq exec-path (append '("/home/tom/bin"
"/home/tom/local/bin"
"/run/current-system/sw/bin"
"/home/tom/scripts")
exec-path)))))
…and now PATH
:
(setenv "PATH" (concat (getenv "PATH")))
UTF-8 is the only thing that makes sense for me.
; Shamelessly stolen from https://writequit.org/eos/eos-core.html
(set-charset-priority 'unicode)
(set-default-coding-systems 'utf-8)
(set-terminal-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)
(set-selection-coding-system 'utf-8)
(prefer-coding-system 'utf-8)
(cond
((string-equal system-type "windows-nt")
(progn
(setq default-process-coding-system '(utf-8-dos . utf-8-dos))))
((string-equal system-type "gnu/linux")
(progn
(setq default-process-coding-system '(utf-8-unix . utf-8-unix)))))
Sometimes it’s just easier to fix the carriage returns. Stolen from https://www.emacswiki.org/emacs/DosToUnix:
(defun tp/encoding/dos2unix ()
"Not exactly but it's easier to remember"
(interactive)
(set-buffer-file-coding-system 'utf-8-unix 't))
I don’t want to see the startup screen. Just dump me into a scratch buffer.
(setq inhibit-startup-message t)
;; (use-package exwm
;; :ensure t
;; :config
;; (progn
;; (require 'exwm-config)
;; (exwm-config-default)))
(require 'exwm-systemtray)
(exwm-systemtray-enable)
(require 'exwm-randr)
(add-hook 'exwm-randr-screen-change-hook
(lambda ()
(start-process-shell-command
"xrandr" nil "xrandr --output HDMI-2 --auto --primary --output eDP-1 --auto --left-of HDMI-2 --mode")))
(setq exwm-randr-workspace-output-plist '(0 "HDMI-2" 1 "HDMI-2" 2 "eDP-1" 3 "eDP-1"))
(exwm-randr-enable)
(setq exwm-worspace-number 4)
I’m lazy and don’t particularly want to press S-&
every time I want to launch
an application, especially if it’s an app I start 5 times a day, so why not
create a Helm source to make things easier?
(setq tp/favorite-shell-programs
'(("Firefox" . "firefox")
("Slack" . "slack")
("Terminal" . "konsole")
("KeePassXC" . "keepassxc")))
(setq tp/helm/favorite-shell-programs-sources
`((name . "Launch commonly used programs")
(candidates . ,(mapcar 'car tp/favorite-shell-programs))
(action .
(lambda (candidate)
(let
((exe-name (cdr (assoc candidate tp/favorite-shell-programs))))
(start-process-shell-command exe-name nil exe-name))))))
Let’s create a custom keymap for all of my new EXWM shortcuts.
- “l” maps to “*l*aunch program”
- ”s” maps to “list all *s*hell buffers”
- For whatever reason this only works if you’re already visiting a shell buffer.
(define-prefix-command 'tp/exwm/key-map)
(define-key tp/exwm/key-map (kbd "r")
(lambda()
(interactive)
(helm :sources '(tp/helm/favorite-shell-programs-sources))))
(define-key tp/exwm/key-map (kbd "s") 'helm-shell-prompts-all)
(global-set-key (kbd "\C-ce") tp/exwm/key-map)
;; (exwm-enable)
;; ;; This has to be installed manually
;; (if (not (require 'poet-theme nil t))
;; (message "Package `poet-theme' not found")
;; (load-theme 'poet 1))
;; (use-package dracula-theme
;; :ensure t)
This is a nice dark theme but it doesn’t handle org-mode tables well.
;; (use-package gotham-theme
;; :ensure t)
;; (load-theme 'gotham t)
Man this is a great-looking, modular theme but like so many other awesome fonts it doesn’t support variable-pitch fonts.
(use-package gruvbox-theme
:ensure t
:config
;; (load-theme 'gruvbox-light-medium t)
)
This is a little too dark and funky for my tastes.
;; (if (not (require 'soothe-theme nil t))
;; (message "Package `soothe-theme' not found")
;; (load-theme 'soothe 1))
(use-package solarized-theme
:ensure t
:config
;; make the fringe stand out from the background
(setq solarized-distinct-fringe-background t)
;; Don't change the font for some headings and titles
(setq solarized-use-variable-pitch t)
;; make the modeline high contrast
(setq solarized-high-contrast-mode-line t)
;; Use less bolding
(setq solarized-use-less-bold t)
;; Use more italics
(setq solarized-use-more-italic t)
;; Use less colors for indicators such as git:gutter, flycheck and similar
(setq solarized-emphasize-indicators nil)
;; Don't change size of org-mode headlines (but keep other size-changes)
(setq solarized-scale-org-headlines nil)
;; Avoid all font-size changes
(setq solarized-height-minus-1 1.0)
(setq solarized-height-plus-1 1.0)
(setq solarized-height-plus-2 1.0)
(setq solarized-height-plus-3 1.0)
(setq solarized-height-plus-4 1.0))
(load-theme 'solarized-light t)
;; (use-package cloud-theme
;; :ensure t)
A lot of people seem to also like this light theme:
;; (use-package modus-operandi-theme
;; :ensure t)
;; (load-theme 'modus-operandi t)
;; (use-package acme-theme
;; :ensure t)
;; (load-theme 'acme t)
This is a sweet minor mode that makes prose pages look much nicer.
(use-package olivetti
:ensure t
:config
(add-hook 'org-mode-hook
(lambda ()
(olivetti-mode 1)
(setq olivetti-body-width 84))))
Since the screen width for prose is now 100 I’m going to bump up paragraph width too:
(setq-default fill-column 85)
Since Olivetti breaks up long lines C-k
(which maps to kill-line
) doesn’t
actually kill the entire line. Thanks to Xah yet again I have a solution:
(global-set-key (kbd "M-9") 'kill-whole-line)
Big fonts + Windows makes Emacs something somthing (slow down terribly).
(cond
((string-equal system-type "windows-nt")
(progn
(setq inhibit-compacting-font-caches 1))))
(set-face-attribute 'default nil :family "InputMonoCondensed" :height 130)
(set-face-attribute 'fixed-pitch nil :family "InputMonoCondensed" :height 130)
(cond
((string-equal system-type "windows-nt")
(progn
(set-face-attribute 'variable-pitch nil :family "InputSansCondensed" :height 130)))
((string-equal system-type "gnu/linux")
(progn
(set-face-attribute 'variable-pitch nil :family "InputSansCondensedLight" :height 130))))
Emacs has a great feature that allows you to view non-code text using a proportional font (like Helvetica) and code text using a non-proportional font (like Courier). You just have to run this below:
(add-hook 'text-mode-hook
(lambda ()
(variable-pitch-mode 1)))
For whatever reason I can never the name of the variable-pitch-mode
function so here’s
my own alias:
(defun tp/font/toggle-variable-pitch-mode ()
(interactive)
(variable-pitch-mode nil))
Let’s make it globally accessible.
Actually, let’s turn it off for a little bit. I think it’s having way too big of an impact on performance.
;; (use-package emojify
;; :ensure t
;; :init
;; (add-hook 'after-init-hook #'global-emojify-mode))
(use-package emojify
:ensure t
:mode ("\\.org\\'" . org-mode))
My pendulum has swung in the direction of using a fancier modeline, so I’m going
to try telephone-line
instead.
;; (use-package powerline
;; :ensure t
;; :config
;; (powerline-default-theme))
(use-package telephone-line
:ensure t
:config
(telephone-line-mode 1))
And why not?
(setq display-time-format "%I:%M")
(display-time-mode)
This is thanks to https://stackoverflow.com/a/750933/1380901
(defun tp/file/remove-dos-eol ()
"Do not show ^M in files containing mixed UNIX and DOS line endings."
(interactive)
(setq buffer-display-table (make-display-table))
(aset buffer-display-table ?\^M []))
All of this is shamelessly stolen from https://writequit.org/eos/eos-core.html:
(when (functionp 'menu-bar-mode)
(menu-bar-mode -1))
(when (functionp 'set-scroll-bar-mode)
(set-scroll-bar-mode 'nil))
(when (functionp 'mouse-wheel-mode)
(mouse-wheel-mode -1))
(when (functionp 'tooltip-mode)
(tooltip-mode -1))
(when (functionp 'tool-bar-mode)
(tool-bar-mode -1))
(when (functionp 'blink-cursor-mode)
(blink-cursor-mode -1))
Of course you need this!
Oh wait, according the Xah this really slows things down. I’m going to turn it off for now and see if that helps:
;; (global-linum-mode t)
(use-package zone-nyan
:defer t
:ensure t)
;; (use-package nyan-mode
;; :ensure t
;; :init
;; (add-hook 'after-init-hook #'nyan-mode)
;; :config
;; (nyan-start-animation))
This is a cool way to control font size and such for sharing:
(use-package presentation
:ensure t)
This plugin has changed my mother-flippin’ life.
(use-package org-re-reveal
:ensure t
:config
(setq org-re-reveal-root "../reveal.js")
(setq org-re-reveal-title-slide "<h1>%t</h1><footer><h5>©%a</h5></footer>"))
Make sure that your Org file has that directory beneath it.
Beacon to the rescue!
(use-package beacon
:ensure t
:defer 120
:config
(beacon-mode 1))
(use-package yasnippet
:ensure t
:config
(yas-global-mode 1))
(use-package yasnippet-snippets
:ensure t)
(cond
((string-equal system-type "windows-nt")
(progn
(setq org-directory "~/Roaming-Home/org/")))
((string-equal system-type "gnu/linux")
(progn
(setq org-directory "~/gtd/org/"))))
(setq org-log-done 'time)
Here are global properties that are available to each file. For more information on the “*_ALL” properties check this out:
;; Effort and global properties
(setq org-global-properties
'(
("POM_Estimate_ALL". "n/a 1 2 3 4 5 6 7 8 9 10")
("PRIORITIES" . "AAA AA A B C")))
(define-key global-map "\C-cl" 'org-store-link)
(define-key global-map "\C-ca" 'org-agenda)
(global-set-key (kbd "<f4>") 'set-org-agenda-files)
(add-hook 'org-mode-hook
(lambda ()
(local-set-key (kbd "<f5>") #'org-toggle-inline-images)
(local-set-key (kbd "C-c n s") #'org-narrow-to-subtree)
(local-set-key (kbd "C-c w") #'widen)))
(define-key global-map "\C-cc" 'org-capture)
(global-set-key (kbd "C-c h") 'open-org-html-file-in-browser)
(global-set-key (kbd "<f6>") (lambda() (interactive)(org-publish-current-file)))
I know this doesn’t work but I think I’m close:
(global-set-key (kbd "C-c C-x C-p") 'org-pomodoro)
Org sometimes adds an extra line between headers, which drives me nuts. This fixes that:
(setq org-blank-before-new-entry
'((heading . nil) (plain-list-item . nil)))
A version of variable pitch mode for Org docs that makes them look a little better:
(use-package org-variable-pitch
:ensure t)
If you’re running this on Windows then set then tell emacs to use hunspell
instead of ispell
:
(cond
((string-equal system-type "windows-nt")
(progn
(setq ispell-program-name
(concat chocolatey-lib "/" "hunspell.portable/tools/bin/hunspell"))))
)
Setup spell-checking in general and turn it on when you load org-mode
:
(use-package flyspell
:ensure t
:init
(add-hook 'org-mode-hook
(lambda () (flyspell-mode 1))))
(setq org-link-frame-setup (quote ((vm . vm-visit-folder-other-frame)
(vm-imap . vm-visit-imap-folder-other-frame)
(gnus . org-gnus-no-new-news)
(file . find-file)
(wl . wl-other-frame))))
(fset 'tp/org/jump-to-logbook
(lambda (&optional arg)
"Keyboard macro."
(interactive "p")
(kmacro-exec-ring-item (quote ([19 108 111 103 98 return] 0 "%d")) arg)))
(global-set-key (kbd "\C-ck") 'tp/org/jump-to-logbook)
I admit that this is a bit hacky because it requires the following:
- Your mouse pointer has to be on the parent bullet of the sub-list.
- The parent bullet needs another bullet at the same level beneath it.
However, it works really well for the intended purpose, which is taking sub-bullets created by a capture template and moving them to the top of a sub-list.
(defun tp/org/move-last-subbullet-to-top-of-sublist ()
"Move the last sub-bullet to the top of the list of sub-bullets."
(interactive)
(org-forward-heading-same-level 1)
(forward-line -1)
(kill-visual-line 1)
(org-backward-heading-same-level 1)
(forward-line 1)
(org-yank)
(forward-line -1))
(defun set-org-agenda-files ()
(interactive)
(message "Saving all org buffers to keep agenda files list clean")
(org-save-all-org-buffers)
(setq org-agenda-files (list org-directory (concat org-directory "journal")))
(message "Done setting org agenda files."))
(set-org-agenda-files)
Here’s my custom agenda view that uses “column view”.
(setq org-agenda-overriding-columns-format
"%TODO %4PRIORITY(Pri.) %50ITEM(Task) %4POM_Estimate(Est.) %7POM_Pomodori(Poms) %12CLOCKSUM_T(Today's Time)")
(setq org-agenda-view-columns-initially t)
(setq org-agenda-custom-commands
'(("p" "Pomodoro View"
((tags "+today")))
("c" "Daily Checklist"
((org-ql-block '(and (todo)
(tags "daily_checklist")
(scheduled :to today))
((org-ql-block-header "Daily Checklist")))))
("A" "Remaining Agenda"
((org-ql-block '(and (todo "TODO")
(not (or (tags "today")
(tags "daily_checklist")))
(or
(scheduled :to today)
(deadline auto)))
((org-ql-block-header "Remaining Agenda")))))
))
This only shows today’s tasks in the agenda view by default:
(setq org-agenda-span 1)
Finally, this appears to be necessary to get the clocksum
functions
to run properly on startup:
(org-clock-sum)
This function clears out the “today” tag from the tasks in my custom view above.
Note: This function is very brittle and will need to change if you make any changes to your org-agenda view.
(fset 'tp/org/remove-today-tag
(lambda (&optional arg)
"Keyboard macro."
(interactive "p")
(kmacro-exec-ring-item '([6 6 6 6 6 6 101 116 return 14 1] 0 "%d") arg)))
(fset 'tp/org/remove-pom-count
(lambda (&optional arg)
"Removes the pomodoro count from a task while viewing the agenda in column mode."
(interactive "p")
(kmacro-exec-ring-item
(quote ([6 6 6 6 101 1 11 return 14 1] 0 "%d")) arg)))
I’m hoping to use this to help organize things:
(use-package org-ql
:ensure t)
Set your default parameters for clock reports when they are viewed i the agenda view:
(setq org-agenda-clockreport-parameter-plist
'(:scope agenda-with-archives :formula % :maxlevel 10 :tags t :fileskip0 t :compact t :narrow 60 :score 0))
If I’m idle for more than X minutes then ask me what to do with the clock time:
(setq org-clock-idle-time 15)
(setq org-default-notes-file (concat org-directory "/notes.org"))
(setq org-capture-templates
'(
("t" "Todo" entry (file+headline (lambda () (concat org-directory "inbox.org")) "In-Process") "* TODO %? %^g")
("w" "Work Log" entry (file+headline (lambda () (concat org-directory "/WorkLogs.org")) "On-Deck") "** %(create-org-link 1) %?")
("d" "Daily Review" entry (file+headline (lambda () (concat org-directory "/Personal_Reviews.org")) "Daily") "** %(create-org-link 1 \"Daily Review\") %?")
("k" "Weekly Review" entry (file+headline (lambda () (concat org-directory "/Personal_Reviews.org")) "Weekly") "** %(create-org-link 1 \"Weekly Review\") %?")
("s" "Start of Week Check-In" entry (file+headline (lambda () (concat org-directory "/Personal_Reviews.org")) "Weekly") "** %(create-org-link 1 \"Start of Week Check-In\") %?")
("r" "Research Note" entry (file+headline (lambda () (concat org-directory "/ResearchNotes.org")) "In-Process") "** %(create-org-link nil) %?")
("l" "Lessons Learned" entry (file+headline (lambda () (concat org-directory "/LessonsLearned.org")) "Drafts") "** %(create-org-link nil) %?")
("m" "Meeting Minute" entry (file+headline (lambda () (concat org-directory "/MeetingMinutes.org")) "In-Process") "** %(create-org-link 1) %?")
))
(setq org-todo-keywords
'((sequence "TODO(t)" "WAIT(w@/!)" "|" "DONE(d!)" "CANCELED(c@)")))
Have org measure todo completion percentage recursively. nil
means
that you want it to look recursively.
(setq org-hierarchical-todo-statistics nil)
(defvar org-link-date-stamp-format "%y%m%d"
"Format of date stamps to use in Org links")
(defun add-date-stamp-to-file-name (org-link)
"Add a date stamp to the file name portion of an org link"
(replace-regexp-in-string ":"
(concat ":"
(format-time-string org-link-date-stamp-format (current-time))
"-") org-link))
(defun add-date-stamp-to-link-title (org-link)
"Add a date stamp to the title portion of an org link"
(replace-regexp-in-string "\\]\\["
(concat "]["
(format-time-string org-link-date-stamp-format (current-time))
" - ") org-link))
This is just a minor utility function.
(defun escape-file-titles (title)
"Take an arbitrary string and replace all of the bad chars with
underscores"
(replace-regexp-in-string " " "_" title))
Here’s a much better version of my create-org-link function courtesy of -> http://emacs.stackexchange.com/a/12166/8228
(defun create-org-link (addDate? &optional title)
"Takes a human-readable title for a link and returns a
nicely-formatted file link."
(interactive)
(unless title
(setq title
(read-string "Please enter a title: ")))
(let ((plain-file-link
(format "[[file:%s.org][%s]]" (escape-file-titles title) title)))
(let ((formatted-file-link
(if addDate?
(add-date-stamp-to-file-name (add-date-stamp-to-link-title plain-file-link))
plain-file-link)))
(if (called-interactively-p)
(insert formatted-file-link)
formatted-file-link))))
(defun org-file-name-convert-to-html (org-file-name)
"Convert an org file name into its HTML eqlivalent"
(replace-regexp-in-string
"\\(.*\\)\\/org\\/\\(.*\\)\.org$"
"\\1/org/\\2.html" org-file-name))
(defun open-org-html-file-in-browser ()
"Open the current html version of the current org file in a web
browser."
(interactive)
(browse-url-of-file (org-file-name-convert-to-html (buffer-file-name))))
When creating new org files I like to insert a nicely-formatted title at the top that’s based on the file name. The code below does things like replace underscores with spaces so that a file name like “This_Is_Cool.org” will automatically have a title of “This Is Cool”.
(defun format-page-title-from-buffer-name ()
"Takes a buffer name and returns a much more friendly looking
title.
Note: This function assumes that the create-org-link function
replaces spaces with underscores"
(interactive)
(replace-regexp-in-string "\.org" ""
(replace-regexp-in-string "_" " "
(replace-regexp-in-string "\w-\w" " - " (buffer-name))))
)
(defun org-file-header ()
"Generate a header for an org mode file"
(interactive)
(let ((out (format "#+TITLE: %s
"
(format-page-title-from-buffer-name))))
out))
(defun org-file-insert ()
"Insert a header containing HTML boilerplate and a title and
whatever else you want."
(interactive)
(insert (org-file-header)))
(add-hook 'find-file-hook 'auto-insert)
(define-auto-insert ".*\.org$" 'org-file-insert)
; Don't ask for confirmation if auto-insert is called non-interactively.
(setq auto-insert-query nil)
(require 'ox-publish)
Since this is an alist I don’t know how to embed functions in it. Thats’s why I’ve replaced the org-directory var with the literal value.
(setq org-publish-project-alist
'(
("org-notes" ;Used to export .org file
:base-directory "~/org/" ;directory holds .org files
:base-extension "org" ;process .org file only
:publishing-directory "~/org/" ;export destination
:recursive t
:publishing-function org-html-publish-to-html
:headline-levels 4 ; Just the default for this project.
:auto-preamble t
:auto-sitemap t ; Generate sitemap.org automagically...
:sitemap-filename "sitemap.org" ; ... call it sitemap.org (it's the default)...
:sitemap-title "Sitemap" ; ... with title 'Sitemap'.
:export-creator-info nil ; Disable the inclusion of "Created by Org" in the postamble.
:export-author-info nil ; Disable the inclusion of "Author: Your Name" in the postamble.
:auto-postamble nil ; Disable auto postamble
:table-of-contents t ; Set this to "t" if you want a table of contents, set to "nil" disables TOC.
:section-numbers nil ; Set this to "t" if you want headings to have numbers.
:html-postamble " <p class=\"postamble\">Last Updated %d.</p> " ; your personal postamble
:style-include-default nil ;Disable the default css style
:html-head "<link id='pagestyle' rel='stylesheet' type='text/css' href='static/css/org.css' />\n<link id='pagestyle' rel='stylesheet' type='text/css' href='static/css/custom.css' />"
("org-static" ;Used to publish static files
:base-directory "~/org/static/"
:base-extension "css\\|js\\|png\\|jpg\\|gif\\|pdf\\|mp3\\|ogg\\|swf"
:publishing-directory "~/org/"
:recursive t
:publishing-function org-publish-attachment
)
("org" :components ("org-notes" "org-static"))) ;combine "org-static" and "org-static" into one function call
))
(use-package ox-gfm
:ensure t)
(defun yas/org-very-safe-expand ()
(let ((yas/fallback-behavior 'return-nil)) (yas/expand)))
(add-hook 'org-mode-hook
(lambda ()
(make-variable-buffer-local 'yas/trigger-key)
(setq yas/trigger-key [tab])
(add-to-list 'org-tab-first-hook 'yas/org-very-safe-expand)
(define-key yas/keymap [tab] 'yas/next-field)))
Here’s the languages that I can interpret. Note that there’s a difference between the way that the shell
language is loaded between older and newer versions of Emacs. This my hacky way of fixing it for now:
(cond
((string-equal system-type "windows-nt")
(progn
(org-babel-do-load-languages
'org-babel-load-languages
'((js . t)
(emacs-lisp . t)
(shell . t)
(python . t)
(dot . t)
(plantuml . t)))))
((string-equal system-type "gnu/linux")
(progn
(org-babel-do-load-languages
'org-babel-load-languages
'((js . t)
(emacs-lisp . t)
(shell . t)
(python . t)
(dot . t)
(plantuml . t))))))
I don’t want to manually confirm that code written in the following languages can be executed:
(defun my-org-confirm-evaluate (lang body)
(and (not (string= lang "js"))
(not (string= lang "dot"))
(not (string= lang "python"))))
(setq org-confirm-babel-evaluate 'my-org-confirm-evaluate)
Here are my global src
block headers. So far, all this does is
ensure that the publishing process never executes the code in src
block (unless it’s overrided at a lower lever of course).
(setq org-babel-default-header-args
(cons '(:eval . "never-export")
(assq-delete-all :eval org-babel-default-header-args)))
These are the tags that I will use the most when creating new tasks.
(cond
((string-equal system-type "windows-nt")
(progn
;; Work-related tags
(setq org-tag-alist '(
("c_admin" . ?a)
("c_coding" . ?c)
("c_documentation" . ?d)
("goal" . ?g)
("c_hardware_troubleshooting" . ?h)
("c_training" . ?i)
("c_knowledge_transfer" . ?k)
("c_manual_testing" . ?m)
("c_monitoring" . ?n)
("c_meetings" . ?e)
("objective" . ?o)
("c_hr" . ?r)
("c_agile_process_stuff" . ?s)
("today" . ?t)
("c_system_maintenance" . ?z)))))
((string-equal system-type "gnu/linux")
(progn
(setq org-tag-alist '(
("c_bills" . ?b)
("c_chore" . ?c)
("c_errand" . ?e)
("c_self_care" . ?s)
("today" . ?t))))))
Here’s the tags that I exclude from tag inheritance:
(setq org-tags-exclude-from-inheritance (quote ("crypt")))
Of course you need these 😄
(use-package org-bullets
:ensure t
:init
(add-hook 'org-mode-hook (lambda () (org-bullets-mode 1))))
This turns on inline images at startup:
(setq org-startup-with-inline-images t)
… and this scales them down when viewing them inline:
(setq org-image-actual-width t)
This seems like a promising way to keep track of what I do throughout the day.
(use-package org-journal
:ensure t
:init
(setq org-journal-dir (concat org-directory "journal"))
(setq org-journal-date-format "%A, %d %B %Y")
(setq org-journal-file-format "%Y%m%d.org"))
UGH
Here’s my list of properties that can be inherited. I like to keep this small so as not to adversely affect the speed of agenda searches.
(setq org-use-property-inheritance
(list "FEATURE_NUM"
"STORY_NUM"))
This seems to be the best way to implement a Zettelkasten system with Emacs.
(use-package deft
:ensure t
:init
(setq deft-extensions '("org" "md" "txt")
deft-use-filename-as-title t)
(setq deft-directory (concat org-directory "/zd")))
(use-package zetteldeft
:ensure t
:after deft
:init
(setq zetteldeft-link-indicator "§"
zetteldeft-id-format "%Y-%m-%d-%H%M"
zetteldeft-id-regex "[0-9]\\{4\\}\\(-[0-9]\\{2,\\}\\)\\{3\\}"
zetteldeft-tag-regex "[#@][a-z-]+")
:config (zetteldeft-set-classic-keybindings))
First, install magit:
Note: There might be an issue with putting defer
and bind
in the same
use-package
statement. So if things get super crazy consider that.
(use-package magit
:ensure t
:defer 120
:bind ("C-c m s" . magit-mode))
I’m currently stuck in dependency hell here and the old version of magit doesn’t work so I’m just going to comment all of this out.
(cond
((string-equal system-type "windows-nt")
(progn
(add-to-list 'exec-path "c:/Program Files/Git/bin")
)))
Pushing to an SSH repo using Windows is a bit tricky. Here’s what I did to make it work:
- Install the regular Git package.
- Install the PuTTY tools, including
pageant
andplink
. - Manage your SSH keys using
pageant
- Ideally, load your git-related keys on Windows startup.
After all of that I only needed the following config:
(cond
((string-equal system-type "windows-nt")
(progn
(setenv "SSH_ASKPASS" "git-gui--askpass")
(setenv "GIT_SSH" "C:/Program Files/PuTTY/plink.exe"))))
I nee to copy some environment variables from my shell in order to use
ssh-agent
. Please note that this also makes everything else (including
rsync-dired
) work with ssh-agent
too.
TODO - Install this automatically
(cond
((string-equal system-type "gnu/linux")
(progn
(require 'exec-path-from-shell)
(exec-path-from-shell-copy-env "SSH_AGENT_PID")
(exec-path-from-shell-copy-env "SSH_AUTH_SOCK")
)))
I like having my own custom keymap for Magit.
(progn
(define-prefix-command 'tp/magit/key-map)
(define-key tp/magit/key-map (kbd "s") 'magit-status)
(define-key tp/magit/key-map (kbd "b") 'magit-branch-popup)
(define-key tp/magit/key-map (kbd "c") 'magit-checkout)
(define-key tp/magit/key-map (kbd "d") 'magit-diff-popup)
;; Show the git log for the current file.
(define-key tp/magit/key-map (kbd "l") 'magit-log-buffer-file))
(global-set-key (kbd "\C-cm") tp/magit/key-map)
I’m also already using C-x gg
as a shortcut to jump to the top of a buffer, so
I’m not a huge fan of Magit using C-x g
to run magit-status
. So let’s nuke
that:
(global-unset-key (kbd "C-x g"))
This is the package that auto-completes file names when you press C-x C-f
.
(ido-mode 1)
(ido-everywhere 1)
This package is a lot like ido-ubiquitous but it autocompletes values
when you press M-x
:
(use-package smex
:ensure t
:config
(smex-initialize)
;; :bind (("M-x" . smex)
;; ("M-X" . smex-major-mode-commands)
;; ("C-c C-c M-x" . 'execute-extended-command))
)
Since I started using helm
I don’t think Smex does anything any more,
but I’m afraid to delete it at this point :-)
Use helm
for M-x
function searching:
(use-package helm
:ensure t
:bind (("M-x" . helm-M-x)
("C-x b" . helm-mini)
("C-c x" . helm-all-mark-rings)))
(defvar current-date-time-format "%a %b %d %H:%M:%S %Z %Y"
"Format of date to insert with `insert-current-date-time' func
See help of `format-time-string' for possible replacements")
(defvar current-date-format-for-org "** %m/%d/%Y"
"Format of date to insert with `insert-current-date' func for org files.
See help of `format-time-string' for possible replacements")
(defvar current-date-format-for-links "%m-%d-%Y"
"This format works better for HTML links than the org format.")
(defvar current-date-format "%m/%d/%Y"
"Format of date to insert with `insert-current-date' func.
Note the weekly scope of the command's precision.")
(defvar current-time-format-for-org "*** %H:%M"
"Format of date to insert with `insert-current-time' func for org files.
Note the weekly scope of the command's precision.")
(defvar current-time-format "%H:%M:%S"
"Format of date to insert with `insert-current-time' func.
Note the weekly scope of the command's precision.")
(defvar current-time-format-no-delim "%H%M%S"
"Format of date with no delimiters.")
(defun insert-current-date-for-org ()
"insert the current date as a heading into an org file.
Uses `current-date-time-format' for the formatting the date/time."
(interactive)
(insert (format-time-string current-date-format-for-org (current-time)))
(insert "\n")
)
(defun insert-current-date-for-links ()
"Insert the current date in a way that works in HTML
links."
(interactive)
(insert (format-time-string current-date-format-for-links (current-time)))
)
(defun get-current-date-for-links ()
"Retrieves the current date in a way that works in HTML
links."
(interactive)
(format-time-string current-date-format-for-links (current-time))
)
(defun insert-current-date ()
"insert the current date into current buffer.
Uses `current-date-time-format' for the formatting the date/time."
(interactive)
(insert (format-time-string current-date-format (current-time)))
)
(defun get-current-date ()
"Returns the current date. Uses `current-date-time-format` for the formatting of the date/time"
(interactive)
(format-time-string current-date-format (current-time)))
(defun insert-current-time-for-org ()
"insert the current time as a heading into an org file."
(interactive)
(insert (format-time-string current-time-format-for-org (current-time)))
(insert "\n")
)
(defun insert-new-day-headings ()
"insert the 'new day' heading into an org file"
(interactive)
(insert-current-date-for-org)
(insert "\n")
(insert-current-time-for-org)
(insert "\n")
)
(defun insert-current-date-time ()
"insert the current date and time into current buffer.
Uses `current-date-time-format' for the formatting the date/time."
(interactive)
(insert "==========\n")
; (insert (let () (comment-start)))
(insert (format-time-string current-date-time-format (current-time)))
(insert "\n")
)
(defun insert-current-time ()
"insert the current time (1-week scope) into the current buffer."
(interactive)
(insert (format-time-string current-time-format (current-time)))
)
(defun get-current-time ()
"Returns the current time (1-week scope).."
(interactive)
(format-time-string current-time-format (current-time)))
(defun get-current-time-no-delim ()
"Returns the current time with no delimiters."
(interactive)
(format-time-string current-time-format-no-delim (current-time)))
(global-set-key "\C-c\C-d" 'insert-current-date-time)
(global-set-key "\C-c\C-t" 'insert-current-time)
Here’s some of the keystrokes from Vim that I still like to use.
This emulates Vim’s “gg top” mnemonic:
(global-set-key (kbd "C-x gg") 'beginning-of-buffer)
(global-set-key (kbd "C-x G") 'end-of-buffer)
(use-package rainbow-delimiters
:ensure t
:hook (prog-mode . rainbow-delimiters-mode))
Flycheck relies on external programs to analyze your code. Here’s what you need to install for your favorite programming languages:
- Python
- pylint
- Bash
- shellcheck
(use-package flycheck
:disabled
:hook (after-init . global-flycheck-mode)
)
Projectile is a fantastic package that makes it easier to work within a project using Emacs.
I’m not a huge fan of it’s built-in prefix though so let’s fix that:
(use-package projectile
:ensure t
:init
(setq projectile-keymap-prefix (kbd "C-c p"))
:bind-keymap
("C-c p" . projectile-mode)
:config
(setq projectile-globally-ignored-directories
(append '(".git" ".pytest_cache" ".vscode" "Output" "venv" "venv3" "node_modules")))
(setq projectile-globally-ignored-files
(append '("*~" "*#" "log.html" "output.xml" "report.html")))
)
(use-package helm-projectile
:ensure t
:hook projectile-mode
:config
(setq projectile-completion-system 'helm)
(helm-projectile-on))
This turns off tabs and replaces them with 4 spaces for most major modes:
(setq-default c-basic-offset 4)
(setq-default indent-tabs-mode nil)
(global-hl-line-mode)
(use-package powershell
:ensure t
:config
(autoload 'powershell "powershell" "Run powershell as a shell within emacs." t)
)
(add-hook 'robot-mode-hook
(lambda () (local-set-key (kbd "<f5>") #'robot-mode-find-kw)))
(add-hook 'robot-mode-hook 'tp/file/remove-dos-eol)
Let’s just turn it on for everything 😄
(use-package paredit
:ensure t
:hook ((emacs-lisp-mode . enable-paredit-mode)
(eval-expression-minibuffer-setup . enable-paredit-mode)
(ielm-mode . enable-paredit-mode)
(lisp-mode . enable-paredit-mode)
(lisp-interaction-mode . enable-paredit-mode)
(scheme-mode . enable-paredit-mode)))
Holy crap is this cool, and it even works on Windows. If only I could install it from Melpa :-)
(use-package aweshell
:load-path "customizations/packages/aweshell"
:defer t)
These customizations make it easier to know where code blocks are.
(show-paren-mode 1)
This seemed like a good idea but caused lots and lots of weirdness that kept me from closing Emacs.
;; (defun eval-emacs-lisp-buffer ()
;; "Eval a buffer if it's major mode is emacs-lisp."
;; (when (eq major-mode 'elisp-mode)
;; (eval-buffer)))
;; (add-hook 'after-save-hook 'eval-buffer)
Yet another package that we can’t install from melpa.
(cond
((string-equal system-type "windows-nt")
(progn
(require 'autoit-mode)
(add-to-list 'auto-mode-alist '("\\.au3\\'" . autoit-mode)))))
web-server is a great module that can interpret elisp or just serve up static files (which is how I use it). For me it provides a really easy way viewing HTML files in a browser in a “real” way.
(use-package web-server
:ensure t
:defer t)
This function starts a server on port 9003 that serves up static content that’s located in the PWD (which is also your DOCROOT).
(defun tp/httpd/start-server-in-pwd ()
(interactive)
(setq httpd-port 8001)
(setq httpd-root default-directory)
(httpd-start)
(message "Serving up files on port 8001."))
web-mode is awesome!
(use-package web-mode
:ensure t
:config
(add-to-list 'auto-mode-alist '("\\.html?\\'" . web-mode)))
(use-package pip-requirements
:ensure t)
Let’s see if this works better for me than regular old python-mode
:
(use-package elpy
:ensure t
:mode ("\\.py\\'" . python-mode)
:init
(add-hook 'python-mode-hook #'elpy-enable)
:config
;; (setq python-shell-interpreter "jupyter"
;; python-shell-interpreter-args "console --simple-prompt"
;; python-shell-prompt-detect-failure-warning nil)
;; (add-to-list 'python-shell-completion-native-disabled-interpreters
;; "jupyter")
)
I turned off the jupyter stuff because a) it wasn’t really helping me and b) I’m having issues using it on Nixos that I’m sure are just user error.
Apparently I need all of these :-/
(use-package py-autopep8
:ensure t
:hook (elpy-mode . py-autopep8-enable-on-save))
(use-package blacken
:ensure t)
This looks kindof cool
(use-package ein
:ensure t)
Let’s add support for Dockerfiles!
(use-package dockerfile-mode
:ensure t
:init
(add-to-list 'auto-mode-alist '("Dockerfile\\'" . dockerfile-mode)))
Also, the docker porcelain is pretty freakin’ sweet:
(use-package docker
:ensure t
)
This a Stack Exchange browser for Emacs. As of today (3/20/2019) the version in MELPA stable has a pretty major bug in it so I’m using HEAD from Github:
(use-package sx-load
:disabled
:load-path "customizations/packages/sx.el")
(use-package slime
:ensure t
:mode "\\.cl\\'"
:init
(cond
((string-equal system-type "windows-nt")
(progn
(setq inferior-lisp-program "c:/who/knows")))
((string-equal system-type "gnu/linux")
(progn
(setq inferior-lisp-program "/usr/bin/sbcl")))))
This is a fantastic package for interacting with REST endpoints in an interactive way.
This also looks very promising. It integrates with org-mode.
(use-package verb
:ensure t
:after org
:config (define-key org-mode-map (kbd "C-c C-r") verb-command-map))
(use-package yaml-mode
:ensure t
:init
(add-to-list 'auto-mode-alist '("\\.yml\\'" . yaml-mode)))
This is a great shell
mode helper that gives you a bunch of extras:
(use-package shx
:ensure t
:config
(shx-global-mode))
This gives you bash completion when using shell mode.
(use-package bash-completion
:ensure t
:config
(progn
(autoload 'bash-completion-dynamic-complete
"bash-completion"
"BASH completion hook")
(add-hook 'shell-dynamic-complete-functions
'bash-completion-dynamic-complete)))
(use-package cider
:ensure t)
(use-package nix-mode
:ensure t)
The ack
Emacs plugin looked sweet but I couldn’t get it to work
on Windows :-( Luckily the Silver Searcher worked!
Here’s the basics:
(use-package ag
:ensure t)
(use-package helm-swoop
:ensure t)
I thought it would be nice to access the ag-*
functions using a
Ctrl-c f
prefix, and the code below does exactly that (thanks to
Xah Lee once again).
I also added a few helm-swoop
shortcuts since that’s also an
excellent tool for searching files.
(progn
(define-prefix-command 'tp/find/ag/key-map)
; Find a file in the current project
(define-key tp/find/ag/key-map (kbd "p") 'projectile-ag)
; Find in the current buffer.
(define-key tp/find/ag/key-map (kbd "b") 'helm-swoop)
; Find using all open buffers
(define-key tp/find/ag/key-map (kbd "o") 'helm-org-rifle)
; Search all of your org buffers
(define-key tp/find/ag/key-map (kbd "r") 'helm-org-rifle)
; And if you didn't trust any of these, try plain-old ag :-)
(define-key tp/find/ag/key-map (kbd "a") 'ag)
)
(global-set-key (kbd "\C-cf") tp/find/ag/key-map)
Why not? It looks so cool.
(use-package wgrep
:ensure t)
Also, to be able to use this with ag I need to install the following:
(use-package wgrep-ag
:ensure t)
The killer feather here is using Swiper instead of incremental search when hitting C-s:
(use-package swiper
:ensure t
:config
(progn
(ivy-mode 1)
(setq ivy-use-virtual-buffers t)
(setq enable-recursive-minibuffers t)
(global-set-key "\C-s" 'swiper)
(global-set-key (kbd "C-c C-r") 'ivy-resume)
(global-set-key (kbd "<f6>") 'ivy-resume)
(define-key minibuffer-local-map (kbd "C-r") 'counsel-minibuffer-history)))
This is pretty cool and handy when performing word searches across all of your open org buffers.
(use-package helm-org-rifle
:ensure t)
This is a great package for comparing syncthing conflicts:
(use-package emacs-conflict
:load-path "customizations/packages/emacs-conflicts"
:bind
(("C-c r r" . emacs-conflict-resolve-conflicts)))
If at all possible I prefer to splitt my diff windows horizontally:
(setq ediff-split-window-function (quote split-window-horizontally))
(set-register ?w (cons 'file (concat org-directory "/WorkLogs.org")))
(set-register ?i (cons 'file (concat org-directory "/index.org")))
(set-register ?m (cons 'file (concat org-directory "/MeetingMinutes.org")))
(set-register ?v (cons 'file (concat org-directory "/Personal_Reviews.org")))
(set-register ?j (cons 'file (concat org-directory "/journal/" (format-time-string "%Y%m%d") ".org")))
(cond
((string-equal system-type "windows-nt")
(progn
(set-register ?p (cons 'file "c:/tools/cmder/config/user-profile.ps1"))
(set-register ?g (cons 'file "c:/users/tom.purl/.gitconfig"))
(set-register ?r (cons 'file "c:/users/tom.purl/git/braindump/index.org"))))
((string-equal system-type "gnu/linux")
(progn
(set-register ?g (cons 'file "~/.gitconfig"))
(set-register ?r (cons 'file "~/gtd/kata-blog/index.org"))))
)
(set-register ?e (cons 'file "~/.emacs.d/emacs-init.org"))
(use-package logview
:disabled
:ensure t
)
Make eww
create a new buffer if executed from a non-=eww= buffer. This allows you to
easily create more than one eww
buffer. Also, I copied this from
https://emacs.stackexchange.com/a/24477/8228, which was copied from Xah’s erogemacs tips
(like a lot of stuff in this file).
;; Auto-rename new eww buffers
(defun xah-rename-eww-hook ()
"Rename eww browser's buffer so sites open in new page."
(rename-buffer "eww" t))
(add-hook 'eww-mode-hook #'xah-rename-eww-hook)
Also stole from EOS:
(defun eos/core/save-persistent-scratch ()
"Write the contents of *scratch* to the file name
`persistent-scratch-file-name'."
(with-current-buffer (get-buffer-create "*scratch*")
(write-region (point-min) (point-max) "~/.emacs.d/persistent-scratch")))
(defun eos/core/load-persistent-scratch ()
"Load the contents of `persistent-scratch-file-name' into the
scratch buffer, clearing its contents first."
(interactive)
(if (file-exists-p "~/.emacs.d/persistent-scratch")
(with-current-buffer (get-buffer "*scratch*")
(delete-region (point-min) (point-max))
(insert-file-contents "~/.emacs.d/persistent-scratch"))))
(add-hook 'after-init-hook 'eos/core/load-persistent-scratch)
(add-hook 'kill-emacs-hook 'eos/core/save-persistent-scratch)
I like to sync some of my files using Syncthing. The problem is when I do the following:
- Edit a file on my laptop and save and sync without killing the buffer.
- Edit the same file on my phone using Orgzly and sync.
- Sync everything on my laptop and visit the same buffer in Emacs.
At this point I would be looking at the version of the file from step 1 on my laptop. To view the step 2 updates I would need to manually revert the buffer, and chances are I wouldn’t know which buffers to revert.
I therefore am turning on global-auto-revert-mode
to see if that helps.
(global-auto-revert-mode 1)
First, let’s install the mode:
(use-package markdown-mode
:mode "\\.md\\'"
:ensure t)
I just love this, it was stupid simple to write and I think I use it a least 10 times a day. It “moves” the current window into a new frame.
What does that mean? Let’s say you split your current window (which is called a frame
in Emacs) into 2 using Ctrl-3
or something like that and then realize that you would
really like to focus on the buffer in that “split” (which is called a window in
Emacs). Wouldn’t it be great if you could just move it to a new frame?
(defun tp/wm/move-window-to-new-frame ()
"Take the content of the current window and move it to its own
frame"
(interactive)
(make-frame)
(delete-window))
It’s kindof like tmux for Emacs but it doesn’t do quite as much.
(use-package eyebrowse
:ensure t
:config
(validate-setq eyebrowse-mode-line-separator " "
eyebrowse-new-workspace t)
(eyebrowse-mode t))
This includes all kinds of cool stuff:
(if (not (require 'dired-narrow nil t))
(message "Package `dired-narrow' not found"))
(if (not (require 'dired-subtree nil t))
(message "Package `dired-subtree' not found")
(bind-key "<tab>" #'dired-subtree-toggle dired-mode-map)
(bind-key "<backtab>" #'dired-subtree-cycle dired-mode-map))
This only works on a system with find
installed. It asks you for a directory and
a search string, finds the files, and displays them in an editable dired
buffer. It’s pretty freakin’ sweet and so handy.
(defun tp/dired/find-files-in-dired-and-edit ()
(interactive)
(find-name-dired
(read-directory-name "Directory: ")
(read-string "Search string: "))
(wdired-change-to-wdired-mode))
I’m using the techniques from this video to “narrow” or filter the results of a dired buffer:
I’m having lots of issues with this and will try to fix it later using
dired-git
.
(add-hook 'dired
(lambda ()
(local-set-key (kbd "C-c n s") #'dired-narrow-regexp)))
This is a really good way of copying files remotely in an asynchronous way.
(use-package dired-rsync
:ensure t
:config
(bind-key "C-c C-r" 'dired-rsync dired-mode-map))
I don’t like seeing all of the temp files in dired
, so dired-x
to the rescue!
(require 'dired-x)
(add-hook 'dired-mode-hook
(lambda ()
;; Set dired-x buffer-local variables here. For example:
(dired-omit-mode 1)))
First let’s set the keystrokes:
(global-set-key (kbd "C-x C-b") 'ibuffer) ;; Use Ibuffer for Buffer List
Next let’s group buffers:
(setq ibuffer-saved-filter-groups
'(("home"
("emacs-config" (filename . "emacs-init.org"))
("Org" (or (mode . org-mode)
(filename . "OrgMode")
(name . "\*Org Agenda\*")))
("Dired" (or (mode . dired-mode)
(name . "\*Sunrise\*")))
("Dev" (or (mode . python-mode)
(mode . robot-mode)))
("Magit" (or (name . "\*magit")
(name . "magit")
(mode . magit-mode)))
("EXWM" (or (mode . exwm-mode)
(name . "\*EXWM\*")))
("Shells" (or (mode . eshell-mode)
(mode . shell-mode)
(mode . comint-mode))))
("eww" (or (mode . eww-mode)
(mode . eww-bookmark-mode)))
("Help" (or (name . "\*Help\*")
(name . "\*Apropos\*")
(name . "\*info\*")))))
(add-hook 'ibuffer-mode-hook
'(lambda ()
(ibuffer-switch-to-saved-filter-groups "home")))
(use-package burly
:quelpa (burly :fetcher github :repo "alphapapa/burly.el"))
This is a super sweet package:
(use-package ox-hugo
:ensure t
:after
ox)
This is Emac’s built-in interface GPG that I like to use to transparently encrypt entire files. When you use it you should put something like this at the top of your file:
# -*- mode:org; epa-file-encrypt-to: ("[email protected]") -*-
You can replace the email address with the public key’s id.
(require 'epa-file)
(epa-file-enable)
(setq epa-pinentry-mode 'loopback)
I hate to admit it but my current process for whole-file encryption goes like this:
- I add a line that looks something like this to the top of my file:
# -*- mode:org; epa-file-encrypt-to: ("5BF5A514D04978DD") -*-
- I then drop into the command line and run a command that looks something like
this:
- =gpg –output foo.org.gpg –encrypt –recipient 5BF5A514D04978DD foo.org
- I then test that I can open
foo.org.gpg
in Emacs seamlessly.
This makes it possible to use pinentry
from exwm:
(use-package pinentry
:ensure t
:config
(pinentry-start))
I use this to encrypt sections of org documents. You just have to tag the section
with crypt
.
(require 'org-crypt)
(org-crypt-use-before-save-magic)
(cond
((string-equal system-type "windows-nt")
(progn
(setq org-crypt-key "989889BA8447C29C")))
((string-equal system-type "gnu/linux")
(progn
(setq org-crypt-key "5BF5A514D04978DD"))))
Chronos seems to do this really well, but unfortunately it isn’t available (as of 2/4/19) in Melpa Stable. So you’ll first want to download it and then do this:
(require 'chronos)
This is definitely a work in progress :-)
(cond
((string-equal system-type "windows-nt")
(progn
(setq chronos-shell-notify-program "c:/users/tom.purl/AppData/Roaming/Documents/td/apps/snarl 5.0/tools/heysnarl"
chronos-shell-notify-parameters '("notify?text=Important!&priority=1")
chronos-expiry-functions '(chronos-buffer-notify
chronos-shell-notify)))))
ace-window
works well for this.
(use-package ace-window
:ensure t)
(global-set-key (kbd "C-]") 'ace-window)
For god’s sake, please don’t beep.
(setq ring-bell-function (lambda ()))
try
is kindof fun:
(use-package try
:ensure t)
Because why not?
;; (use-package symon
;; :ensure t)
I need this for orq-ql
:
(use-package peg
:ensure t)
Since I run Emacs as a user service it is unceremoniously killed every time I log out of a session. My bookmarks are therefore never saved. This fixes that by saving my bookmarks every time I change one.
(setq bookmark-save-flag 1)
This is a nice little function that “de-indents” you back to the first column in a line:
(defun tp/backward-kill-line (arg)
"Kill ARG lines backward."
(interactive "p")
(kill-line (- 1 arg)))
(global-set-key [M-delete] 'scratch/backward-kill-line)
(global-set-key [M-backspace] 'scratch/backward-kill-line)
(require 'server)
;; Start a server if (server-running-p) does not return t (e.g. if it
;; returns nil or :other)
(or (eq (server-running-p) t)
(server-start))
(when (equal window-system 'w32)
(setq server-use-tcp t))
(with-eval-after-load 'server
(when (equal window-system 'w32)
;; Suppress error "directory ~/.emacs.d/server is unsafe". It is needed
;; needed for the server to start on Windows.
(defun server-ensure-safe-dir (dir) "Noop" t)))
nov
looks like a pretty cool epub reader:
(use-package nov
:ensure t
:config
(add-to-list 'auto-mode-alist '("\\.epub\\'" . nov-mode)))
I’d love to be able to transparently annotate EPUB and PDF files using
Emacs. org-noter
looks like a good way to do this:
(use-package org-noter
:ensure t)
This is a lot like top
but managed using normal emacs conventions.
(use-package helm-proc
:ensure t)
This looks really very cool:
(use-package bongo
:ensure t)
It’s a royal pain in a shell script to loop over a list of files using the shell, so here’s what I do instead.
find . -name "*flac*" > flac.sh
- Add a shebang and
set -e
to the top offlac.sh
- Execute this macro on every line after positioning the cursor in the first column.
(fset 'tp/mm/flac2mp3
(lambda (&optional arg)
"Keyboard macro."
(interactive "p")
(kmacro-exec-ring-item
(quote ([67108896 5 134217847 1 102 102 109 112 101 103 32 45 105 32 34 5 34 32 45 97 98 32 51 50 48 107 32 45 109 97 112 95 109 101 116 97 100 97 116 97 32 48 32 45 105 100 118 backspace 51 118 50 95 118 101 114 115 105 111 110 32 51 32 34 25 backspace backspace backspace backspace 109 112 51 34 14 1] 0 "%d")) arg)))