You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

26 KiB

emacs init file

Some remarks and comments

setq vs setq-default

Some variables are buffer-local, others are not; for non buffer-local variables the two commands are equivalent; for the buffer-local variables, setq acts on the current buffer, whereas setq-default sets the default value of the variable for buffers that do not have a local value.

:source: [https://stackoverflow.com/a/18173666]

Why not package.el

it is convenient, but it is not git-based; borg.el is promising, but it is way complicated; I can do everything by hand as soon as it is neatly org-anized. In the end we use a few, but I plan to phase them out and replace them with git submodules

Files and dirs

Move Customize to a separate file

  (setq custom-file "~/.emacs.d/custom.el")
  (load custom-file 'noerror)

Add relevant dirs to load path [This is somewhat undesirable; I should uniformize the path-loading business at some point…]

  (let ((default-directory "~/.emacs.d/"))
    (normal-top-level-add-subdirs-to-load-path)
    (normal-top-level-add-to-load-path '("fringe-helper.el"
                                         "multiple-cursors.el"
                                         "expand-region.el"
                                         "dash.el")))

Put autosave files (ie #foo#) and backup files (ie foo~) in ~/.emacs.d/. create the autosave dir if necessary, since emacs won't.

  (make-directory "~/.emacs.d/autosaves/" t)
  (make-directory "~/.emacs.d/backup/" t)

Themes

Use (my clone of) the solarized theme

  (add-to-list 'custom-theme-load-path "/home/jacopods/.emacs.d/emacs-color-theme-solarized")
  (load-theme 'solarized t)

Use patched terminus font (this overrides the settings in Customize, but I never could it to work otherwise). See the special treatment later on for dealing with bold weight. To avoid flickering one should also set the font in .Xresources

  (set-face-font 'default "-xos4-hackminus-medium-r-normal--20-200-72-72-c-100-ISO10646-1")

Global settings

Cosmetics

Prefer a minimal appearance: no menu, toolbar or scroll-bars; no splash screens or messages

  (menu-bar-mode -1)
  (tool-bar-mode 0)
  (scroll-bar-mode -1)
  (setq inhibit-startup-screen t
        inhibit-startup-message t)

a blinking cursor keeps the gpu awake; add global hl-line mode to more easily spot the cursor

  (blink-cursor-mode 0)
  (set-default 'cursor-type 'box)
  (global-hl-line-mode t)

Set frame title

  (setq frame-title-format
     '((buffer-file-name "%f"
         (dired-directory dired-directory "%b")) " · emacs"));; · " (:eval (kde-current-activity-name)))) ;; "%S"))

Themed tooltips

(setq x-gtk-use-system-tooltips nil)

Set Fill-column to 78, which happens to be good for third-tiled frames and it also is a reasonable standard (almost 80)

  (setq default-fill-column 78)

Highlight sexp (apparently I am not even using this)

  ;(require 'highlight-sexps)

Mouseless

Disable mouse interaction with emacs

  (setq mouse-autoselect-window nil)
  (mouse-wheel-mode -1)
  (setq mouse-yank-at-point nil)
  (setq focus-follows-mouse nil)

TODO Find out what of the above is necessary given the disable-mouse mode below

Use the disable-mouse package by Steve Purcell available at [https://github.com/purcell/disable-mouse]

  (require 'disable-mouse)
  (global-disable-mouse-mode)

Window behavior

Prevent compilation window eating up other windows

   (setq compilation-scroll-output t
         compilation-window-height 12)

Prevent any automatic splitting to split vertically

  (setq split-width-threshold nil)

Scrolling

Scrolling setup

   (setq redisplay-dont-pause t
         scroll-margin 3
         scroll-step 1
         scroll-conservatively 10000
         scroll-preserve-screen-position 1)

TODO find out what this was actually meant to do

  (setq-default display-buffer-reuse-frames t)

Modeline

  (setq-default mode-line-modified '(:eval (if (buffer-modified-p) "●" "·"))) ;still needs some improvements,
                                                                              ;does not report Readonly state
  (setq-default mode-line-remote '(:eval (let ((s (format-mode-line "%@")))
    (cond
     ((equal s "-") "·") ((equal s "@") "@") (t s)))))

  (defvar wilder-buffer-vc-mode-line
                '("%b" (vc-mode (:propertize
                       ;; Strip the backend name from the VC status information
                       (:eval (let* ((backend (downcase (symbol-name (vc-backend (buffer-file-name)))))
                                     (branch (substring vc-mode (+ (length backend) 2)))
                                     (s (substring vc-mode (+ (length backend) 1) (+ (length backend) 2)))
                                     (status (cond ((equal s "-") "") ((equal s ":") "!") (t s))))
                                (concat "·" branch status)))
                       face font-lock-comment-face))))
  (put 'wilder-buffer-vc-mode-line 'risky-local-variable t)

  (defvar wilder-position
    '("[%p,%I] " ))

  (put 'wilder-position 'risky-local-variable t)

  (setq-default mode-line-format
                '("%e"
                  mode-line-front-space
                  mode-line-mule-info
                  mode-line-client
                  mode-line-modified
                  mode-line-remote
                  mode-line-frame-identification
                  wilder-buffer-vc-mode-line "   "
                  wilder-position " "
                  mode-line-modes
                  mode-line-misc-info
                  mode-line-end-spaces))

Mark handling

No transient mark is more flexible

(transient-mark-mode 0)

But of course we need to see the mark

(require 'visible-mark)
(visible-mark-mode t)
(global-visible-mark-mode t)

The following are some convenient bindings; notice that on my layout F13 and F14 are obtained by tapping the left and right shift respectively

(global-set-key (kbd "<f13>") 'set-mark-command)
(global-set-key (kbd "<f14>") 'set-mark-command)

(defun jump-to-mark ()
  "Jumps to the local mark, respecting the `mark-ring' order.
This is the same as using \\[set-mark-command] with the prefix argument."
  (interactive)
  (set-mark-command 1))
(global-set-key (kbd "<M-f13>") 'jump-to-mark)
(global-set-key (kbd "<M-f14>") 'jump-to-mark)

(defun just-activate-mark ()
  (interactive)
  (activate-mark))
(global-set-key (kbd "<S-f13>") 'just-activate-mark)
(global-set-key (kbd "<S-f14>") 'just-activate-mark)

Global bindings

Remove some supremely annoying bindings

  (global-unset-key (kbd "C-z"))
  (global-unset-key (kbd "C-x f"))
  (global-unset-key (kbd "<M-f4>")) ; rly?

Change {up,down}-list

  (global-unset-key (kbd "C-M-u"))
  (global-unset-key (kbd "C-M-d"))
  (global-set-key (kbd "C-M-i") 'down-list) ;; -i stands for /in/
  (global-set-key (kbd "C-M-o") 'up-list)   ;; -o stands for /out/

Add some opinionated bindings

  (global-set-key (kbd "C-M-d") 'kill-sexp)
  (global-set-key (kbd "C-M-<backspace>") 'backward-kill-sexp)
  (global-set-key (kbd "C-x k") 'kill-this-buffer)
  (global-set-key (kbd "C-S-v") 'scroll-down-command)

Smart beginning-of-line

This is a relatively smart way to go back to the beginning of the line

  (defun smart-line-beginning ()
  "Move point to the beginning of text on the current line; if that
  is already the current position of point, then move it to the
  beginning of the line."
(interactive)
(let ((pt (point)))
(beginning-of-line-text)
(when (eq pt (point))
  (beginning-of-line))))
   (global-set-key (kbd "C-a") 'smart-line-beginning)

Whitespace

Trailing whitespace is evil; get rid of it

  (setq-default show-trailing-whitespace t)
  (add-hook 'before-save-hook 'delete-trailing-whitespace)

Define what is whitespace during a search

     (setq search-whitespace-regexp "[ \t\r\n]+")

Tabs are evil; get rid of them

  (setq c-basic-offset 4)
  (setq tab-width 4)
  (setq indent-tabs-mode nil)

TODO Have a look at ws-trim.el

It is conf'ble to avoid removing whitespace from lines that were not modified; sounds like a good idea for git [ftp://ftp.lysator.liu.se/pub/emacs/ws-trim.el]

Show matching parens

Use mic-paren for paren-highlighting

;     (setq show-paren-mode t)
  (require 'mic-paren)
  (paren-activate)

TODO find out if there are better options out there

Abbrevs

Set up abbrevs

   (setq-default abbrev-mode t)
   (read-abbrev-file "~/.abbrev_defs")
   (setq save-abbrevs t)

Spellcheck

Use flyspell

   (add-hook 'text-mode-hook 'flyspell-mode)
   (setq flyspell-use-meta-tab nil)

Fringe treatment

TODO try linum-relative

  (require 'linum-relative)
  (linum-relative-mode 1)

Add line numbers globally

  (global-linum-mode 1)

Highlight also the linum in the fringe

 (require 'hlinum)
 (hlinum-activate)

Add marker for current line in the fringe (see [https://github.com/kyanagi/fringe-current-line])

  ;; (require 'fringe-current-line)
  ;; (global-fringe-current-line-mode 1)
  ;; (setq fcl-fringe-bitmap 'right-triangle)

Turn on echo mode

Display unfinished commands in the echo area after the specified delay.

  (setq echo-keystrokes 0.10)

Disable completion buffer

Remove the completion buffer as soon as we get out of the minibuffer

  (add-hook 'minibuffer-exit-hook
            '(lambda ()
               (let ((buffer "*Completions*"))
                 (and (get-buffer buffer)
                      (kill-buffer buffer))) ))

Auto save on compile

  (setq compilation-ask-about-save nil)

Calendar

(add-hook 'calendar-load-hook
  (lambda ()
  (calendar-set-date-style 'european)))
;; first day of the week is monday instead of sunday:
(setq calendar-week-start-day 1)
(setq calendar-location-name "Toronto, ON Canada")
(setq calendar-latitude 43.7)
(setq calendar-longitude -79.4)

Use system proxy

     ;; Use system proxy
    (setq url-proxy-services '(("http" . "127.0.0.1:8118")))

Settings for important major modes

org-mode


(require 'org-install)
(require 'org-pomodoro)

(setq org-agenda-files
' ("~/org/notes.org" "~/org/orgzly/work.org" "~/org/orgzly/hack.org" "~/org/orgzly/live.org" "~/org/orgzly/refile.org"))

(add-hook 'org-mode-hook (lambda ()
   (turn-on-auto-fill)))
(setq org-default-notes-file "~/org/notes.org")
(global-set-key (kbd "C-c a") 'org-agenda)
(global-set-key (kbd "C-c c") 'org-capture)

(add-to-list 'org-structure-template-alist
          '("el" "#+BEGIN_SRC emacs-lisp\n?\n#+END_SRC"))

(setq org-src-fontify-natively t)

(setq org-capture-templates
   '(("t" "TODO today" entry (file+headline "~/org/notes.org" "Tasks")
"* TODO %?\n  SCHEDULED: %t" :clock-in t :clock-resume t)
("n" "TODO next" entry (file+headline "~/org/notes.org" "Tasks")
"* NEXT %?\n  " :clock-in t :clock-resume t)
("T" "TODO" entry (file+headline "~/org/notes.org" "Tasks")
"* TODO %?\n  %a" :clock-in t :clock-resume t)
("i" "Idea" entry (file+headline "~/org/notes.org" "Ideas")
"* IDEA %?\n  %u" :clock-in t :clock-resume t	 )
("j" "Journal" entry (file+datetree "~/org/notes.org")
            "* %?\n%U\n" :clock-in t :clock-resume t)
("b" "Break" entry (file+datetree "~/org/notes.org")
            "* break %?\n" :clock-in t :clock-resume t)
("e" "Mail To" entry (file+headline "~/org/notes.org" "E-mails")
"* DONE mailto:%?")
     ("r" "Reply to" entry (file+headline "~/org/notes.org" "E-mails")
"* DONE mailto:%?")))

(setq org-clock-persist 'history)
(org-clock-persistence-insinuate)

(setq org-agenda-span 1)

;; Separate drawers for clocking and logs
(setq org-drawers (quote ("PROPERTIES" "CLOCKBOOK")))
;; Save clock data and state changes and notes in the CLOCK drawer
(setq org-clock-into-drawer "CLOCKBOOK")
;; Sometimes I change tasks I'm clocking quickly - this removes clocked tasks with 0:00 duration
(setq org-clock-out-remove-zero-time-clocks t)
;; Clock out when moving task to a done state
(setq org-clock-out-when-done t)


(setq org-agenda-custom-commands
        '(("h" "Agenda and Android tasks"
           ((agenda "")
            (tags-todo "Android")))
   ("a" "Main agenda"
           ((agenda "")
     (todo "NEXT|ONGOING")
     (tags-todo "hack")
     (tags-todo "5m")
     (todo "TODO")))
          ("5" "Agenda and Break tasks"
           ((agenda "")
            (tags-todo "5m")
     (tags-todo "20m")))))

;; some super-clever stuff
;; [https://emacs.stackexchange.com/questions/39032/tangle-the-same-src-block-to-different-files]
(defun org-babel-tangle-collect-blocks-handle-tangle-list (&optional language tangle-file)
"Can be used as :override advice for `org-babel-tangle-collect-blocks'.
Handles lists of :tangle files."
(let ((counter 0) last-heading-pos blocks)
 (org-babel-map-src-blocks (buffer-file-name)
   (let ((current-heading-pos
      (org-with-wide-buffer
       (org-with-limited-levels (outline-previous-heading)))))
 (if (eq last-heading-pos current-heading-pos) (cl-incf counter)
   (setq counter 1)
   (setq last-heading-pos current-heading-pos)))
   (unless (org-in-commented-heading-p)
 (let* ((info (org-babel-get-src-block-info 'light))
        (src-lang (nth 0 info))
        (src-tfiles (cdr (assq :tangle (nth 2 info))))) ; Tobias: accept list for :tangle
   (unless (consp src-tfiles) ; Tobias: unify handling of strings and lists for :tangle
     (setq src-tfiles (list src-tfiles))) ; Tobias: unify handling
   (dolist (src-tfile src-tfiles) ; Tobias: iterate over list
     (unless (or (string= src-tfile "no")
         (and tangle-file (not (equal tangle-file src-tfile)))
         (and language (not (string= language src-lang))))
       ;; Add the spec for this block to blocks under its
       ;; language.
       (let ((by-lang (assoc src-lang blocks))
         (block (org-babel-tangle-single-block counter)))
     (setcdr (assoc :tangle (nth 4 block)) src-tfile) ; Tobias:
     (if by-lang (setcdr by-lang (cons block (cdr by-lang)))
       (push (cons src-lang (list block)) blocks)))))))) ; Tobias: just ()
 ;; Ensure blocks are in the correct order.
 (mapcar (lambda (b) (cons (car b) (nreverse (cdr b)))) blocks)))

(defun org-babel-tangle-single-block-handle-tangle-list (oldfun block-counter &optional only-this-block)
"Can be used as :around advice for `org-babel-tangle-single-block'.
If the :tangle header arg is a list of files. Handle all files"
(let* ((info (org-babel-get-src-block-info))
  (params (nth 2 info))
  (tfiles (cdr (assoc :tangle params))))
 (if (null (and only-this-block (consp tfiles)))
 (funcall oldfun block-counter only-this-block)
   (cl-assert (listp tfiles) nil
      ":tangle only allows a tangle file name or a list of tangle file names")
   (let ((ret (mapcar
       (lambda (tfile)
         (let (old-get-info)
           (cl-letf* (((symbol-function 'old-get-info) (symbol-function 'org-babel-get-src-block-info))
              ((symbol-function 'org-babel-get-src-block-info)
               `(lambda (&rest get-info-args)
                  (let* ((info (apply 'old-get-info get-info-args))
                     (params (nth 2 info))
                     (tfile-cons (assoc :tangle params)))
                    (setcdr tfile-cons ,tfile)
                    info))))
         (funcall oldfun block-counter only-this-block))))
       tfiles)))
 (if only-this-block
     (list (cons (cl-caaar ret) (mapcar #'cadar ret)))
   ret)))))

(advice-add 'org-babel-tangle-collect-blocks :override #'org-babel-tangle-collect-blocks-handle-tangle-list)
(advice-add 'org-babel-tangle-single-block :around #'org-babel-tangle-single-block-handle-tangle-list)

TODO split these up and incorporate them in the main file

   (load "init-latex.el")
   (load "init-c++.el")

KDE integration

TODO These entries should be added to the subtree once it is split

  (defun kde-current-activity ()
"Returns the current KDE activity"
(substring (shell-command-to-string "qdbus org.kde.ActivityManager /ActivityManager/Activities org.kde.ActivityManager.Activities.CurrentActivity") 0 -1)
  )

  (defun kde-current-activity-name ()
"Returns the name of the current KDE activity"
(substring (shell-command-to-string (concat "qdbus org.kde.ActivityManager /ActivityManager/Activities org.kde.ActivityManager.Activities.ActivityName " (kde-current-activity))) 0 -1))

  (defun X-window-id-belongs-to-activity (window-id activity)
(= (shell-command (concat "xprop -id " window-id " | grep  _KDE_NET_WM_ACTIVITIES | grep " activity ">/dev/null")) 0)
  )

  (defun select-frame-on-activity (activity)
(setq framelist (frame-list))
(setq done nil)
(while (and framelist (not done))
(setq cur (car framelist))
(setq cur-id (cdr (assq 'window-id (frame-parameters cur))))
(if cur-id (if (X-window-id-belongs-to-activity cur-id activity) (progn;
  (setq done 't) (select-frame cur)) ))
(setq framelist (cdr framelist)))
done
  )

  (defun select-X-frame ()
(setq framelist (frame-list))
(setq done nil)
(while (and framelist (not done))
(setq cur (car framelist))
(setq cur-id (cdr (assq 'window-id (frame-parameters cur))))
(if cur-id (progn;
 (setq done 't) (raise-frame cur)))
(setq framelist (cdr framelist)))
done
  )

This function is used to raise the frame associated to the current activity

  (defun select-frame-on-current-activity ()
  (select-frame-on-activity (kde-current-activity)))

I prefer to keep one server for each KDE activity, so set the server name to be the name of the current activity

  (setq server-name (kde-current-activity-name))

elisp

hooks

  (add-hook 'emacs-lisp-mode-hook
(lambda ()
(outline-minor-mode)
(linum-mode)))

Replace last sexp

I use this a lot to evaluate (e.g.) quick computations in files

  (defun replace-last-sexp ()
(interactive)
(let ((value (eval (preceding-sexp))))
(kill-sexp -1)
(insert (format "%S" value))))
  (global-set-key (kbd "C-c C-x C-e") 'replace-last-sexp)

qml

Load qml-mode

  (load "qml-mode.el" nil t t)
  (add-to-list 'auto-mode-alist '("\\.qml\\'" . qml-mode))

Specialties

flash-hline

This function is defined to help in training with new keybindings. It acts as a visual bell which flashes the current line. It is (arbitrarily) bound to F15 which is supposed to be triggered by some “illegal” key hit

    (defun flash-hline ()
    "Flash the current line to emph some mistake"
    (interactive)
   (let ((fg (face-foreground 'default))
  (bg (face-background 'hl-line)))
(set-face-background 'hl-line fg)
(run-with-timer
0.1 nil (lambda ()
(set-face-background 'hl-line "#303030") ))))

 (global-set-key (kbd "<f15>") 'flash-hline)

unfill-paragraph

This is authored by Stefan Monnier <foo at acm.org>. It is the opposite of fill-paragraph

 (defun unfill-paragraph (&optional region)
   "Takes a multi-line paragraph and makes it into a single line of text."
   (interactive (progn (barf-if-buffer-read-only) '(t)))
   (let ((fill-column (point-max))
  ;; This would override `fill-column' if it's an integer.
  (emacs-lisp-docstring-fill-column t))
(fill-paragraph nil region)))

Main packages

Magit

  (global-set-key (kbd "C-x C-g") 'magit-status)

smart-tab

This package is a gem: it allows to make tab work dwim

(require 'smart-tab)
(global-smart-tab-mode 1)

Outshine

  (require 'outshine)
  (add-hook 'outline-minor-mode-hook 'outshine-hook-function)
  (setq outshine-use-speed-commands t)
  (defvar outline-minor-mode-prefix "\M-#")
  (eval-after-load 'outshine '(define-key outline-minor-mode-map (kbd "C-M-i") nil))
  ;; (add-hook 'sh-mode-hook 'outline-minor-mode)

helm

  (require 'helm-config)
  (helm-mode 1)
  (global-set-key (kbd "M-x") 'helm-M-x)
  (global-set-key (kbd "C-x C-f") 'helm-find-files)
  (global-set-key (kbd "C-x b") 'helm-mini)
  (global-set-key (kbd "C-x C-b") 'helm-mini)
  (global-set-key (kbd "M-y") 'helm-show-kill-ring)
  (define-key helm-map (kbd "C-h") nil)
  (define-key helm-find-files-map (kbd "C-h") nil)
  (define-key helm-find-files-map (kbd "C-<backspace>") nil)

multiple-cursors

(require 'multiple-cursors)
(define-key mc/keymap (kbd "<return>") nil)

(global-set-key (kbd "C->") 'mc/mark-next-like-this)
(global-set-key (kbd "C-<") 'mc/mark-previous-like-this)
(global-set-key (kbd "C-c C-<") 'mc/mark-all-like-this)

(global-set-key (kbd "C-c <f13>") 'mc/mark-pop)
(global-set-key (kbd "C-c <f14>") 'mc/mark-pop)

avy

 (global-set-key (kbd "C-c SPC") 'avy-goto-word-or-subword-1)
 (global-set-key (kbd "M-s") 'avy-goto-word-or-subword-1)
 (global-set-key (kbd "M-g M-g") 'avy-goto-line)
 (global-set-key (kbd "M-g g") 'avy-goto-line)

expand-region

This is an excellent package, although I do not use it that much I should find a better binding

 (require 'expand-region)
 (global-set-key (kbd "C-=") 'er/expand-region)

Atomic chrome

;;(require 'atomic-chrome)
;;(atomic-chrome-start-server)

TODO Phase out Package.el

Load package.el

  (require 'package)
  (add-to-list 'package-archives
 '("melpa-stable" . "http://stable.melpa.org/packages/") t)

Tidy-up

Save emacs-session files in appropriate directory

Save session files to the sessions directory so that they do not litter the .emacs.d base directory.

 (defun emacs-session-filename (session-id)
   "Construct a filename to save the session in based on SESSION-ID.
 If the directory ~/.emacs.d exists, we make a filename in there, otherwise
 a file in the home directory."
   (let ((basename (concat "sessions/session." session-id))
   (emacs-dir user-emacs-directory))
(expand-file-name (if (file-directory-p emacs-dir)
      (concat emacs-dir basename)
    (concat "~/.emacs-" basename)))))

Finale

Fixup faces

This is really a workaround as I do not like either bold or italic. It needs to be at the end of the file since it sets the face for packages that have loaded in the meantime; yet it does not wark perfectly as some packages are still to be loaded (most notably magit)

;; (set-face-font 'default "-xos4-hackminus-medium-r-normal--20-200-72-72-c-100-ISO10646-1")

 (mapc
    (lambda (face)
(set-face-attribute face nil :weight 'normal)
(set-face-attribute face nil :slant 'normal))
    (face-list))

Start server

  (server-start)