Skip to content

EAsencios/emacs-config

 
 

Repository files navigation

Paf’s portable Emacs configuration

This is my Emacs config. You need to tangle this into a file that then gets loaded by Emacs: C-c C-v t [org-babel-tangle]. Below, I also explain how this tangling is automated.

Find extensive documentation about how to do this here.

Personal Plans

I regularly try out new packages, this is my current list of things being evaluated. They usually live temporarily in my ~/.emacs until I am happy, in which case I move their config into this file so that it gets replicated on all machines I work on with Emacs.

Currently under review

Installed, but need no or external config

One-time Initial Setup

I have my config in directory ~/Emacs which is where I clone this repository. The config setup is maintained purely in the ~/Emacs/emacs_setup.org file.

In your ~/.emacs file, all you need to add is

;; Loads PAF's emacs setup with bootstrap
(load-file "~/Emacs/emacs_setup.el")

Bootstrap

Initially when cloning this repository, you have the emacs_setup.org file, that contains the config that you adapt to your specific setup, and an emacs_setup.el with a bootstrap content that will tangle and compile the org file, and replace itself. This is useful the very first time.

After that, the config itself should have the hook to re-tangle and re-compile the setup at each save.

Therefore my setup is very easy to install, and it needs these steps:

  1. clone this repo into ~/Emacs
  2. add the one line in you ~/.emacs
  3. make sure Emacs re-interprets its init (you could restart it)

It may be that use-package is not installed on your setup, so it will first try to install that. After that step, it will also start installing any package that is marked as needed in this config automatically.

The original content of the emacs_setup.el is as follows:

;; This is the initial state of the file to be loaded.
;; It will replace itself with the actual configuration at first run.

(require 'org) ; We can't tangle without org!

(setq config_base (expand-file-name "emacs_setup"
				    (file-name-directory
				     (or load-file-name buffer-file-name))))
(find-file (concat config_base ".org"))        ; Open the configuration
(org-babel-tangle)                             ; tangle it
(load-file (concat config_base ".el"))         ; load it
(byte-compile-file (concat config_base ".el")) ; finally byte-compile it

One-time configure

To preserve the original state of this file when updating the git repos with new config settings, execute the following block once (C-c C-c):

#!/bin/bash

# Make git ignore the tangled & updated emacs_setup.el
GIT_ROOT=$(dirname $0)
(cd ${GIT_ROOT} && git update-index --skip-worktree emacs_setup.el)

# Maybe this is a new install, .emacs does not exist
test -e ~/.emacs || touch ~/.emacs

# Add the load-file as the first thing in the user's ~/.emacs
declare lines=$(grep emacs_setup ~/.emacs | wc -l)
if (( lines < 1 )); then
  echo "Added loading the config in your ~/.emacs"
  cat > ~/.emacs.new <<EOF
<<emacs_bootstrap>>

EOF
  cat ~/.emacs >> ~/.emacs.new
  mv ~/.emacs.new ~/.emacs
else
  echo "Config in your ~/.emacs already set up!"
fi

Recompile all packages

This will force-recompile everything in ~/.emacs.d/elpa/… Just run M-: and then enter this:

(byte-recompile-directory package-user-dir nil 'force)

or simply C-x C-e at the end of that line.

Initialize Emacs

This section sets up Emacs so it can tangle the config, find use-package, and find the ELPA repositories where to get the new packes from.

Info header

Just to add a little information in the tangled file.

;; ===== this file was auto-tangled, only edit the emacs_setup.org =====

melpa

Make sure we have the package system initialized before we load anything.

(require 'package)
(package-initialize)

Adding my choice of packages repositories. #+NAME melpa-setup

(setq package-archives '(("org" . "https://orgmode.org/elpa/")
                         ("melpa" . "https://stable.melpa.org/packages/")
                         ; ("melpa" . "https://melpa.org/packages/")
                         ("gnu" . "https://elpa.gnu.org/packages/")
                         ; ("marmalade" . "https://marmalade-repo.org/packages/")
                        ))

use-package

I use use-package for most configuration, and that needs to be at the top of the file. use-package verifies the presence of the requested package, otherwise installs it, and presents convenient sections for configs of variables, key bindings etc. that happen only if the package is actually loaded.

First, make sure it gets installed if it is not there yet.

;; make sure use-package is installed
(unless (package-installed-p 'use-package)
  (unless package-archive-contents
    (package-refresh-contents))
  (package-install 'use-package))
(eval-when-compile (require 'use-package))

tangle-this-config

I set this up to tangle the init org-mode file into the actual Emacs init file as soon as I save it.

(defun tangle-init ()
  "If the current buffer is 'init.org' the code-blocks are
tangled, and the tangled file is compiled."
  (when (equal (buffer-file-name)
               (expand-file-name "~/Emacs/emacs_setup.org"))
    ;; Avoid running hooks when tangling.
    (let ((prog-mode-hook nil))
      (org-babel-tangle)
      (byte-compile-file "~/Emacs/emacs_setup.el"))))

(add-hook 'after-save-hook 'tangle-init)

Personal Initialization

Clear C-p so I can use it as a prefix

Remove C-p that I want to use for me personally as a prefix.

(global-set-key (kbd "C-p") nil) ;; was 'previous-line'

Environment

add-hook-run-once

Use instead of add-hook to run it a single time. found here

(defmacro add-hook-run-once (hook function &optional append local)
  "Like add-hook, but remove the hook after it is called"
  (let ((sym (make-symbol "#once")))
    `(progn
       (defun ,sym ()
         (remove-hook ,hook ',sym ,local)
         (funcall ,function))
       (add-hook ,hook ',sym ,append ,local))))

Browser default

(setq browse-url-generic-program (executable-find "google-chrome")
  browse-url-browser-function 'browse-url-generic)

Setup server

Start the background server, so we can use emacsclient.

(server-start)

UTF-8

Make Emacs request UTF-8 first when pasting stuff.

(use-package unicode-escape
  :ensure t
  :init
  (setq x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING)))
(set-language-environment "UTF-8")

Newline (only Unix wanted)

This should automatically convert any files with dos or Mac line endings into Unix style ones. Code found here.

(defun no-junk-please-we-are-unixish ()
  (let ((coding-str (symbol-name buffer-file-coding-system)))
    (when (string-match "-\\(?:dos\\|mac\\)$" coding-str)
      (set-buffer-file-coding-system 'unix))))

(add-hook 'find-file-hooks 'no-junk-please-we-are-unixish)

Theme

I really like the high-contract Zenburn theme.

(use-package zenburn-theme
 :ensure t)

Buffer behavior

Use auto-revert, which reloads a file if it’s updated on disk and not modified in the buffer.

(global-auto-revert-mode 1)
(put 'upcase-region 'disabled nil)
(put 'narrow-to-region 'disabled nil)

Managing Buffers

winner-mode (layout managing)

Enables winner-mode. Navigate buffer-window configs with C-c left and C-c right.

(winner-mode 1)

eyebrowse (layout managing)

This is supposed to be a better window manager.

(use-package eyebrowse
  :ensure t)

toggle-maximize-buffer

Temporarily maximize a buffer. found here

(defun toggle-maximize-buffer () "Maximize buffer"
  (interactive)
  (if (= 1 (length (window-list)))
      (jump-to-register '_)
    (progn
      (window-configuration-to-register '_)
      (delete-other-windows))))

Map it to a key.

(global-set-key [M-f8] 'toggle-maximize-buffer)

Colors and Look

Fontlock

This gets the font coloring switched on for all buffers.

Note: this should be the default, maybe this can go ?

  • State “TODO” from [2018-11-07 Wed 22:29]
(global-font-lock-mode t)

In terminal mode

(when (display-graphic-p)
  (set-background-color "#ffffff")
  (set-foreground-color "#141312"))

In X11 mode: mouse and window title

(setq frame-title-format "emacs @ %b - %f")
(when window-system
  (mwheel-install)  ;; enable wheelmouse support by default
  (set-selection-coding-system 'compound-text-with-extensions))

Look: buffer naming

(use-package uniquify
  :init
  (setq uniquify-buffer-name-style 'post-forward-angle-brackets))

Buffer Decorations

Setup the visual cues about the current editing buffer

(column-number-mode 1)
(setq visible-bell t)
(setq scroll-step 1)
(setq-default transient-mark-mode t)  ;; highlight selection

nyan-mode

(use-package nyan-mode
  :ensure t
  :bind ("C-p n" . 'nyan-mode))

dynamic cursor colors

The cursor is displayed in different colors, depending on overwrite or insert mode.

(setq hcz-set-cursor-color-color "")
(setq hcz-set-cursor-color-buffer "")

(defun hcz-set-cursor-color-according-to-mode ()
  "change cursor color according to some minor modes."
  ;; set-cursor-color is somewhat costly, so we only call it when needed:
  (let ((color
         (if buffer-read-only "orange"
           (if overwrite-mode "red"
             "green"))))
    (unless (and
             (string= color hcz-set-cursor-color-color)
             (string= (buffer-name) hcz-set-cursor-color-buffer))
      (set-cursor-color (setq hcz-set-cursor-color-color color))
      (setq hcz-set-cursor-color-buffer (buffer-name)))))

(add-hook 'post-command-hook 'hcz-set-cursor-color-according-to-mode)

Key Mappings

alternate key mappings

Letting one enter chars that are otherwise difficult in e.g. the minibuffer.

(global-set-key (kbd "C-m") 'newline-and-indent)
(global-set-key (kbd "C-j") 'newline)
(global-set-key [delete] 'delete-char)
(global-set-key [kp-delete] 'delete-char)

Macros

(global-set-key [f3] 'start-kbd-macro)
(global-set-key [f4] 'end-kbd-macro)
(global-set-key [f5] 'call-last-kbd-macro)

Text size

Increase/decrease text size

(define-key global-map (kbd "C-+") 'text-scale-increase)
(define-key global-map (kbd "C--") 'text-scale-decrease)

multiple regions

(global-set-key (kbd "C-M-i") 'iedit-mode)

Moving around buffers

(global-set-key (kbd "C-c <C-left>")  'windmove-left)
(global-set-key (kbd "C-c <C-right>") 'windmove-right)
(global-set-key (kbd "C-c <C-up>")    'windmove-up)
(global-set-key (kbd "C-c <C-down>")  'windmove-down)
(global-set-key (kbd "C-c C-g") 'goto-line)

multiple-cursors

Configure the shortcuts for multiple cursors

(use-package multiple-cursors
  :ensure t
  :bind (("C-S-c C-S-c" . 'mc/edit-lines)
         ("C->" . 'mc/mark-next-like-this)
         ("C-<" . 'mc/mark-previous-like-this)
         ("C-c C->" . 'mc/mark-all-like-this)))

ace-jump-mode

Let’s one jump around text

(use-package ace-jump-mode
  :ensure t
  :bind (("C-c C-SPC" . 'ace-jump-mode)
         ("C-c C-DEL" . 'ace-jump-mode-pop-mark)))

Editing Style

No tabs, ever. No trailing spaces either.

(setq-default indent-tabs-mode nil)
(setq require-final-newline t)
(setq next-line-add-newlines nil)
(add-hook 'before-save-hook 'delete-trailing-whitespace)

Mark the 80 cols boundary

(use-package column-marker
  :load-path "~/Emacs"
  :config
  (add-hook 'c-mode-common-hook (lambda () (interactive) (column-marker-1 80)))
  :bind ("C-c m" . 'column-marker-1))

Better kill ring

Seen demonstrated by Uncle Dave

(use-package popup-kill-ring
  :ensure t
  :bind ("M-y" . popup-kill-ring))

Better writing

This should highlight bad style in writing.

(use-package artbollocks-mode
  :ensure t
  :config
  ;; Modify the mapping so it does not clash with Hyperbole's window management.
  (define-key artbollocks-mode-keymap (kbd "C-c \\") nil)
  (define-key artbollocks-mode-keymap (kbd "C-c %") 'artbollocks-readability-index)
  (add-hook 'text-mode-hook 'artbollocks-mode))

Coding

Projectile

Start using projectile. It has the documentation here.

(use-package projectile
  :ensure t
  :config
  (define-key projectile-mode-map (kbd "C-c p") 'projectile-command-map)
  (projectile-mode +1))

(use-package helm-projectile
  :ensure t
  :requires projectile
  :config
  (helm-projectile-on))

Also make sure we do have the faster silver searcher version. This may need you to install the corresponding tool for this, with the following snippet:

# helm-ag uses this for faster grepping
sudo apt-get install silversearcher-ag

Search the entire project with C-c p s s for a regexp. This let’s you turn the matching results into an editable buffer using C-c C-e. Other keys are listed here.

(use-package helm-ag
  :ensure t)

header/implementation toggle

Switch from header to implementation file quickly.

(add-hook 'c-mode-common-hook
          (lambda ()
            (local-set-key  (kbd "C-c o") 'ff-find-other-file)))

ripgrep

This enables searching recursively in projects.

# This can be used by helm-ag for faster grepping
sudo apt-get install ripgrep
(use-package ripgrep
  :ensure t)
(use-package projectile-ripgrep
  :ensure t
  :requires (ripgrep projectile))

commenting out

Easy commenting out of lines.

(autoload 'comment-out-region "comment" nil t)
(global-set-key (kbd "C-c q") 'comment-out-region)

Deduplicate and sort

Help cleanup the includes and using lists. found here

(defun uniquify-region-lines (beg end)
  "Remove duplicate adjacent lines in region."
  (interactive "*r")
  (save-excursion
    (goto-char beg)
    (while (re-search-forward "^\\(.*\n\\)\\1+" end t)
      (replace-match "\\1"))))

(defun paf/sort-and-uniquify-region ()
  "Remove duplicates and sort lines in region."
  (interactive)
  (sort-lines nil (region-beginning) (region-end))
  (uniquify-region-lines (region-beginning) (region-end)))

Simplify cleanup of #include / typedef / using blocks.

(global-set-key (kbd "C-p s") 'paf/sort-and-uniquify-region)

diffing

vdiff let’s one compare buffers or files.

(use-package vdiff
  :ensure t
  :config
  ; This binds commands under the prefix when vdiff is active.
  (define-key vdiff-mode-map (kbd "C-c") vdiff-mode-prefix-map))

yankpad / yasnippet

(use-package yasnippet
  :ensure t)
(use-package auto-yasnippet
  :ensure t
  :config
  (bind-key "C-p C-s c" 'aya-create)
  (bind-key "C-p C-s e" 'aya-expand))

(use-package yankpad
  :ensure t
  :init
  (setq yankpad-file "~/OrgFiles/yankpad.org")
  :config
  (bind-key "C-p y m" 'yankpad-map)
  (bind-key "C-p y e" 'yankpad-expand))

Selective display

Will fold all text indented more than the position of the cursor at the time the keys are pressed.

(defun set-selective-display-dlw (&optional level)
  "Fold text indented more than the cursor.
   If level is set, set the indent level to level.
   0 displays the entire buffer."
  (interactive "P")
  (set-selective-display (or level (current-column))))

(global-set-key "\C-x$" 'set-selective-display-dlw)

Info in the gutter

Line numbers

This is bound to change in Emacs 26, as it has built-in support for this and is more efficient.

(global-set-key (kbd "C-c C-n") 'linum-mode)

git informations

(use-package git-gutter-fringe+
  :ensure t
  :if window-system
  :bind ("C-c g" . 'git-gutter+-mode))

Speedup VCS

Regexp matching directory names that are not under VC’s control. The default regexp prevents fruitless and time-consuming attempts to determine the VC status in directories in which filenames are interpreted as hostnames.

(defvar locate-dominating-stop-dir-regexp
  "\\`\\(?:[\\/][\\/][^\\/]+\\|/\\(?:net\\|afs\\|\\.\\.\\.\\)/\\)\\'")

GDB with many windows

(setq gdb-many-windows t)

Dealing with numbers

Simple way to increase/decrease a number in code.

(use-package shift-number
  :ensure t
  :bind (("M-+" . shift-number-up)
         ("M-_" . shift-number-down)))

Cool Packages

VCS

magit

Add the powerful Magit

(use-package magit
  :ensure t
  :config
  (global-set-key (kbd "C-x g") 'magit-status))
(use-package magit-todos
   :ensure t)

monky

Add the Magit-copy for Mercurial ‘monky’

(use-package monky
  :ensure t
  :config
  (global-set-key (kbd "C-x m") 'monky-status))

Global caller

Have a single binding to call the most appropriate tool given the repository.

(defun paf/vcs-status ()
     (interactive)
     (condition-case nil
         (magit-status-setup-buffer)
       (error (monky-status))))

(global-set-key (kbd "C-p v") 'paf/vcs-status)

annotate-mode

The file-annotations are store externally. Seems to fail with args-out-of-range and then Emacs is confused. (filed issue for this)

Also, it seems to interfere with colorful modes like magit or org-agenda-mode so that I went with a whitelist instead of the wish of a blacklist of modes.

(use-package annotate
  :ensure t
  :bind ("C-c C-A" . 'annotate-annotate)  ;; for ledger-mode, as 'C-c C-a' is taken there.
  :config
  (add-hook 'org-mode 'annotate-mode)
  (add-hook 'csv-mode 'annotate-mode)
  (add-hook 'c-mode 'annotate-mode)
  (add-hook 'c++-mode 'annotate-mode)
  (add-hook 'sh-mode 'annotate-mode)
  (add-hook 'ledger-mode 'annotate-mode)
;;;  (define-globalized-minor-mode global-annotate-mode annotate-mode
;;;    (lambda () (annotate-mode 1)))
;;;  (global-annotate-mode 1)
  )

web-mode

web-mode with config for Polymer editing

(use-package web-mode
  :ensure t
  :mode "\\.html\\'"
  :config
  (setq web-mode-markup-indent-offset 2)
  (setq web-mode-css-indent-offset 2)
  (setq web-mode-code-indent-offset 2))

csv-mode

mode to edit CSV files.

(use-package csv-mode
  :ensure t
  :mode "\\.csv\\'")

Helm (list completion)

Trying out Helm instead of icicles, as it is available on ELPA.

I just took over the config described in this helm intro.

(use-package helm
 :ensure t
 :config
  (require 'helm-config)
  ;; The default "C-x c" is quite close to "C-x C-c", which quits Emacs.
  ;; Changed to "C-c h". Note: We must set "C-c h" globally, because we
  ;; cannot change `helm-command-prefix-key' once `helm-config' is loaded.
  (global-set-key (kbd "C-c h") 'helm-command-prefix)
  (global-unset-key (kbd "C-x c"))

  (define-key helm-map (kbd "<tab>") 'helm-execute-persistent-action) ; rebind tab to run persistent action
  (define-key helm-map (kbd "C-i") 'helm-execute-persistent-action) ; make TAB work in terminal
  (define-key helm-map (kbd "C-z")  'helm-select-action) ; list actions using C-z

  (when (executable-find "curl")
    (setq helm-google-suggest-use-curl-p t))

  (setq helm-split-window-inside-p            t ; open helm buffer inside current window, not occupy whole other window
        helm-move-to-line-cycle-in-source     t ; move to end or beginning of source when reaching top or bottom of source.
        helm-ff-search-library-in-sexp        t ; search for library in `require' and `declare-function' sexp.
        helm-scroll-amount                    8 ; scroll 8 lines other window using M-<next>/M-<prior>
        helm-ff-file-name-history-use-recentf t
        helm-echo-input-in-header-line t)

  (setq helm-autoresize-max-height 0)
  (setq helm-autoresize-min-height 20)
  (helm-autoresize-mode 1)

  (helm-mode 1)

  (global-set-key (kbd "M-x") 'helm-M-x))
(defun spacemacs//helm-hide-minibuffer-maybe ()
  "Hide minibuffer in Helm session if we use the header line as input field."
  (when (with-helm-buffer helm-echo-input-in-header-line)
    (let ((ov (make-overlay (point-min) (point-max) nil nil t)))
      (overlay-put ov 'window (selected-window))
      (overlay-put ov 'face
                   (let ((bg-color (face-background 'default nil)))
                     `(:background ,bg-color :foreground ,bg-color)))
      (setq-local cursor-type nil))))


(add-hook 'helm-minibuffer-set-up-hook
          'spacemacs//helm-hide-minibuffer-maybe)

Useful abbreviations when codng in HTML.

(use-package emmet-mode
:ensure t)

rainbow-mode

Colorize color names and codes in the correct color.

(use-package rainbow-mode
:ensure t)

taskjuggler-mode (tj3-mode)

(use-package tj3-mode
 :ensure t)

writeroom-mode

(use-package writeroom-mode
  :ensure t
  :init
  (global-set-key (kbd "C-p w") 'writeroom-mode))

wgrep-mode

(use-package wgrep
  :ensure t)

Cleanup ledger file

(defun single-lines-only ()
  "replace multiple blank lines with a single one"
  (interactive)
  (goto-char (point-min))
  (while (re-search-forward "\\(^\\s-*$\\)\n" nil t)
    (replace-match "\n")
    (forward-char 1)))

(defun paf/cleanup-ledger-buffer ()
  "Cleanup the ledger file"
  (interactive)
  (delete-trailing-whitespace)
  (single-lines-only)
  (ledger-mode-clean-buffer)
  (ledger-sort-buffer))

Setup

(use-package ledger-mode
  :ensure nil
  :pin manual
  :mode "\\.ledger\\'"
  :bind ("<f6>" . 'paf/cleanup-ledger-buffer)
  :config
  (setq ledger-reconcile-default-commodity "CHF"))

Let’s try this too, even though I do not quite get the point of this whole package yet.

NOTE assigns hui-search-web to C-c C-/ to not clobber the later used C-c / from OrgMode (org-mode sparse trees) This works because hyperbole will first check if the function is already bound to some key before binding it to the coded default.

(use-package hyperbole
  :ensure t
  :config
  (bind-key "C-c C-/" 'hui-search-web)  ;; bind before calling require
  (require 'hyperbole))

A tree-view navigation of files, with diff tool for directories.

(use-package ztree
  :ensure t)

OrgMode

Load all my org stuff, but first org-mode itself.

Init

If variable org-directory is not set yet, map it to my home’s files. You may set this in the ~/.emacs to another value, e.g. (setq org-directory "/ssh:fleury@machine.site.com:OrgFiles")

NEXT This does not seem to work, check out doc about defcustom

  • State “NEXT” from [2019-06-24 Mon 10:10]
(use-package org
  :ensure nil
  :config
  (if (not (boundp 'org-directory))
      (setq org-directory "~/OrgFiles")))

Access my remote Org files directory

Let’s bind this to a key, so I can open remote dirs. I suually put this in my .emacs as it is host- and user-specific.

(defun paf/open-remote-org-dir ()
  (interactive)
  (dired "/ssh:remote.host.com:OrgFiles"))

(global-set-key (kbd "C-p r o") 'paf/open-remote-org-dir)

Helper Functions / Tools found on the web / worg

Open remote org dir

In your .emacs just add this to configure the location:

(setq remote-org-directory "/ssh:fleury@my.hostname.com:OrgFiles")

Then you can use the keyboard shortcut to open that dir.

(defcustom remote-org-directory "~/OrgFiles"
  "Location of remove OrgFile directory, should you have one."
  :type 'string
  :group 'paf)
(defun paf/open-remote-org-directory ()
  (interactive)
  (find-file remote-org-directory))

(global-set-key (kbd "C-p r o") 'paf/open-remote-org-directory)

org-protocol

Let other tools use emacs client to interact

(require 'org-protocol)

Org-relative file function

(defun org-relative-file (filename)
  "Compute an expanded absolute file path for org files"
  (expand-file-name filename org-directory))

Preserve structure in archives

Make sure archiving preserves the same tree structure, including when archiving subtrees. source on worg

(defun my-org-inherited-no-file-tags ()
  (let ((tags (org-entry-get nil "ALLTAGS" 'selective))
        (ltags (org-entry-get nil "TAGS")))
    (mapc (lambda (tag)
            (setq tags
                  (replace-regexp-in-string (concat tag ":") "" tags)))
          (append org-file-tags (when ltags (split-string ltags ":" t))))
    (if (string= ":" tags) nil tags)))

This used to work, but org-extract-archive-file is no longer defined.

(defadvice org-archive-subtree
    (around my-org-archive-subtree-low-level activate)
  (let ((tags (my-org-inherited-no-file-tags))
        (org-archive-location
         (if (save-excursion (org-back-to-heading)
                             (> (org-outline-level) 1))
             (concat (car (split-string org-archive-location "::"))
                     "::* "
                     (car (org-get-outline-path)))
           org-archive-location)))
    ad-do-it
    (with-current-buffer (find-file-noselect (org-extract-archive-file))
      (save-excursion
        (while (org-up-heading-safe))
        (org-set-tags tags)))))

Adjust tags on the right

Dynamically adjust tag position source on worg

(defun ba/org-adjust-tags-column-reset-tags ()
  "In org-mode buffers it will reset tag position according to
`org-tags-column'."
  (when (and
         (not (string= (buffer-name) "*Remember*"))
         (eql major-mode 'org-mode))
    (let ((b-m-p (buffer-modified-p)))
      (condition-case nil
          (save-excursion
            (goto-char (point-min))
            (command-execute 'outline-next-visible-heading)
            ;; disable (message) that org-set-tags generates
            (cl-letf (((symbol-function 'message) #'format))
              (org-set-tags 1 t))
            (set-buffer-modified-p b-m-p))
        (error nil)))))

(defun ba/org-adjust-tags-column-now ()
  "Right-adjust `org-tags-column' value, then reset tag position."
  (set (make-local-variable 'org-tags-column)
       (- (- (window-width) (length org-ellipsis))))
  (ba/org-adjust-tags-column-reset-tags))

(defun ba/org-adjust-tags-column-maybe ()
  "If `ba/org-adjust-tags-column' is set to non-nil, adjust tags."
  (when ba/org-adjust-tags-column
    (ba/org-adjust-tags-column-now)))

(defun ba/org-adjust-tags-column-before-save ()
  "Tags need to be left-adjusted when saving."
  (when ba/org-adjust-tags-column
     (setq org-tags-column 1)
     (ba/org-adjust-tags-column-reset-tags)))

(defun ba/org-adjust-tags-column-after-save ()
  "Revert left-adjusted tag position done by before-save hook."
  (ba/org-adjust-tags-column-maybe)
  (set-buffer-modified-p nil))

;; between invoking org-refile and displaying the prompt (which
;; triggers window-configuration-change-hook) tags might adjust,
;; which invalidates the org-refile cache
(defadvice org-refile (around org-refile-disable-adjust-tags)
  "Disable dynamically adjusting tags"
  (let ((ba/org-adjust-tags-column nil))
    ad-do-it))
(ad-activate 'org-refile)

;; Now set it up
(setq ba/org-adjust-tags-column t)
;; automatically align tags on right-hand side
;; TODO(fleury): Does not seem to work as of 2017/12/18
;; Seems to work again 2018/11/01
(add-hook 'window-configuration-change-hook
          'ba/org-adjust-tags-column-maybe)
(add-hook 'before-save-hook 'ba/org-adjust-tags-column-before-save)
(add-hook 'after-save-hook 'ba/org-adjust-tags-column-after-save)
(add-hook 'org-agenda-mode-hook (lambda ()
                                  (setq org-agenda-tags-column (- (window-width)))))

Update org-set-tags-to

  • State “TODO” from [2019-01-12 Sat 12:08]
=org-set-tags-to= is gone, and org-set-tags with > 1 args is not working. Not sure what to replace it with though…

Auto-Refresh Agenda

Refresh org-mode agenda regularly. source on worg There are two functions that supposedly do the same.

(defun kiwon/org-agenda-redo-in-other-window ()
  "Call org-agenda-redo function even in the non-agenda buffer."
  (interactive)
  (let ((agenda-window (get-buffer-window org-agenda-buffer-name t)))
    (when agenda-window
      (with-selected-window agenda-window (org-agenda-redo)))))

(defun update-agenda-if-visible ()
  (interactive)
  (let ((buf (get-buffer "*Org Agenda*"))
        wind)
    (if buf
        (org-agenda-redo))))

Display Agenda when idle

Show the agenda when emacs left idle. source on worg

(defun jump-to-org-agenda ()
  (interactive)
  (let ((buf (get-buffer "*Org Agenda*"))
        wind)
    (if buf
        (if (setq wind (get-buffer-window buf))
            (select-window wind)
          (if (called-interactively-p 'any)
              (progn
                (select-window (display-buffer buf t t))
                (org-fit-window-to-buffer)
                (org-agenda-redo)
                )
            (with-selected-window (display-buffer buf)
              (org-fit-window-to-buffer)
              ;;(org-agenda-redo)
              )))
      (call-interactively 'org-agenda-list)))
  ;;(let ((buf (get-buffer "*Calendar*")))
  ;;  (unless (get-buffer-window buf)
  ;;    (org-agenda-goto-calendar)))
  )

Display location in agenda

From some help on this page I think this could work:

(defun paf/org-agenda-get-location()
  "Gets the value of the LOCATION property"
  (let ((loc (org-entry-get (point) "LOCATION")))
    (if (> (length loc) 0)
        loc
      "")))

Also, to set this after org-mode has loaded (see here):

(with-eval-after-load 'org-agenda
  (add-to-list 'org-agenda-prefix-format
               '(agenda . "  %-12:c%?-12t %(paf/org-agenda-get-location)% s"))

org-gtasks

Should follow this git repo: org-gtasks I have copied a version of the file here, it’s not yet available on MELPA.

(use-package request
  :ensure t)
(load-file "~/Emacs/org-gtasks.el")

I have this currently in my `~/.emacs`:

(use-package org-gtasks
  :init
  (org-gtasks-register-account
     :name "pascal"
     :directory "~/OrgFiles/GTasks/"
     :client-id "XXX"
     :client-secret "XXX"))

Properties collector

Collect properties into tables. See documentation in the file.

(load-file "~/Emacs/org-collector.el")

My Setup

These are mostly org-config specific to me, myself and I.

Key mappings

(global-set-key (kbd "C-c l") 'org-store-link)
(global-set-key (kbd "C-c c") 'org-capture)
(global-set-key (kbd "C-c a") 'org-agenda)
(global-set-key (kbd "C-c b") 'org-iswitchb)

(add-hook 'org-mode-hook
    (lambda ()
            (local-set-key (kbd "C-<up>") 'org-move-subtree-up)
            (local-set-key (kbd "C-<down>") 'org-move-subtree-down)
            (local-set-key (kbd "C-c l") 'org-store-link)
            (local-set-key (kbd "C-c C-l") 'org-insert-link)))

Display settings

Some config for display.

(setq org-hide-leading-stars 't)
(setq org-log-done 't)
(setq org-startup-folded 't)
(setq org-startup-indented 't)
(setq org-startup-folded 't)
(setq org-ellipsis "...")
; Don't really like the new bullets though.
;;(use-package 'org-bullets
;;  :config
;;  (add-hook 'org-mode-hook (lambda () (org-bullets-mode 1))))

org-habit

(use-package org-habit
  :config
  (setq org-habit-graph-column 38)
  (setq org-habit-preceding-days 35)
  (setq org-habit-following-days 10)
  (setq org-habit-show-habits-only-for-today nil))

bash command

(setq org-babel-sh-command "bash")

org-clock properties

clock stuff into a drawer.

(setq org-clock-into-drawer t)
(setq org-log-into-drawer t)
(setq org-clock-int-drawer "CLOCK")

org-mobile

config for org-mobile-*

(setq org-mobile-directory (org-relative-file "Mobile"))
(setq org-mobile-inbox-for-pull (org-relative-file "mobileorg.org"))

open first agenda file

F12 open the first agenda file

(defun org-get-first-agenda-file ()
  (interactive)
  (find-file (elt org-agenda-files 0)))
(global-set-key [f12] 'org-get-first-agenda-file)
; F12 on Mac OSX displays the dashboard....
(global-set-key [C-f12] 'org-get-first-agenda-file)

org-ehtml [localhost:55555]

This will start serving the org files through the emacs-based webbrowser when pressing M-f12 (on localhost:55555)

(use-package org-ehtml
  :ensure t
  :config
  (setq org-ehtml-docroot (expand-file-name org-directory))
  (setq org-ehtml-everything-editable t)
  (setq org-ehtml-allow-agenda t))

(defun paf/start-web-server ()
  (interactive)
  (ws-start org-ehtml-handler 55555))
(global-set-key (kbd "<M-f12>") 'paf/start-web-server)

org-link-abbrev

This lets one write links as e.g. [ [b:123457] ]

(setq org-link-abbrev-alist
      '(("b" . "http://b/")
        ("go" . "http://go/")
        ("cl" . "http://cr/")))

org-secretary

(use-package  org-secretary
:ensure org-plus-contrib
:config
(setq org-sec-me "paf")
(setq org-tag-alist '(("PRJ" . ?p)
                      ("DESIGNDOC" . ?D)
                      ("Milestone" . ?m)
                      ("DESK" . ?d)
                      ("HOME" . ?h)
                      ("VC" . ?v))))

task tracking

Track task dependencies, and dim them in in the agenda.

(setq org-enforce-todo-dependencies t)
(setq org-agenda-dim-blocked-tasks 'invisible)

effort & columns mode

(setq org-global-properties
      '(("Effort_ALL". "0 0:10 0:30 1:00 2:00 4:00 8:00 16:00")))
(setq org-columns-default-format
      "%TODO %30ITEM %3PRIORITY %6Effort{:} %10DEADLINE")

org-todo keywords

(setq org-todo-keywords
      '((sequence "TODO(t!)" "NEXT(n!)" "STARTED(s!)" "WAITING(w!)" "AI(a!)" "|" "DONE(d!)" "CANCELLED(C@)" "DEFERRED(D@)" "SOMEDAY(S!)" "FAILED(F!)" "REFILED(R!)")
        (sequence "APPLIED(A!)" "WAITING(w!)" "ACCEPTED" "|" "REJECTED" "PUBLISHED")
        (sequence "TASK(m!)" "|" "DONE(d!)" "CANCELLED(C@)" )))

(setq org-tags-exclude-from-inheritance '("PRJ")
      org-use-property-inheritance '("PRIORITY")
      org-stuck-projects '("+PRJ/-DONE-CANCELLED"
			   ; it is considered stuck if there is no next action
                           (;"TODO"
			    "NEXT" "STARTED" "TASK") ()))

(setq org-todo-keyword-faces '(
        ("TODO" . (:foreground "purple" :weight bold))
        ("TASK" . (:foreground "steelblue" :weight bold))
        ("NEXT" . (:foreground "red" :weight bold))
        ("STARTED" . (:foreground "darkgreen" :weight bold))
        ("WAITING" . (:foreground "orange" :weight bold))
        ("FLAG_GATED" . (:foreground "orange" :weight bold))
        ("SOMEDAY" . (:foreground "steelblue" :weight bold))
        ("MAYBE" . (:foreground "steelblue" :weight bold))
        ("AI" . (:foreground "red" :weight bold))
        ("NEW" . (:foreground "orange" :weight bold))
        ("RUNNING" . (:foreground "orange" :weight bold))
        ("WORKED" . (:foreground "green" :weight bold))
        ("FAILED" . (:foreground "red" :weight bold))
        ("REFILED" . (:foreground "gray"))
        ; For publications
        ("APPLIED" . (:foreground "orange" :weight bold))
        ("ACCEPTED" . (:foreground "orange" :weight bold))
        ("REJECTED" . (:foreground "red" :weight bold))
        ("PUBLISHED" . (:foreground "green" :weight bold))
        ))

org-agenda

views

(setq org-agenda-custom-commands
       '(("t" "Hot Today" ((agenda "" ((org-agenda-span 'day)))
                           (tags-todo "/NEXT")
                           (tags-todo "-dowith={.+}/STARTED")
                           (tags-todo "-dowith={.+}/WAITING")))
         ("n" "Agenda and all TODO's" ((agenda "") (alltodo "")))
         ("N" "Next actions" tags-todo
          "-personal-doat={.+}-dowith={.+}/!-TASK-TODO"
          ((org-agenda-todo-ignore-scheduled t)))
         ("h" "Work todos" tags-todo
          "-personal-doat={.+}-dowith={.+}/!-TASK"
          ((org-agenda-todo-ignore-scheduled t)))
         ("H" "All work todos" tags-todo "-personal/!-TASK-CANCELLED"
          ((org-agenda-todo-ignore-scheduled nil)))
         ("A" "Work todos with doat or dowith" tags-todo
          "-personal+doat={.+}|dowith={.+}/!-TASK"
          ((org-agenda-todo-ignore-scheduled nil)))
         ("j" "TODO dowith and TASK with"
         ((org-sec-with-view "TODO dowith")
          (org-sec-where-view "TODO doat")
          (org-sec-assigned-with-view "TASK with")
          (org-sec-stuck-with-view "STUCK with")
          (todo "STARTED")))
         ("J" "Interactive TODO dowith and TASK with"
          ((org-sec-who-view "TODO dowith")))))

colors

Make the calendar day info a bit more visible. Move this into the custom-set-faces in ~/.emacs

;; '(org-agenda-date ((t (:inherit org-agenda-structure :background "pale green" :foreground "black" :weight bold))) t)
;; '(org-agenda-date-weekend ((t (:inherit org-agenda-date :background "light blue" :weight bold))) t)
;; '(org-agenda-current-time ((t (:inherit org-time-grid :foreground "yellow" :weight bold))))

now marker

A more visible current-time marker in the agenda

(setq org-agenda-current-time-string ">>>>>>>>>> NOW <<<<<<<<<<")

auto-refresh

;; will refresh it only if already visible
(run-at-time nil 180 'update-agenda-if-visible)
;;(add-hook 'org-mode-hook
;;          (lambda () (run-at-time nil 180 'kiwon/org-agenda-redo-in-other-window)))

This would open the agenda if any org file was opened. In the end, I don’t like this feature, so it is disabled by not tangling it.

;; Make this happen only if we open an org file.
(add-hook 'org-mode-hook
          (lambda () (run-with-idle-timer 600 t 'jump-to-org-agenda)))

auto-save org files when idle

This will save them regularly when the idle for more than a minute.

(add-hook 'org-mode-hook
    (lambda () (run-with-idle-timer 180 t 'org-save-all-org-buffers)))

export

That’s the export function to update the agenda view.

(setq org-agenda-exporter-settings
      '((ps-number-of-columns 2)
        (ps-portrait-mode t)
        (org-agenda-add-entry-text-maxlines 5)
        (htmlize-output-type 'font)))

(defun dmg-org-update-agenda-file (&optional force)
  (interactive)
  (save-excursion
    (save-window-excursion
      (let ((file "~/www/agenda/agenda.html"))
        (org-agenda-list)
        (org-agenda-write file)))))

org-duration

(use-package org-duration
  :config
  (setq org-duration-units
    `(("min" . 1)
      ("h" . 60)
      ("d" . ,(* 60 8))
      ("w" . ,(* 60 8 5))
      ("m" . ,(* 60 8 5 4))
      ("y" . ,(* 60 8 5 4 10)))
     )
  (org-duration-set-regexps))

Capture & refile

Capture and refile stuff, with some templates that I think are useful.

(setq org-default-notes-file (org-relative-file "refile.org"))

(setq org-capture-templates
      `(("a" "Action Item" entry (file+headline ,(org-relative-file "refile.org") "Tasks")
             "* AI %?\n  %U")
        ("m" "Meeting" entry (file+headline ,(org-relative-file "refile.org") "Meetings")
             "* %U  :MTG:\n %^{with}p\n%?")
        ("n" "Note" entry (file+headline ,(org-relative-file "refile.org") "Notes")
             "* %?\n%U")
        ("j" "Journal" entry (file+datetree ,(org-relative-file "journal.org"))
             "* %?\n  %U")))

; show up to 2 levels for refile targets, in all agenda files
(setq org-refile-targets '((org-agenda-files . (:maxlevel . 2))))
(setq org-log-refile t)  ;; will add timestamp when refiled.
; from: http://doc.norang.ca/org-mode.html
; Exclude DONE state tasks from refile targets
(defun bh/verify-refile-target ()
  "Exclude todo keywords with a done state from refile targets"
  (not (member (nth 2 (org-heading-components)) org-done-keywords)))
(setq org-refile-target-verify-function 'bh/verify-refile-target)

org-reveal

This presentation generator is still under review (by me).

NOTE Currently problematic as it depends on org-20190225 which does not display the calendar right.

;;(add-to-list 'org-structure-template-alist
;;             (list "n" . "#+BEGIN_NOTES\n\?\n#+END_NOTES"))
;; disable the addition in the lib that does not do it right for Org 9.2
(setq org-reveal-note-key-char nil)

;; import as usual.
(use-package ox-reveal
 :ensure t)

org-babel

What kind of code block languages do I need

(setq org-confirm-babel-evaluate 'nil) ; Don't ask before executing

(org-babel-do-load-languages
 'org-babel-load-languages
 '(
   (R . t)
   (dot . t)
   (emacs-lisp . t)
   (gnuplot . t)
   (python . t)
   (ledger . t)
   ;;(sh . t)
   (latex . t)
   (plantuml . t)
   (shell . t)
  ))

org-export

Add a few formats to the export functionality of org-mode.

(use-package ox-odt)
(use-package ox-taskjuggler)

plant-uml

Tell where PlantUML is to be found. This needs to be downloaded and installed separately, see the PlantUML website.

You could install the PlantUML JAR file with this snippet:

URL='http://sourceforge.net/projects/plantuml/files/plantuml.jar/download'
DIR="${HOME}/Apps"
[[ -d "${DIR}" ]] || mkdir -p "${DIR}"
(cd "${DIR}" && curl -o plantuml.jar "${URL}")
ls -l "${DIR}/plantuml.jar"
(use-package plantuml-mode
 :ensure t
 :config
  (setq plantuml-jar-path "~/Apps/plantuml.jar")
  (setq org-plantuml-jar-path "~/Apps/plantuml.jar")
  ;; Let us edit PlantUML snippets in plantuml-mode within orgmode
  (add-to-list 'org-src-lang-modes '("plantuml" . plantuml))
  ;; Enable plantuml-mode for PlantUML files
  (add-to-list 'auto-mode-alist '("\\.plantuml\\'" . plantuml-mode)))

iimage (M-I)

Make the display of images a simple key-stroke away.

(use-package iimage
  :config
  (add-to-list 'iimage-mode-image-regex-alist
               (cons (concat "\\[\\[file:\\(~?" iimage-mode-image-filename-regex
                             "\\)\\]")  1))

  (defun org-toggle-iimage-in-org ()
    "display images in your org file"
    (interactive)
    (if (face-underline-p 'org-link)
        (set-face-underline 'org-link nil)
      (set-face-underline 'org-link t))
    (iimage-mode 'toggle))

  (add-hook 'org-mode-hook (lambda ()
                             ;; display images
                             (local-set-key "\M-I" 'org-toggle-iimage-in-org)
                            )))

PDF-Tools

A bit difficult to find the docs of how to use it, but it seems quite useful.

Disabled, as it causes only trouble to me, and I am not really using it anyway.

(use-package pdf-tools
  :if (and (eq system-type 'gnu/linux)  ;; Set it up on Linux
           (not (string-prefix-p "aarch64" system-configuration)))  ;; but not mobile devices
  :pin manual  ;; update only manually
  :config
  ;; initialize
  (pdf-tools-install)
  (setq-default pdf-view-display-size 'fit-page)           ;; Fit to page when opening
  (add-hook 'pdf-view-mode-hook (lambda () (cua-mode 0)))  ;; turn off cua so copy works
  (setq pdf-view-resize-factor 1.1)                        ;; more fine-grained zoom control
  ;; keyboard shortcuts
  (define-key pdf-view-mode-map (kbd "h") 'pdf-annot-add-highlight-markup-annotation)
  (define-key pdf-view-mode-map (kbd "t") 'pdf-annot-add-text-annotation)
  (define-key pdf-view-mode-map (kbd "D") 'pdf-annot-delete))

(use-package org-pdfview
  :after (pdf-tools)
  :init
  (add-to-list 'org-file-apps '("\\.pdf\\'" . org-pdfview-open))
  (add-to-list 'org-file-apps '("\\.pdf::\\([[:digit:]]+\\)\\'" . org-pdfview-open)))
# for all the native apps related to PDF tools
sudo apt-get install pdf-tools

This is a note-taking packages inspired by the principles of the Zettelkasten

(use-package deft
  :ensure t)
(use-package avy
  :ensure t)

(use-package zetteldeft
  :ensure nil
  :after (org deft avy)

  :config
  (setq deft-extensions '("org" "md" "txt"))
  (setq deft-directory (concat org-directory "/Zettelkasten"))
  (setq deft-recursive t)

  :bind (("C-p C-k d" . deft)
         ("C-p C-k D" . zetteldeft-deft-new-search)
         ("C-p C-k R" . deft-refresh)
         ("C-p C-k s" . zetteldeft-search-at-point)
         ("C-p C-k c" . zetteldeft-search-current-id)
         ("C-p C-k f" . zetteldeft-follow-link)
         ("C-p C-k F" . zetteldeft-avy-file-search-ace-window)
         ("C-p C-k l" . zetteldeft-avy-link-search)
         ("C-p C-k t" . zetteldeft-avy-tag-search)
         ("C-p C-k T" . zetteldeft-tag-buffer)
         ("C-p C-k i" . zetteldeft-find-file-id-insert)
         ("C-p C-k I" . zetteldeft-find-file-full-title-insert)
         ("C-p C-k o" . zetteldeft-find-file)
         ("C-p C-k n" . zetteldeft-new-file)
         ("C-p C-k N" . zetteldeft-new-file-and-link)
         ("C-p C-k r" . zetteldeft-file-rename))
)

Update the version by downloading the latest version here:

wget https://raw.githubusercontent.com/EFLS/zetteldeft/master/zetteldeft.el -O ~/Emacs/zetteldeft.el

About

My personal Emacs configs, consisting mostly of configuration of free tools.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Emacs Lisp 99.2%
  • Shell 0.8%