The SSH host key has changed on 8 April, 2022 to this one: SHA256:573uTBSeh74kvOo0HJXi5ijdzRm8me27suzNEDlGyrQ
My .emacs.d directory
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.

85 KiB

Emacs configuration

Set up the package archives

(require 'package)
(add-to-list 'package-archives
             '("gnu" . ""))
(add-to-list 'package-archives
             '("melpa-stable" . "") t)
(add-to-list 'package-archives
             '("melpa" . "") t)
(add-to-list 'package-archives
             '("marmalade" . "") t)
(add-to-list 'package-archives
             '("org" . "") t)

Configure use-package and preload bind-key

  (unless (package-installed-p 'use-package)
    (package-install 'use-package))

  (setq use-package-always-ensure t
        use-package-verbose t)

  (require 'use-package)

(use-package bind-key)

Set up my personal keymap

I set it up early so I can use it in use-package calls immediately.

(defvar gpolonkai/pers-map (make-sparse-keymap)
  "My own, personal, keymap!")
(define-prefix-command 'gpolonkai/pers-map)
(define-key ctl-x-map "t" 'gpolonkai/pers-map)
(define-key global-map (kbd "C-t") 'gpolonkai/pers-map)

I really don’t want to type more than I really must…

(defalias 'yes-or-no-p 'y-or-n-p)

Set UTF-8 as the default encoding

Just to make sure, although most Linux DE does this for me.

(set-language-environment "UTF-8")
(set-default-coding-systems 'utf-8)

Set personal information

Who am I?

(setq user-full-name "Gergely Polonkai"
      user-mail-address "")

Add some directories to load-path

My own (version controlled) lisp directory

(add-to-list 'load-path (expand-file-name
                         (convert-standard-filename "lisp/")
(add-to-list 'load-path (expand-file-name
                         (convert-standard-filename "lisp/nyan-prompt")

The local site-lisp

…if it exists.

(let ((site-lisp-dir "/usr/local/share/emacs/site-lisp"))
  (when (file-directory-p site-lisp-dir)
    (dolist (elt (directory-files site-lisp-dir))
      (unless (or (string= elt ".") (string= elt ".."))
        (add-to-list 'load-path (expand-file-name elt site-lisp-dir))))))

Load some prerequisites

Load xdg-paths

(load "xdg-paths")

Load the tango dark theme

(load-theme 'tango-dark t)

Custom commands and functions

Utility functions

Check if something is nil or a list of strings

(defun nil-or-list-of-strings-p (var)
  "Return t if VAR is either nil or a list holding only strings."
  (or (null var)
      (not (null (delq nil
            (mapcar (lambda (x) (and (stringp x) x)) var))))))

Get the number at point

(defun get-number-at-point ()
  (skip-chars-backward "0123456789.-")
  (or (looking-at "[0123456789.-]+")
      (error "No number at point"))
  (string-to-number (match-string 0)))

Round number at point to the given decimals

(defun round-number-at-point-to-decimals (decimal-count)
  (interactive "NDecimal count: ")
  (let ((mult (expt 10 decimal-count)))
    (replace-match (number-to-string

Make a backup filename under user-emacs-cache-directory

Taken from Xah’s site.

(defun xah/backup-file-name (fpath)
    "Return a new file path for FPATH under `user-emacs-cache-directory'"
    (let* ((backup-root-dir (expand-file-name "backup" user-emacs-cache-directory))
           (file-path (replace-regexp-in-string "[A-Za-z]:" "" fpath))
           (backup-file-path (replace-regexp-in-string "//" "/" (concat backup-root-dir file-path "~"))))
      (make-directory (file-name-directory backup-file-path) (file-name-directory backup-file-path))

Run a function on a region

(defun func-region (start end func)
  "Run a function over the region between START and END in current buffer."
    (let ((text (delete-and-extract-region start end)))
      (insert (funcall func text)))))

Check if we are running under Termux

We need to do things differently, if so.

(defun termux-p ()
  "Check if Emacs is running under Termux."
   (regexp-quote "/com.termux/")
   (expand-file-name "~")))

Misc text manipulation functions

Delete the current line

(defun gpolonkai/delete-current-line ()
  "Kill the whole line on which point is."

  (kill-line 1))

Duplicate current line

(defun gpolonkai/duplicate-line()
  "Duplicate line at point."


    (move-beginning-of-line 1)
    (open-line 1)
    (forward-line 1)

Toggle case of character at point

Based on Xah’s toggle letter case defun version 2015-12-22

(defun toggle-char-case (arg-move-point)
  "Toggle the case of the char after point.

If prefix argument ARG-MOVE-POINT is non-nil, move point after the char."
  (interactive "P")
  (let ((case-fold-search nil))
     ((looking-at "[[:lower:]]") (upcase-region (point) (1+ (point))))
     ((looking-at "[[:upper:]]") (downcase-region (point) (1+ (point)))))
     (arg-move-point (right-char)))))

Open a new line below

Copied from

(defun open-line-below ()
  "Open a new line below point."



Open a new line above

(defun open-line-above ()
  "Open a new line above point."


  (forward-line -1)

TODO Kill or copy the whole line

Got from Xah’s site (TODO is for adding a link here.)

(defun æ-kill-or-copy-whole-line (kill)
  "Kill or copy the whole line point is on.

If KILL is non-nil, the line gets killed.  Otherwise, it gets just
copied to the kill ring."
  (interactive "P")

  (if kill
    (let ((beginning (progn (beginning-of-line) (point)))
          (end (progn (end-of-line) (point))))
      (copy-region-as-kill beginning end))))

Enclose region in a specific character

(defun æ-enclose-region (character &optional start end)
  "Enclose region in CHARACTER. If region is empty, simply inserts
  CHARACTER two times and moves point between them.

  If character is present in `insert-pair-alist', this function
  will enclose region in the corresponding pair. In this case,
  CHARACTER must be the opening member of the pair."

  (interactive "cWhat character? \nr")

  (setq open character close character)

  (let ((pair (assq character insert-pair-alist)))
    (if pair
        (if (nth 2 pair)
            (setq open (nth 1 pair) close (nth 2 pair))
          (setq open (nth 0 pair) close (nth 1 pair)))))

  (unless (and open close)
    (setq open character)
    (setq close character))

  (unless (use-region-p)
    (setq start (point) end (point)))

    (goto-char end)
    (insert-char close)

    (goto-char start)
    (insert-char open))

  (unless (use-region-p)

Convert camelCase to snakecase

(defun camel-to-snake-case (arg)
  "Convert a camel case (camelCase or CamelCase) word to snake case (snake_case).

If the prefix argument ARG is non-nil, convert the text to uppercase."
  (interactive "p")
    (let ((start (region-beginning))
          (end (region-end))
          (case-fold-search nil)
          (had-initial-underscore nil))
      (goto-char start)
      (when (looking-at "_") (setq had-initial-underscore t))
      (while (re-search-forward "\\([A-Z]\\)" end t)
        (replace-match "_\\1")
        (setq end (1+ end)))
      (if arg
          (upcase-region start end)
        (downcase-region start end))
      (goto-char start)
      (unless had-initial-underscore (delete-char 1)))))

Insert two spaces after specific characters

(defun org-space-key (&optional arg)
  "Insert two spaces after a period.

ARG will be passed down verbatim to `self-insert-command'"
  (interactive "p")

  (when (looking-back "[.!?…]" nil)
    (call-interactively 'self-insert-command arg))
  (call-interactively 'self-insert-command arg))

Fill or unfill a paragraph


(defun sachachua/fill-or-unfill-paragraph (&optional unfill region)
  "Fill (or unfill, if UNFILL is non-nil) paragraph (or REGION)."
  (interactive (progn
                 (list (if current-prefix-arg 'unfill) t)))
  (let ((fill-column (if unfill (point-max) fill-column)))
    (fill-paragraph nil region)))

Swap occurences of strings

Copied from

(defun so/query-swap-strings (from-string
                              &optional delimited start end)
  "Swap occurrences of FROM-STRING and TO-STRING.

DELIMITED, START, and END are passed down verbatim to `perform-replace'."
   (let ((common
           (concat "Query swap"
                   (if current-prefix-arg
                       (if (eq current-prefix-arg '-) " backward" " word")
                   (if (use-region-p) " in region" ""))
     (list (nth 0 common) (nth 1 common) (nth 2 common)
           (if (use-region-p) (region-beginning))
           (if (use-region-p) (region-end)))))
   (concat "\\(" (regexp-quote from-string) "\\)\\|" (regexp-quote to-string))
   `(replace-eval-replacement replace-quote
                              (if (match-string 1)
   t t delimited nil nil start end))


Move to different beginnings of the current line

Inspired by Bozhidar Batsov's solution.

(defun gpolonkai/move-to-beginning-of-line ()
  "Move to different beginnings of the line.

These are, in order:

- beginning of the visual line if `visual-line-mode' is active,
- the first non-whitespace (indentation),
- the actual beginning of the line.

This function will jump between the first character and the
indentation if used multiple times."
  (let ((last-pos (point)))
    (when visual-line-mode
    (when (= (point) last-pos)
    (when (= (point) last-pos)
    (when (and (eq major-mode 'org-mode)
               (= (point) last-pos))
    (when (= (point) last-pos)

Move to the different ends of the current line

(defun gpolonkai/move-to-end-of-line ()
  "Move to the end of the line.

If `visual-line-mode' is active, jump to the end of the visual
line first.  Then jump to the actual end of the line."
  (let ((last-pos (point)))
    (when visual-line-mode
    (when (= (point) last-pos)
    (when (and (eq major-mode 'org-mode)
               (= (point) last-pos))

File manipulation

Rename the current file

Copied from

(defun rename-current-buffer-file ()
  "Renames current buffer and file it is visiting."

  (let ((name (buffer-name))
        (filename (buffer-file-name)))
    (if (not (and filename (file-exists-p filename)))
        (error "Buffer '%s' is not visiting a file!" name)
      (let ((new-name (read-file-name "New name: " filename)))
        (if (get-buffer new-name)
            (error "A buffer named '%s' already exists!" new-name)
          (rename-file filename new-name 1)
          (rename-buffer new-name)
          (set-visited-file-name new-name)
          ; TODO: this is suspicious for me…
          (set-buffer-modified-p nil)
          (message "File '%s' successfully renamed to '%s'"
                   name (file-name-nondirectory new-name)))))))

Delete the current file

Copied from

(defun delete-current-buffer-file ()
  "Remove file connected to current buffer and kill the buffer."

  (let ((filename (buffer-file-name))
        (name (buffer-name))
        (buffer (current-buffer)))
    (if (not (and filename (file-exists-p filename)))
        (kill-buffer buffer)
      (when (yes-or-no-p "Are you sure you want to remove this file? ")
        (delete-file filename)
        (kill-buffer buffer)
        (message "File '%s' successfully removed" filename)))))

Allow reopening the previously closed file

(defvar gpolonkai/last-killed-buffer-file-name
  "The last killed buffer.

Used by `gpolonkai/save-killed-buffer-filename' and `gpolonkai/undo-buffer-kill'.")

(defun gpolonkai/save-killed-buffer-filename ()
  "Save the filename of the killed buffer in `gpolonkai/last-killed-buffer-file-name'."
  (let ((filename (buffer-file-name)))
   (unless filename
    (setq gpolonkai/last-killed-buffer-file-name (buffer-file-name)))))

(add-hook 'kill-buffer-hook 'gpolonkai/save-killed-buffer-filename)

(defun gpolonkai/undo-buffer-kill ()
  "Undo killing the last buffer.

Esentially it visits the file again."
  (if gpolonkai/last-killed-buffer-file-name
        (find-file gpolonkai/last-killed-buffer-file-name)
        (setq gpolonkai/last-killed-buffer-file-name nil))
    (message "The buffer last killed didn’t visit a file.")))

Open this file as another user

(defun open-this-file-as-other-user (user)
  "Edit current file as USER, using `tramp' and `sudo'.

If the current buffer is not visiting a file, prompt for a file
  (interactive "sEdit as user (default: root): ")
  (when (string= "" user)
    (setq user "root"))
  (let* ((filename (or buffer-file-name
                       (read-file-name (format "Find file (as %s): "
         (tramp-path (concat (format "/sudo:%s@localhost:" user) filename)))
    (if buffer-file-name
        (find-alternate-file tramp-path)
      (find-file tramp-path))))

Open my own init.el

(defun gpolonkai/visit-init-file ()
  "Open the init file."
  (find-file-other-window (expand-file-name "" user-emacs-directory)))

Open my Org-mode index file

(defun gpolonkai/visit-org-index ()
  "Visit the root of Org-mode notes."
  (find-file-other-window (concat (file-name-as-directory org-directory)

Frame manipulation

Hidden modeline mode

To temporarily hide the mode line.

Copied from

(defvar hidden-mode-line-mode nil)
(defvar hide-mode-line nil)

(define-minor-mode hidden-mode-line-mode
  "Minor mode to hide the mode-line in the current buffer."
  :init-value nil
  :global nil
  :variable hidden-mode-line-mode
  :group 'editing-basics
  (if hidden-mode-line-mode
      (setq hide-mode-line mode-line-format
            mode-line-format nil)
    (setq mode-line-format hide-mode-line
          hide-mode-line nil))
  (when (and (called-interactively-p 'interactive)
     0 nil 'message
     (concat "Hidden Mode Line Mode enabled.  "
             "Use M-x hidden-mode-line-mode to make mode-line appear."))))

Window manipulation

Transpose windows

(defun transpose-windows (arg)
  "Transpose the buffers shown in two windows."
  (interactive "p")
  (let ((selector (if (>= arg 0) 'next-window 'previous-window)))
    (while (/= arg 0)
      (let ((this-win (window-buffer))
            (next-win (window-buffer (funcall selector))))
        (set-window-buffer (selected-window) next-win)
        (set-window-buffer (funcall selector) this-win)
        (select-window (funcall selector)))
      (setq arg (if (plusp arg) (1- arg) (1+ arg))))))

Toggle window split between horizontal and vertical

(defun toggle-window-split ()
  (if (= (count-windows) 2)
      (let* ((this-win-buffer (window-buffer))
             (next-win-buffer (window-buffer (next-window)))
             (this-win-edges (window-edges (selected-window)))
             (next-win-edges (window-edges (next-window)))
             (this-win-2nd (not (and (<= (car this-win-edges)
                                         (car next-win-edges))
                                     (<= (cadr this-win-edges)
                                         (cadr next-win-edges)))))
              (if (= (car this-win-edges)
                     (car (window-edges (next-window))))
        (let ((first-win (selected-window)))
          (funcall splitter)
          (if this-win-2nd (other-window 1))
          (set-window-buffer (selected-window) this-win-buffer)
          (set-window-buffer (next-window) next-win-buffer)
          (select-window first-win)
          (if this-win-2nd (other-window 1))))
    (error "This works only for two windows!")))

Scroll up or down in a specific window

(defun gpolonkai/scroll-window-up (window)
  "Scroll WINDOW up as `scroll-up-command' would."
    (select-window window)

(defun gpolonkai/scroll-window-down (window)
  "Scroll WINDOW down as `scroll-down-command' would."
    (select-window window)

Bury a window

(defun gpolonkai/bury-window (window)
  "Quit WINDOW without killing it."
  (quit-window nil window))

Copy the prototype of the current function

(defun gpolonkai/copy-func-prototype ()
  "Copy the current function's prototype to the kill ring."


    (let ((protocopy-begin (point)))
      (let ((protocopy-end (point)))
        (kill-ring-save protocopy-begin protocopy-end)))))

Check if we are inside a string

(defun gpolonkai/prog-in-string-p ()
  "Return t if point is inside a string."
  (nth 3 (syntax-ppss)))

Check if we are inside a comment

(defun gpolonkai/prog-in-comment-p ()
  "Return t if point is inside a comment."
  (nth 4 (syntax-ppss)))

Add a docstring to the current thing

…be it a function, class, or a module

(defun gpolonkai/python-add-docstring ()
  "Add a Python docstring to the current thing.

If point is inside a function, add docstring to that.  If point
is in a class, add docstring to that.  If neither, add docstring
to the beginning of the file."
    (if (not (looking-at-p "\\(def\\|class\\) "))
          (goto-char (point-min))
          (while (gpolonkai/prog-in-comment-p)
      (search-forward ":")
      (while (or (gpolonkai/prog-in-string-p)
        (search-forward ":")))
    (if (eq 1 (count-lines 1 (point)))
    (insert "\"\"\"")
    (insert "\"\"\"")

Get specific fields from a record in idm

(defun gpolonkai/idm-record-get-field (record field)
  "Get FIELD of an id-manager RECORD."
  (let ((funcname (intern (concat "idm-record-" (symbol-name field)))))
    (when (fboundp funcname)
      (funcall funcname record))))

(defun gpolonkai/idm-get-field-for-account (account field)
  "Get id-manager password for ACCOUNT."
  (let ((db (idm-load-db))
        (lookup-record nil))
    (dolist (record (funcall db 'get-all-records) password)
      (when (string= account (idm-record-name record))
        (setq lookup-record (gpolonkai/idm-record-get-field record field))))

(defmacro gpolonkai/idm-get-password-for-account (account)
  `(gpolonkai/idm-get-field-for-account ,account 'password))

(defmacro gpolonkai/idm-get-id-for-account (account)
  `(gpolonkai/idm-get-field-for-account ,account 'account-id))

Mark a string as translatable

(defun jinja-mark-translatable (begin end)
  (interactive (if (use-region-p)
                   (list (region-beginning) (region-end))
                 (list (point-min) (point-max))))
    (goto-char end)
    (insert "{% endtrans %}")
    (goto-char begin)
    (insert "{% trans %}")))

URL-ify and de-URL-ify region

These functions URL-encode/decode a text. Might be helpful when embedding/extracting data to/from HTML.

(defun hex-region (start end)
  "urlencode the region between START and END in current buffer."
  (interactive "r")
  (func-region start end #'url-hexify-string))

(defun unhex-region (start end)
  "de-urlencode the region between START and END in current buffer."
  (interactive "r")
  (func-region start end #'url-unhex-string))

Automatically zone out after 60 seconds

(defun gpolonkai/zone-enable ()
  "Enable zoning out."
  (zone-when-idle 60)
  (message "I will zone out after idling for 60 seconds."))

Utility functions for editing Zim wiki files

(defun zim-timestamp ()
    (insert (format-time-string "%Y-%m-%dT%H:%M:%S%z"))
    (forward-char -2)
    (insert ":")

(defun insert-zim-timestamp ()
  (insert (zim-timestamp)))

(defun insert-zim-header ()
    (goto-char (point-min))
     (concat "Content-Type: text/x-zim-wiki\n"
             "Wiki-Format: zim 0.4\n"
             "Creation-Date: " (zim-timestamp) "\n\n"))))

Utility functions for EDiff

EDiff and Org-mode files don’t play nice together

From gmane.emacs.orgmode

(defun f-ediff-org-showhide (buf command &rest cmdargs)
  "If buffer BUF exists and in `org-mode', execute COMMAND with CMDARGS."
  (when buf
    (when (eq (buffer-local-value 'major-mode (get-buffer buf)) 'org-mode)
        (set-buffer buf)
        (apply command cmdargs)))))

(defun f-ediff-org-unfold-tree-element ()
  "Unfold tree at diff location."
  (f-ediff-org-showhide ediff-buffer-A 'org-reveal)
  (f-ediff-org-showhide ediff-buffer-B 'org-reveal)
  (f-ediff-org-showhide ediff-buffer-C 'org-reveal))

(defun f-ediff-org-fold-tree ()
  "Fold tree back to top level."
  (f-ediff-org-showhide ediff-buffer-A 'hide-sublevels 1)
  (f-ediff-org-showhide ediff-buffer-B 'hide-sublevels 1)
  (f-ediff-org-showhide ediff-buffer-C 'hide-sublevels 1))

Leave isearch at the other end of the matched string

Taken from endless parentheses

(defun isearch-exit-other-end ()
  "Exit isearch, at the opposite end of the string."

  (goto-char isearch-other-end))

Mark the current match after leaving isearch

Taken from here.

(defun isearch-exit-mark-match ()
  "Exit isearch and mark the current match."
  (push-mark isearch-other-end)

Make the slash (/) key act like C-j in some Helm views

(defun gpolonkai/helm-ff-slash-dir-complete ()
  "Make forward slash (/) do completion in helm."
  (if (and (or
            (equal "magit-status" (assoc-default 'name (helm-get-current-source)))
            (equal "Find Files" (assoc-default 'name (helm-get-current-source)))
            (equal "helm-mode-insert-file" (assoc-default 'name (helm-get-current-source))))
           (stringp (helm-get-selection))
           (file-directory-p (helm-get-selection)))
    (insert "/")))

Turn the cursor to purple if Yasnippet’s TAB function would fire

Taken from Sacha Chua’s config.

;; TODO: 'cursor-color is sometimes nil, but why?
(setq default-cursor-color (or (frame-parameter nil 'cursor-color) "#ffd85c"))
(setq yasnippet-can-fire-cursor-color "purple")

;; It will test whether it can expand, if yes, cursor color -> purple.
(defun yasnippet-can-fire-p (&optional field)
  "Check if the word before point can be expanded with yasnippet.

TODO: What is FIELD for?"
  (setq yas--condition-cache-timestamp (current-time))
  (let (templates-and-pos)
    (unless (and yas-expand-only-for-last-commands
                 (not (member last-command yas-expand-only-for-last-commands)))
      (setq templates-and-pos (if field
                                    (narrow-to-region (yas--field-start field)
                                                      (yas--field-end field))
    (and templates-and-pos (first templates-and-pos))))

(defun sachachua/change-cursor-color-when-can-expand (&optional field)
  "Change cursor color if the text before point can be expanded with yasnippet.

TODO: What is FIELD for?"
  (when (eq last-command 'self-insert-command)
    (set-cursor-color (if (sachachua/can-expand)

(defun sachachua/can-expand ()
  "Return t if right after an expandable thing."
  (or (abbrev--before-point) (yasnippet-can-fire-p)))

Filter out tasks from the Org agenda if they have a specific priority

The whole idea comes from here, which i use almost verbatim. This is also the reason it has the air- prefix.

(defun air-org-skip-subtree-if-priority (priority)
  "Skip an agenda subtree if it has a priority of PRIORITY.

PRIORITY may be one of the characters ?A, ?B, or ?C."
  (let ((subtree-end (save-excursion (org-end-of-subtree t)))
        (pri-value (* 1000 (- org-lowest-priority priority)))
        (pri-current (org-get-priority (thing-at-point 'line t))))
    (if (= pri-value pri-current)

Filter out habits from the Org agenda

(defun air-org-skip-subtree-if-habit ()
  "Skip an agenda entry if it has a STYLE property equal to \"habit\"."
  (let ((subtree-end (save-excursion (org-end-of-subtree t))))
    (if (string= (org-entry-get nil "STYLE") "habit")

Filter out entries from the Org agenda with a specific state

(defun gpolonkai/org-skip-subtree-if-state (state)
  "Skip an agenda entry if its state is STATE."
  (let ((subtree-end (save-excursion (org-end-of-subtree t))))
    (if (string= (org-get-todo-state) state)

Wrapper around org-agenda to open my own custom list

(defun gpolonkai/org-agenda-list (&optional arg)
  (interactive "P")
  (org-agenda arg "c"))

UI preferences

Tweak window chrome

Turn off the scroll bar (that’s why Nyan-cat is here), the toolbar (I don’t really use it), and the menu bar (I rarely use it, and in those rare occasions I can simply turn it on.)

Also, maximise the frame.

(tool-bar-mode 0)
(menu-bar-mode 0)
(when window-system
  (scroll-bar-mode -1))

(set-frame-parameter nil 'fullscreen 'maximized)

Set the default font and configure font resizing

Before this can be used, make sure the Symbola font is installed.

(defun gpolonkai/set-font-size (frame)
  (set-face-attribute 'default t :font "Hack-12")
  (set-frame-font "Hack-12" t t))

(defun --set-emoji-font (frame)
  "Adjust the font setting of FRAME so Emacs can display Emoji properly."
  (when (fboundp 'set-fontset-font)
    (if (eq system-type 'darwin)
        ;; For NS/Cocoa
        (set-fontset-font t 'symbol
                          (font-spec :family "Apple Color Emoji")
                          frame 'prepend)
      ;; For Linux
      (set-fontset-font t 'symbol
                       (font-spec :family "Symbola")
                       frame 'prepend))))

(add-hook 'after-make-frame-functions 'gpolonkai/set-font-size)
(add-hook 'after-make-frame-functions '--set-emoji-font)

Set up global minor modes provided by Emacs

Pretty lambdas

Because we can.

(global-prettify-symbols-mode t)

And set up all the pretty symbols.

;; Add some symbols to be prettified
(setq prettify-symbols-alist
      '(("lambda" . 955)    ; λ
        ("function" . 402)  ; ƒ
        ("->" . 8594)       ; →
        ("=>" . 8658)       ; ⇒
        ("map" . 8614)      ; ↦
        ("not" . 172))      ; ¬

      ;; …and some pairs to complete
      ;; TODO: maybe add-to-list is a better way to do it
      insert-pair-alist '(
                          (40 41)      ; ()
                          (91 93)      ; []
                          (123 125)    ; {}
                          (60 62)      ; <>
                          (34 34)      ; ""
                          (39 39)      ; ''
                          (96 39)      ; `'
                          (8220 8221)  ; “”
                          (8222 8221)  ; „”
                          (8216 8217)  ; ‘’
                          (8249 8250)  ; ‹›
                          (8250 8249)  ; ›‹
                          (171 187)    ; «»
                          (187 171))   ; »«

      ;; Set the frame title to the current file name
      frame-title-format '((:eval (concat system-name
                                          ": "
                                          (if (buffer-file-name)

Treat soft line breaks as hard ones in textual modes

(add-hook 'text-mode-hook (lambda () (visual-line-mode t)))

Enable disabled commands

Because I’m a rock star like that.

(put 'downcase-region 'disabled nil)
(put 'upcase-region 'disabled nil)
(put 'erase-buffer 'disabled nil)
(put 'narrow-to-region 'disabled nil)
(put 'narrow-to-page 'disabled nil)
(put 'set-goal-column 'disabled nil)
(put 'scroll-left 'disabled nil)
(put 'dired-find-alternate-file 'disabled nil)
(put 'Info-edit 'disabled nil)
(put 'list-timers 'disabled nil)

Load some built-in libraries


(use-package thingatpt
  :ensure nil)


(use-package calendar
  :ensure nil
  (setq calendar-week-start-day 1
        calendar-latitude 47.4
        calendar-longitude 19.0
        calendar-location-name "Budapest, Hungary"
        calendar-time-zone 60
        calendar-standard-time-zone-name "CET"
        calendar-daylight-time-zone-name "CEST"))

Add the SysAdmin day to the calendar

Because I’m a sysadmin, too.

(add-to-list 'holiday-other-holidays '(holiday-float 7 5 -1 "SysAdmin Day") t)
(add-to-list 'holiday-other-holidays '(holiday-fixed 10 21 "Reptile Awareness Day") t)


(use-package nxml-mode
  :ensure nil
  (setq nxml-attribute-indent 4
        nxml-child-indent 2
        nxml-outline-child-indent 4))


(use-package recentf
  :ensure nil
  (run-at-time nil (* 5 60) 'recentf-save-list)
  (add-to-list 'recentf-exclude (concat user-emacs-directory "elpa")))


(use-package files
  :ensure nil
  (setq make-backup-file-name-function 'xah/backup-file-name))


whitespace-mode is turned on by default, and can be toggled with F10.

(defun prevent-whitespace-mode-for-magit ()
  "Prevent whitespace-mode from running in magit derived modes."
  (not (derived-mode-p 'magit-mode)))

(use-package whitespace
  (add-function :before-while whitespace-enable-predicate 'prevent-whitespace-mode-for-magit)
  (global-whitespace-mode 1)
  (setq whitespace-line-column 100)
  (([f10] . whitespace-mode)
   ([(shift f10)] . global-whitespace-mode)
   :map gpolonkai/pers-map
   ("w" . whitespace-cleanup)))


This is a function to delete a character, or close eshell if there’s nothing to delete. Taken from here.

(defun eshell-C-d ()
  "Either call `delete-char' interactively or quit."

  (condition-case err
      (call-interactively #'delete-char)
    (error (if (and (eq (car err) 'end-of-buffer)
                    (looking-back eshell-prompt-regexp nil))
             (signal (car err) (cdr err))))))

Function to bind it locally to C-d.

(defun gpolonkai/eshell-set-c-d-locally ()
  (local-set-key (kbd "C-d") #'eshell-C-d))

Now set up eshell.

(use-package eshell
  (:map gpolonkai/pers-map
   ("e" . eshell))
  (eshell-mode . gpolonkai/eshell-set-c-d-locally))


;; Save place
(use-package saveplace
  (if (version< emacs-version "25.0")
      (setq-default save-place t)
    (save-place-mode 1))
  (setq save-place-file (expand-file-name ".places" user-emacs-directory)))

ID manager

Manage credentials, AKA password manager.

(use-package id-manager
  (setq idm-database-file (expand-file-name "idm-db.gpg" user-emacs-directory))
  (:map gpolonkai/pers-map
   ("i" . idm-open-list-command)))


(use-package ediff
  (setq-default ediff-merge-split-window-function 'split-window-horizontally
                ediff-split-window-function 'split-window-vertically
                ediff-window-setup-function 'ediff-setup-windows-plain))

Automatically revert changed files

…unless they are modified, of course.

(use-package autorevert
  (global-auto-revert-mode 1))


For in-Emacs browsing needs.

(use-package eww
  (setq eww-search-prefix ""))

Electric indent mode

(use-package electric
  ;; This seems to be the default, but let’s make sure…
  (electric-indent-mode 1))

Save history

(use-package savehist
  (savehist-mode 1))

Web jump

(use-package webjump
  (:map gpolonkai/pers-map
   ("j" . webjump)))

Which function am I in?

(defun gpolonkai/activate-which-func-mode ()
  (if (fboundp 'which-function-mode)
(use-package which-func
  (setq which-func-unknown "∅")
  (prog-mode . gpolonkai/activate-which-func-mode))

Fortune cookies

The cookies are from the Hungarian version an ancient MS-DOS based program called TAGLINE.

(use-package cookie1
  :demand t
  (setq cookie-file (concat user-emacs-directory "fortune-cookies.txt"))
  (:map gpolonkai/pers-map
   ("k" . cookie)))

News reader

(use-package newsticker
  (setq newsticker-url-list '(("(or emacs irrelevant)"
                               nil nil nil)
                               nil nil nil)
                              ("Endless Parentheses"
                               nil nil nil)
                               nil nil nil)
                              ;; The followint may supersede previous entries
                              ("Planet Emacs"
                               nil nil nil)))
  (:map gpolonkai/pers-map
   ("n" . newsticker-show-news)))

Browse URL functionality in Termux

(when (termux-p)
  (use-package browse-url
    :ensure nil
    (advice-add 'browse-url-default-browser :override
                (lambda (url &rest args)
                   (concat "am start -a android.intent.action.VIEW --user 0 -d "

Dired customisation

(use-package dired
  :ensure nil
  (setq dired-dwim-target t)
  (:map dired-mode-map
   ("RET" . dired-find-alternate-file)
   ("^" . (lambda () (interactive) (find-alternate-file "..")))
   ("W" . wdired-change-to-wdired-mode)))

(use-package dired-x
  :ensure nil)

Actionable URLs

(use-package goto-addr
  :hook ((compilation-mode . goto-address-mode)
         (prog-mode . goto-address-prog-mode)
         (eshell-mode . goto-address-mode)
         (shell-mode . goto-address-mode))
  (:map goto-address-highlight-keymap
   ("<RET>" . goto-address-at-point)
   ("M-<RET>" . newline))
  :commands (goto-address-prog-mode goto-address-mode))

Do things at midnight

By default, it closes a bunch of unused buffers. I might add some more things there later.

(use-package midnight
  :ensure nil
  (setq clean-buffer-list-kill-never-buffer-names '("*scratch*"
  (midnight-mode t))

Show line numbers

I don’t usually like to see them, but there are occasions when they can be useful.

(use-package display-line-numbers
  (:map gpolonkai/pers-map
   ("C-n" . display-line-numbers-mode)))

use-package packages

Automatically upgrade packages every week

(use-package auto-package-update
  (setq auto-package-update-interval 7
        auto-package-update-delete-old-versions t)
  ;; Let’s do this in after-init-hook, as use-package invocations may modify
  ;; the list of installed packages
  (after-init . auto-package-update-maybe))


Nyan-cat style position marker

(use-package nyan-mode
  (setq-default nyan-animate-nyancat t
                nyan-wavy-trail t)
  (customize-set-variable 'nyan-bar-length 20)
  (nyan-mode t))

Nyan prompt in EShell

(use-package nyan-prompt
  :ensure nil)

Zone out with Nyancat

Unfortunately, this works only in a graphical mode.

(use-package zone-nyan
  (setq-default zone-nyan-hide-progress t)
  (setq zone-programs (vconcat zone-programs [zone-nyan])))

De-light some minor modes

(use-package delight)

Eye candy

Moody mode-line

(use-package moody
  (customize-set-variable 'moody-mode-line-height 18)
  (set-face-attribute 'mode-line nil :box nil :foreground "#7e7486")
  (set-face-attribute 'mode-line-inactive nil :box nil))


(use-package minions
  (minions-mode 1))

Spinner, e.g. to display running background tasks

(use-package spinner)


Highlight point. Sometimes it’s not easy to see.

(use-package beacon
  (beacon-mode 1)
  (:map gpolonkai/pers-map
   ("b" . beacon-blink)))

Display the status of the last command in the fringe of EShell

(use-package eshell-fringe-status
  (eshell-mode . eshell-fringe-status-mode))

Extras for the EShell prompt

(use-package eshell-prompt-extras
  (with-eval-after-load "esh-opt"
    (autoload 'epe-theme-lambda "eshell-prompt-extras")
    (setq eshell-highlight-prompt nil
          eshell-prompt-function 'epe-theme-lambda)
    (when (featurep 'nyan-prompt)

Show form feeds as a horizontal line

(use-package form-feed
  (emacs-lisp-mode . form-feed-mode)
  (compilation-mode . form-feed-mode))

Highlight the current line

(use-package hl-line
  (when window-system

GNU Globals

(defun gpolonkai/cond-enable-ggtags-mode ()
  (when (derived-mode-p 'c-mode 'c++-mode 'java-mode)
    (ggtags-mode t)))

(use-package ggtags
  (c-mode-common . gpolonkai/cond-enable-ggtags-mode))

Multiple cursors

Because one is never enough.

(defun gpolonkai/no-blink-matching-paren ()
  (setq blink-matching-paren nil))

(defun gpolonkai/blink-matching-paren ()
  (setq blink-matching-paren t))

(use-package multiple-cursors
  (defvar gpolonkai/mc-prefix-map (make-sparse-keymap)
    "Prefix keymap for multiple-cursors")
  (define-prefix-command 'gpolonkai/mc-prefix-map)
  (define-key global-map (kbd "C-c m") 'gpolonkai/mc-prefix-map)
  (multiple-cursors-mode-enabled . gpolonkai/no-blink-matching-paren)
  (multiple-cursors-mode-disabled . gpolonkai/blink-matching-paren)
  :bind (:map gpolonkai/mc-prefix-map
         ("t" . mc/mark-all-like-this)
         ("m" . mc/mark-all-like-this-dwim)
         ("l" . mc/edit-lines)
         ("e" . mc/edit-ends-of-lines)
         ("a" . mc/edit-beginnings-of-lines)
         ("n" . mc/mark-next-like-this)
         ("p" . mc/mark-previous-like-this)
         ("s" . mc/mark-sgml-tag-pair)
         ("d" . mc/mark-all-like-this-in-defun)))

Incremental search for multiple cursors

(use-package phi-search)

(use-package phi-search-mc

Some extras

(use-package mc-extras
  (:map mc/keymap
   ("C-c m =" . mc/compare-chars)))

Add extra cursors via ace-jump

(use-package ace-mc
  (:map gpolonkai/mc-prefix-map
   ("SPC" . ace-mc-add-multiple-cursors)))


(use-package magit
  (setq magit-auto-revert-mode nil
        magit-last-seen-setup-instructions "1.4.0"
        magit-push-always-verify nil)
  (:map ctl-x-map
   ("g" . magit-status))
  (git-commit-mode . turn-on-flyspell))


(use-package zone
  (zone-when-idle 60)
  (:map gpolonkai/pers-map
   ("zi" . gpolonkai/zone-enable)
   ("zq" . zone-leave-me-alone)))


(use-package origami
  (define-prefix-command 'origami-mode-map)
  (define-key ctl-x-map (kbd "z") 'origami-mode-map)
  (:map origami-mode-map
   ("o" . origami-open-node)
   ("O" . origami-open-node-recursively)
   ("c" . origami-close-node)
   ("C" . origami-close-node-recursively)
   ("a" . origami-toggle-node)
   ("A" . origami-recursively-toggle-node)
   ("R" . origami-open-all-nodes)
   ("M" . origami-close-all-nodes)
   ("v" . origami-show-only-node)
   ("k" . origami-previous-fold)
   ("j" . origami-forward-fold)
   ("x" . origami-reset)))

Smart parens

(use-package smartparens
  (show-smartparens-global-mode t)
  (prog-mode . turn-on-smartparens-strict-mode)
  (markdown-mode . turn-on-smartparens-strict-mode)
  (([f9] . smartparens-strict-mode)
   ("C-c s u" . sp-unwrap-sexp)
   ("C-c s k" . sp-kill-sexp)))


(use-package projectile
  :delight '(:eval (concat " [" projectile-project-name "]"))
  :pin melpa-stable
  (projectile-global-mode t))

Repository-based ToDo management with Org mode

(use-package org-projectile)

…and the same with Helm

(use-package org-projectile-helm)

Text object manipulation

From the package description:

Text objects are textual patterns like a line, a top level definition, a word, a sentence or any other unit of text. When objed-mode is enabled, certain editing commands (configurable) will activate objed and enable its modal editing features.

(use-package objed
  :demand t
  (:map global-map
   ("M-SPC" . objed-activate)))

Ace window

Besides its standard functionality, I also make add key bindings for burying or scrolling another window.

(use-package ace-window
  (setq aw-background nil
        aw-dispatch-always t)
  (add-to-list 'aw-dispatch-alist
               '(?s gpolonkai/scroll-window-up " Scroll window up")
  (add-to-list 'aw-dispatch-alist
               '(?S gpolonkai/scroll-window-down " Scroll window down")
  (add-to-list 'aw-dispatch-alist
               '(?q gpolonkai/bury-window " Bury (quit) window")
  (:map ctl-x-map
   ("o" . ace-window)))


(use-package avy
  (defadvice avy-goto-line (around avy-fci activate)
    (let ((fci-was-on (if (boundp 'fci-mode) fci-mode nil)))
      (when fci-was-on
        (fci-mode -1))
      (when fci-was-on
        (fci-mode 1))))
  (("M-g c" . avy-goto-char)
   ("M-g C" . avy-goto-char-2)
   ("M-g f" . avy-goto-line)
   ("M-g w" . avy-goto-word-1)
   ("M-g e" . avy-goto-word-0)))

Focus mode

It is similar to narrow mode, except the narrowing part; it dims everything outside of the current context.

(use-package focus
  (([f8] . focus-mode)))

Command logging mode

For occasional screen casting recordings.

(use-package command-log-mode)


For controlling tmux from within Emacs.

(use-package emamux)

Use StackExchange sites in an Emacs window

(use-package sx
  (:map gpolonkai/pers-map
   ("qi" . sx-inbox)
   ("qs" . sx-search)))

Goto last change

(use-package goto-last-change
  (("M-g /" . goto-last-change)))

Rainbow mode

To highlight colours based on their name or hex code.

(use-package rainbow-mode
  (css-mode . rainbow-mode)
  (scss-mode . rainbow-mode)
  (sass-mode . rainbow-mode))


Toggle other windows for maximum focus. When focus is no longer needed, they can be toggled back. C-x 1 is conveniently bound to it.

(use-package zygospore
  (:map ctl-x-map
   ("1" . zygospore-toggle-delete-other-windows)))

Kanban board

(use-package kanban)

Highlight dired buffer by file size, modified time, git status

(use-package dired-k
  (:map dired-mode-map
   ("K" . dired-k)))

Show number of matches in the mode line while searching

(use-package anzu
  (global-anzu-mode 1))

Gradually expand region

(use-package expand-region
  (:map gpolonkai/pers-map
   ("x" . er/expand-region)))

Read and Edit MediaWiki pages in an Emacs window

(use-package mediawiki
  (add-to-list 'mediawiki-site-alist
                 (gpolonkai/idm-get-id-for-account "WikEmacs")
                 (gpolonkai/idm-get-password-for-account "WikEmacs"))))

Display unread GitHub notification count in the mode line

(use-package github-notifier
  (setq github-notifier-token (gpolonkai/idm-get-password-for-account "GitHub"))

Interact with GitHub gists

(use-package gist)

An Emacs Dashboard

(use-package dashboard
  (add-to-list 'dashboard-items '(projects . 5) t)

Hungarian holidays in the Calendar

(use-package hungarian-holidays


For all your spell-checking needs.

(use-package flyspell
  (prog-mode . flyspell-prog-mode)
  (text-mode . flyspell-mode))

Delete all the whitespace

(use-package hungry-delete

Send alerts to a notification system

(use-package alert
  (setq alert-default-style
        (if (termux-p)
              ;; TODO Remove this as soon as my PR gets merged
              (unless (fboundp 'alert-termux-notify)
                (defcustom alert-termux-command (executable-find "termux-notification")
                  "Path to the termux-notification command.
This is found in the termux-api package, and it requires the Termux
API addon app to be installed."
                  :type 'file
                  :group 'alert)

                (defun alert-termux-notify (info)
                  "Send INFO using termux-notification.
Handles :TITLE and :MESSAGE keywords from the
INFO plist."
                  (if alert-termux-command
                      (let ((args (nconc
                                   (when (plist-get info :title)
                                     (list "-t" (alert-encode-string (plist-get info :title))))
                                   (list "-c" (alert-encode-string (plist-get info :message))))))
                        (apply #'call-process alert-termux-command nil
                               (list (get-buffer-create " *termux-notification output*") t)
                               nil args))
                    (alert-message-notify info)))

                (alert-define-style 'termux :title "Notify using termux"
                                    :notifier #'alert-termux-notify))

Replace the GUI popup menu with something more efficient

(use-package ace-popup-menu
  ;; Unfortunately, avy-menu (used by this package) is not compatible with minions.  I just
  ;; disable it for now.
  :disabled t
  (ace-popup-menu-mode 1))

I’m an achiever!

(use-package achievements
  (achievements-mode 1)
  (:map gpolonkai/pers-map
   ("C-a" . achievements-list-achievements)))


Because even secretaries need a secretary today.

(use-package secretaria
  ;; use this for getting a reminder every 30 minutes of those tasks
  ;; scheduled for today and which have no time of day defined.
  (after-init . secretaria-unknown-time-always-remind-me))

The Silver Searcher

(use-package ag
  :after projectile
  (:map projectile-mode-map
   ("C-c p C-a" . ag-project)))

A fancier narrow-mode

(use-package fancy-narrow

Undo tree

(use-package undo-tree)

All the icons!

Should the fonts be missing, run (all-the-icons-install-fonts). It’s not run automatically, as it requires connecting to a website and download a pretty large font file.

(use-package all-the-icons)

NeoTree, if Dired is not an option

(defun gpolonkai/neo-set-theme ()
  (customize-set-variable 'neo-theme (if (display-graphic-p) 'icons 'arrow)))

(use-package neotree
  (([f5] . neotree-toggle))
  (neo-enter . gpolonkai/neo-set-theme))


This will be replaced with something self-hosted, eventually.

(use-package wakatime-mode
  (setq-default wakatime-cli-path (executable-find "wakatime"))
  (global-wakatime-mode t))

Jump to character, word, line

(use-package ace-jump-mode
  (:map gpolonkai/pers-map
   ("SPC" . ace-jump-mode)))

Command frequency meter

(use-package keyfreq
  (setq keyfreq-file (expand-file-name
  (setq keyfreq-file-lock (expand-file-name
  (keyfreq-mode 1)
  (keyfreq-autosave-mode 1)
  (:map gpolonkai/pers-map
   ("C-f" . keyfreq-show)))


EditorConfig is a nice tool to unify, well, configuration of different editors.

(use-package editorconfig
  (editorconfig-mode t))

occur-like folding in the current buffer

(defun gpolonkai/toggle-loccur ()
  "Toggle `loccur-mode'.

If `loccur-mode' is not active, starts it (which, in turn, will ask for the
pattern to look for).  If it is active, it will disable it."
  (if loccur-mode
      (loccur-mode nil)
    (call-interactively 'loccur)))

(use-package loccur
  (:map gpolonkai/pers-map
   ("C-o" . gpolonkai/toggle-loccur)))

More fine-tuned autosaving

First, a function that turns off auto-saving for remote files.

(defun gpolonkai/dont-autosave-remote ()
  (when (and buffer-file-name (not (file-remote-p buffer-file-name)))

Then configure real-auto-save-mode

(use-package real-auto-save
  :demand t
  (text-mode . gpolonkai/dont-autosave-remote)
  (prog-mode . gpolonkai/dont-autosave-remote))

Help merging pacsave and pacnew files

(use-package pacfiles-mode
  :commands pacfiles)

Mailing with mu4e

(use-package mu4e
  :ensure nil
  (setq mu4e-contexts
        `( ,(make-mu4e-context
             :name "Private"
             :enter-func (lambda () (mu4e-message "Entering Private Context"))
             :leave-func (lambda () (mu4e-message "Leaving Private Context"))
             :match-func (lambda (msg)
                           (when msg
                             (mu4e-message-contact-field-matches msg
                               :to "")))
             :vars '((user-mail-address . "")
                     (mu4e-maildir . "~/.cache/mail/Polonkai")
                     (mu4e-sent-folder . "/[Gmail].Sendur p&APM-stur")
                     (mu4e-drafts-folder . "/[Gmail].Dr&APY-g")
                     (mu4e-trash-folder . "/[Gmail].Rusl")
                     (mu4e-refile-folder . "/[Gmail].Dr&APY-g")))
             :name "GT2"
             :enter-func (lambda () (mu4e-message "Entering GT2 Context"))
             :leave-func (lambda () (mu4e-message "Leaving GT2 Context"))
             :match-func (lambda (msg)
                           (when msg
                              (mu4e-message-contact-field-matches msg
                                :to "")
                              (mu4e-message-contact-field-matches msg
                                                                  :to ""))))
             :vars '((user-mail-address . "")
                     (mu4e-maildir . "~/.cache/mail/GT2")
                     (mu4e-sent-folder . "/[Gmail].Sent Mail")
                     (mu4e-drafts-folder . "/[Gmail].Drafts")
                     (mu4e-trash-folder . "/[Gmail].Trash")
                     (mu4e-refile-folder . "/[Gmail].Drafts"))))
        mu4e-context-policy 'pick-first)
  (:map gpolonkai/pers-map
   ("m m" . mu4e)
   ("m i" . mu4e~headers-jump-to-maildir)
   ("m c" . mu4e-compose-new)
   ("m s" . mu4e-headers-search)))

ViM’s ci functionality

(use-package ciel
  (:map global-map
   ("C-c i" . ciel-ci)
   ("C-c o" . ciel-co)))

Access files in Docker containers using TRAMP

(use-package docker-tramp)

Display a line at fill-column

(use-package fill-column-indicator
  (prog-mode . fci-mode))

Make programming a bit easier

Electric case

Insert snake_case and camelCase without using the Shift key. It is automatically enabled in C mode.

(use-package electric-case
  (c-mode . electric-case-c-init))

Electric operator

Automatically add spaces around operators.

(use-package electric-operator
  ;; Apply electric-operator-mode to vala-mode, too
  (apply #'electric-operator-add-rules-for-mode 'vala-mode
         (electric-operator-get-rules-for-mode 'prog-mode))
  (c-mode-common . electric-operator-mode))


(use-package yasnippet
  (yas-global-mode 1)
  (post-command . sachachua/change-cursor-color-when-can-expand))

Extra snippets for Vala

(use-package vala-snippets

Miscellanous extra snippets

(use-package yasnippet-snippets)

Colourful delimiters

(use-package rainbow-delimiters
  (prog-mode . rainbow-delimiters-mode))

REST Client

(use-package restclient)

Highlight current symbol

A big help during refactoring.

(use-package auto-highlight-symbol
  (global-auto-highlight-symbol-mode t))

Make ReallyLongCamelCaseWords more readable

(use-package glasses
  :delight " 👓"
  (prog-mode . glasses-mode))

GObject boilerplate generator

(use-package gobgen)

Insert specific licenses in the current buffer

(use-package xlicense
  (:map gpolonkai/pers-map
   ("L" . insert-license)))

Highlight TODO, FIXME, and XXX

(use-package hl-todo)

Python related setup and use-package calls

Because, well, that’s my job now. Of course it gets a dedicated section.

Set up pretty symbols for Python

Because they are fancy.

  • not: ¬
  • in: ∈
  • def: ƒ

Maybe add ∉ for not in later, if possible.

(add-hook 'python-mode-hook
          (lambda ()
            (add-to-list 'prettify-symbols-alist
                         '("not" . 172))
            (add-to-list 'prettify-symbols-alist
                         '("in" . 8712))
            (add-to-list 'prettify-symbols-alist
                         '("def" . 402))))

Automatically load the virtualenv if there is one

(use-package auto-virtualenv
  (python-mode . auto-virtualenv-set-virtualenv)
  (projectile-after-switch-project . auto-virtualenv-set-virtualenv))

Anaconda mode

(use-package anaconda-mode
  (python-mode . anaconda-mode)
  (python-mode . anaconda-eldoc-mode))


Because it’s great.

(use-package pipenv
  (python-mode . pipenv-mode)
  (setq pipenv-projectile-after-switch-function #'pipenv-projectile-after-switch-extended))

Automatically insert Sphinx-style docstrings

(use-package sphinx-doc
  (python-mode . sphinx-doc-mode))

C mode

Because that’s still my favourite language.

Set up my own C style

(defconst my-c-style
  '((c-tab-always-indent        . t)
    (c-comment-only-line-offset . 4)
    (c-hanging-braces-alist     . ((substatement-open after)
    (c-hanging-colons-alist     . ((member-init-intro before)
                                   (case-label after)
                                   (label after)
                                   (access-label after)))
    (c-cleanup-list             . (scope-operator
    (c-offsets-alist             . ((arglist-close . +)
                                    (arglist-intro . +)
                                    (substatement-open . 0)
                                    (case-label . 4)
                                    (block-open . 0)
                                    (knr-argdecl-intro . -)
                                    (comment-intro . 0)
                                    (member-init-intro . ++)))
    (c-echo-syntactic-information-p . t))
  "My C Programming Style.")
(c-add-style "PERSONAL" my-c-style)

Some common initialisation for C mode

(add-hook 'c-mode-common-hook
          (lambda ()
            (local-set-key (kbd "C-c o") 'ff-find-other-file)
            (c-set-style "PERSONAL")
            (setq tab-width 4
                  indent-tabs-mode nil)
            (c-toggle-auto-newline 1)))
(add-hook 'c-initialization-hook
          (lambda ()
            (define-key c-mode-base-map (kbd "C-m") 'c-context-line-break)))

Set indentation levels to the same as the tab width

(defvaralias 'c-basic-offset 'tab-width)
(defvaralias 'cperl-indent-level 'tab-width)

Web development

Web mode

(use-package web-mode
  :mode "\\.html?\\'"
  (setq web-mode-enable-auto-indentation nil)
  (setq web-mode-enable-engine-detection t))

Emmet mode

(use-package emmet-mode
  (setq emmet-self-closing-tag-style "")
  (web-mode . emmet-mode)
  (css-mode . emmet-mode))

Query HTML tags by CSS selectors

(use-package enlive)


(use-package flycheck

FlyCheck for pkg-config files

(use-package flycheck-pkg-config)

Org mode

This is a big one; I use a lot of customisation here.

(use-package org
  (require 'xdg-paths)
  (defface org-checkbox-todo-text
    '((t (:inherit org-todo)))
    "Face for the text part of an unchecked org-mode checkbox.")
  (defface org-checkbox-done-text
    '((t (:inherit org-done)))
    "Face for the text part of a checked org-mode checkbox.")
   `(("^[ \t]*\\(?:[-+*]\\|[0-9]+[).]\\)[ \t]+\\(\\(?:\\[@\\(?:start:\\)?[0-9]+\\][ \t]*\\)?\\[\\(?: \\|\\([0-9]+\\)/\\2\\)\\][^\n]*\n\\)" 1 'org-checkbox-todo-text prepend))
   `(("^[ \t]*\\(?:[-+*]\\|[0-9]+[).]\\)[ \t]+\\(\\(?:\\[@\\(?:start:\\)?[0-9]+\\][ \t]*\\)?\\[\\(?:X\\|\\([0-9]+\\)/\\2\\)\\][^\n]*\n\\)" 12 'org-checkbox-done-text prepend))
  (setq org-directory (expand-file-name "NextCloud/orgmode" user-documents-directory))
  (setq-default org-crypt-key "B0740C4C"
                org-default-notes-file (expand-file-name "" org-directory)
                org-agenda-files `(,org-directory)
                org-ellipsis "…#"
                org-startup-folded 'content
                org-log-done 'time
                org-src-preserve-indentation t
                org-log-into-drawer t
                org-tags-column 0
                org-startup-indented t
                org-special-ctrl-a/e t
                org-return-follows-link t
                org-src-fontify-natively t
                org-time-stamp-formats '("<%Y-%m-%d>" . "<%Y-%m-%d %H:%M>")
                org-todo-keywords '((sequence "TODO(t)"
                org-todo-keyword-faces '(
                                         ("SOMEDAY" . (:foreground "goldenrod"))
                                         ("CANCELED" . (:foreground "#228b22" :strike-through t)))
                org-goto-interface 'outline-path-completion
                org-goto-max-level 10
                org-html-checkbox-type 'unicode
                '((unicode (on . "<span class=\"task-done\">☑</span>")
                           (off . "<span class=\"task-todo\">☐</span>")
                           (trans . "<span class=\"task-in-progress\">▣</span>")))
                org-src-window-setup 'current-window
                org-pretty-entities t
                org-pretty-entities-include-sub-superscripts t
                org-use-speed-commands t
                org-speed-commands-user '(("m" . org-mark-subtree))
                org-hide-leading-stars t
                org-enforce-todo-dependencies t
                org-catch-invisible-edits 'show
                org-log-reschedule 'time
                org-log-redeadline 'note
                org-refile-targets '((org-agenda-files :maxlevel . 3))
                org-refile-use-outline-path 'file
                org-outline-path-complete-in-steps nil
                org-refile-allow-creating-parent-nodes 'confirm
                org-agenda-custom-commands '(("c" "Simple agenda view" ((tags "PRIORITY=\"A\""
                                                                              ((org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done))
                                                                               (org-agenda-overriding-header "High priority unfinished tasks")))
                                                                        (agenda "")
                                                                        (alltodo ""
                                                                                   '(or (air-org-skip-subtree-if-habit)
                                                                                        (air-org-skip-subtree-if-priority ?A)
                                                                                        (gpolonkai/org-skip-subtree-if-state "SOMEDAY")
                                                                                        (org-agenda-skip-if nil '(scheduled deadline))))
                                                                                  (org-agenda-overriding-header "ALL normal priority tasks"))))
                                              ((org-agenda-compact-blocks t)))))
  ;; Load the markdown exporter
  (require 'ox-md)

  ;; Make sure we have 'org-capture-templates` defined
  (unless (boundp 'org-capture-templates)
    (setq org-capture-templates nil))

  ;; Set up capture templates for blog posts and GT2 related notes
  (add-to-list 'org-capture-templates
               '("p" "Blog post" entry
                 (file+olp+datetree (lambda () (concat org-directory "")))
                 "* %^{Title}  :blog:\n   :PROPERTIES:\n   :on: %T\n   :END:\n   %i%?"))
  (add-to-list 'org-capture-templates
               '("g" "GT2 note" entry
                 (file+headline (lambda () (concat org-directory "")) "Captures")
                 "** %^{Title}\n   :PROPERTIES:\n   :on: %T\n   :END:\n   %i%?"))
  (add-to-list 'org-capture-templates
               '("c" "Item to current Clocked Task" item
                 :empty-lines 1))
  (add-to-list 'org-capture-templates
               '("K" "Kill-ring to Current Clocked Task" plain
                 :immediate-finish t
                 :empty-lines 1))
  (add-to-list 'org-capture-templates
               '("R" "Region to Current Clocked Task" plain
                 :immediate-finish t
                 :empty-lines 1))
  (ediff-select . f-ediff-org-unfold-tree-element)
  (ediff-unselect . f-ediff-org-fold-tree)
  (:map gpolonkai/pers-map
   ("a" . gpolonkai/org-agenda-list)
   ("C" . org-capture)
   ("l" . org-store-link)
   :map org-mode-map
   ("SPC" . org-space-key)
   ("C-c l" . org-toggle-link-display)
   ("C-a" . gpolonkai/move-to-beginning-of-line)
   ("C-e" . gpolonkai/move-to-end-of-line)
   ("C-c h" . outline-previous-heading)
   ("C-c ;" . org-toggle-timestamp-type)))

Show a random ToDo every hour

(use-package org-random-todo
  ;; Don’t bug me too often…
  (setq org-random-todo-how-often 3600)
  (:map gpolonkai/pers-map
   ("r" . org-random-todo)))

Citations and cross-references for Org

(use-package org-ref
  (setq org-ref-bibliography-notes (concat user-documents-directory
        org-ref-default-bibliography '((concat user-documents-directory
        org-ref-pdf-directory (concat user-documents-directory

And set up a function to open PDF files with the system pdf viewer, using xdg-open.

An alternative could be

(setq bibtex-completion-pdf-open-function 'org-open-file))
(setq bibtex-completion-pdf-open-function
  (lambda (fpath)
    (start-process "xdg-open" "*open*" "open" fpath)))

Load CalDAV entries from NextCloud

(use-package org-caldav
  :after org
   org-caldav-url ""
   org-caldav-calendar-id "org"
   org-caldav-inbox (expand-file-name "" org-directory)
   org-caldav-files nil))

Improved list management

(use-package org-autolist
  (org-mode . org-autolist-mode))

Write messages with Org-mode

(use-package org-msg
  (customize-set-variable 'org-msg-options "html-postamble:nil H:5 num:nil ^:{} toc:nil")
  (customize-set-variable 'org-msg-startup "hidestars indent inlineimages")
  (customize-set-variable 'org-msg-greeting-fmt "\nHello,\n\n")
  (customize-set-variable 'org-msg-greeting-fmt-mailto nil)
  (customize-set-variable 'org-msg-signature "


-- *Gergely Polonkai* \\\\

Git & Co.

Git status on the fringe

In graphical modes we use git-gutter-fringe, and git-gutter otherwise.

;; Git gutter
;; If we are in text-only mode, there is no fringe.
(let ((gitgutter-package
       (if (display-graphic-p)
  (eval `(use-package ,gitgutter-package
    (global-git-gutter-mode t)
    (:map gpolonkai/pers-map
     ("gg" . git-gutter:update-all-windows)
     ("gn" . git-gutter:next-hunk)
     ("gp" . git-gutter:previous-hunk)))))

Git messenger

AKA blame current line.

(use-package git-messenger
  (:map gpolonkai/pers-map
   ("gm" . git-messenger:popup-message)))

Git time machine

See previous versions of the current file.

(use-package git-timemachine
  (([f6] . git-timemachine-toggle)))

Company & Co.

(use-package company
  :delight " 🏢"
  (setq company-idle-delay nil
        company-frontends '(company-pseudo-tooltip-frontend
        company-dabbrev-downcase nil)
  (put 'company-clang-arguments 'safe-local-variable #'nil-or-list-of-strings-p)

Company completion based on local C headers

(use-package company-c-headers)

Company mode in the shell

(use-package company-shell)

REST Client completion via Company

(use-package company-restclient)

Insert Emoji with Company

(use-package company-emoji
  (--set-emoji-font nil)
  (add-to-list 'company-backends 'company-emoji))

Anaconda backend for Company

(use-package company-anaconda
  (add-to-list 'company-backends 'company-anaconda))

Web mode (web-mode and emmet-mode, too) backend for Company

(use-package company-web
  (require 'company-web-html))

Helm & Co.


(use-package helm
  (require 'helm-config)
  (setq helm-M-x-fuzzy-match t
        helm-buffers-fuzzy-matching t
        helm-recentf-fuzzy-match t)
  (helm-mode t)
  (("M-x" . helm-M-x)
   :map ctl-x-map
   ("C-f" . helm-find-files)
   ("b" . helm-mini)
   :map helm-map
   ("/" . gpolonkai/helm-ff-slash-dir-complete)))

Helm-style swooping

(use-package helm-swoop
  (("M-i" . helm-swoop)))

GNU Globals with Helm

(defun gpolonkai/enable-helm-gtags-mode ()
  (helm-gtags-mode t))

(use-package helm-gtags
  (setq-default helm-gtags-auto-update t
                helm-gtags-ignore-case t
                helm-gtags-path-style 'relative)
  (c-mode . gpolonkai/enable-helm-gtags-mode)
  (:map helm-gtags-mode-map
   ("M-t" . helm-gtags-find-tag)
   ("M-r" . helm-gtags-find-rtag)
   ("M-s" . helm-gtags-find-symbol)
   ("M-g M-p" . helm-gtags-parse-file)
   ("C-c <" . helm-gtags-previous-history)
   ("C-c >" . helm-gtags-next-history)
   ("M-," . helm-gtags-pop-stack)))

Ag with Helm

(use-package helm-ag
  (:map gpolonkai/pers-map
   ("s" . helm-do-ag)))

Company with Helm

(use-package helm-company
  (:map company-mode-map
   ("C-c j" . helm-company)
   :map company-active-map
   ("C-c j" . helm-company)))

Projectile with Helm

(use-package helm-projectile
  (setq projectile-completion-system 'helm)

FlyCheck with Helm

(use-package helm-flycheck)

FlySpell with Helm

(use-package helm-flyspell
  (:map flyspell-mode-map
   ("C-M-i" . helm-flyspell-correct)))

Search GitHub starred repos with Helm

(use-package helm-github-stars
  (setq-default helm-github-stars-username "gergelypolonkai"))

Smex with Helm

(use-package helm-smex
  (("M-S-x" . helm-smex)))

Describe bindings with Helm

(use-package helm-descbinds)

Describe modes with Helm

(use-package helm-describe-modes)

REST Client with Helm

(use-package restclient-helm)

C Yasnippets with Helm

(use-package helm-c-yasnippet
  :demand t
  (setq helm-yas-space-match-any-greedy t)
  (("C-c y" . helm-yas-complete)))

Git hunks with Helm

(use-package helm-hunks)

PyDoc with Helm

(use-package helm-pydoc)

BibTex with Helm

(use-package helm-bibtex
  (setq bibtex-completion-bibliography (concat user-documents-directory
        bibtex-completion-library-path (concat user-documents-directory
        bibtex-completion-notes-path (concat user-documents-directory
        bibtex-completion-pdf-open-function 'org-open-file))

Mode specific use-package calls


(use-package js2-mode
  :pin melpa-stable
  :mode "\\.js\\'")


(use-package typescript-mode
  :mode "\\.ts\\'")


(use-package coffee-mode
  :mode "\\.coffee\\'")


(use-package json-mode
  :mode "\\.json\\'")


(use-package yaml-mode
  :mode (("\\.yml\\'" . yaml-mode)
         ("\\.yaml\\'" . yaml-mode))
  (add-to-list 'auto-mode-alist '("\\.yml\\'" . yaml-mode)))


(use-package markdown-mode
  :mode (("\\.md\\'" . markdown-mode)
         ("\\.markdown\\'" . markdown-mode)))


(use-package less-css-mode
  :mode "\\.less\\'")


(use-package sass-mode
  :mode "\\.sass\\'")


(use-package vala-mode
  :mode "\\.vala\\'")


(use-package dockerfile-mode)


(use-package gitconfig-mode)


(use-package gitignore-mode)


(use-package po-mode
  :mode "\\.po\\'")


(use-package csharp-mode
  :mode "\\.cs\\'")

Gherkin (BDD) feature files

(use-package feature-mode
  :mode "\\.feature\\'")


Before using this, make sure the latest PlantUML JAR file is downloaded into the downloads directory. It is available from here.

(use-package plantuml-mode
  (setq plantuml-jar-path
         ;; Make sure we have a download location even if XDG is not working
          ((xdg-user-dir "DOWNLOAD")
           (concat (xdg-user-dir "DOWNLOAD") "/plantuml.jar"))
  (defvaralias 'org-plantuml-jar-path 'plantuml-jar-path)
   '((plantuml . t))))

For editing CSV files

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

The Go programming language

(use-package go-mode
  :mode "\\.go\\'")

Meson build system

(use-package meson-mode
  :mode "\\.meson\\'")


Gnu Go

(use-package gnugo)

Last, but not least, key bindings!

 :map global-map
 ("M-(" . æ-enclose-region)
 ("<C-return>" . open-line-below)
 ("<C-S-return>" . open-line-above)
 ("M-t" . nil) ;; Remove the old keybinding
 ("M-t c" . transpose-chars)
 ("M-t w" . transpose-words)
 ("M-t l" . transpose-lines)
 ("M-t e" . transpose-sexps)
 ("M-t s" . transpose-sentences)
 ("M-t p" . transpose-paragraphs)
 ("M-t W" . transpose-windows)
 ("C-a" . gpolonkai/move-to-beginning-of-line)
 ("C-e" . gpolonkai/move-to-end-of-line)
 ("M-q" . sachachua/fill-or-unfill-paragraph)
 ("C-c r" . round-number-at-point-to-decimals)
 ("C-s" . isearch-forward-regexp)
 ("C-r" . isearch-backward-regexp)
 ("C-M-s" . isearch-forward)
 ("C-M-r" . isearch-backward)
 ("C-~" . toggle-char-case)
 :map ctl-x-map
 ("C-y" . gpolonkai/duplicate-line)
 ("_" . maximize-window)
 ("C-r" . rename-current-buffer-file)
 ("C-d" . delete-current-buffer-file)
 ("|" . toggle-window-split)
 ("k" . kill-this-buffer)
 ("M-k" . gpolonkai/undo-buffer-kill)
 ("C-b" . bury-buffer)
 ("/" . repeat)
 :map isearch-mode-map
 ("<C-return>" . isearch-exit-other-end)
 ("<S-return>" . isearch-exit-mark-match)
 :map gpolonkai/pers-map
 ("h" . hidden-mode-line-mode)
 ("C-i e" . "")
 ("C-i w" . "")
 ("C-p" . package-list-packages)
 ("o i" . gpolonkai/visit-init-file)
 ("o o" . gpolonkai/visit-org-index)
 ("u" . browse-url-at-point)
 ("M-C" . clean-buffer-list)
 ("C-c" . calc)
 ("c i" . org-clock-in)
 ("c I" . org-clock-in-last)
 ("c o" . org-clock-out)
 ("c g" . org-clock-goto))

TODO These fail to work using bind-keys, but why?

(define-key 'help-command (kbd "C-l") 'find-library)
(define-key 'help-command (kbd "C-f") 'find-function)
(define-key 'help-command (kbd "C-k") 'find-function-on-key)
(define-key 'help-command (kbd "C-v") 'find-variable)

And finally, server mode

Sometimes i start an emacsclient process, like for editing a commit message or something similar. As my startup time is pretty long, waiting for everything to complete is undesirable.

(require 'server)
(unless (server-running-p)