UP | HOME

My GNU Emacs configuration
A personal emacs configuration

Table of Contents

Introduction

This is my version of an configuration file for GNU Emacs. I now use straight to install packages and use-package to configure them. Previously I used package.el, the built-in package-handling system with use-package but it became a bit awkward and slow when I wanted to upgrade installed packages. This configuration should start without problems but will take a very long time the first time, since straight needs to clone and build all packages. And Git is needed before this to work.

Load emacs.org in emacs and run org-babel-tangle to create startup files the first time. Restart emacs.

Inspiration

All config in one file from System Crafters Emacs from Scratch.

Early init

Some things go to the early-init.el file so they are executed before Emacs initializing process. This is to setup things before the GUI loads and other features.

early-init.el

The file to load before init.el. This will be created after org-babel-tangle.

;;; early-init.el --- Startup file before init.el to disable settings.

;;; Commentary:

;; From https://github.com/raxod502/straight.el#getting-started
;; Disable stuff before init.el gets loaded.
;; See https://www.gnu.org/software/emacs/manual/html_node/emacs/Early-Init-File.html

;;; Code:

(message "*** Reading early-init.el @ %s" (format-time-string "%Y-%m-%d %H:%M:%S" (current-time)))
(setq package-enable-at-startup nil)

;; From Doom early-init.
(set-language-environment "UTF-8")

;; From Doom, shaves off a second from startup.
(setq-default inhibit-redisplay t
              inhibit-message t)
(add-hook 'window-setup-hook
          (lambda ()
            (setq-default inhibit-redisplay nil
                          inhibit-message nil)
            (redisplay)))

Provide

Final statements

(provide 'early-init)
;;; early-init.el ends here

init.el

;;; -*- mode: emacs-lisp; lexical-binding: t -*-
;;; init.el --- Configuration of Emacs

;;; Commentary:

;; From https://gitlab.com/buildfunthings/emacs-config/blob/master/init.el

;;; Code:
(message "*** Reading from %s ***" (buffer-name))

;; Debug startup
(setq debug-on-error t)
(setq debug-on-quit t)

;; Garbage collection
;; Increase the garbage collection threshold to make startup faster
(setq gc-cons-threshold (* 50 1024 1024))
(setq garbage-collection-messages nil)

;; From emacs-from-scratch https://github.com/daviwil/emacs-from-scratch/blob/master/init.el
(defun efs/display-startup-time ()
  "Prints the startup time for Emacs."
  (message "*** Emacs loaded in %s with %d garbage collections."
           (format "%.2f seconds"
                   (float-time
                    (time-subtract after-init-time before-init-time)))
           gcs-done))

(add-hook 'emacs-startup-hook #'efs/display-startup-time)

(defvar start-time (float-time (current-time)))

(defun my/format-time (time)
  "Displays formatted TIME."
  (format-time-string "%Y-%m-%d %H:%M:%S" time))

(defun my/startup-timer ()
  "Measures time differences."
  (format-time-string "%M:%S.%3N" (- (float-time (current-time)) start-time)))

(message "*** Started emacs @ %s" (my/format-time start-time))
(message "*** Reading configuration from init.el...")

Server

Start Emacs as server.

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

Straight

Bootstrap straight.

;; install straight package manager
(defvar bootstrap-version)
(let ((bootstrap-file
       (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
      (bootstrap-version 6))
  (unless (file-exists-p bootstrap-file)
    (with-current-buffer
        (url-retrieve-synchronously "https://raw.githubusercontent.com/radian-software/straight.el/develop/install.el"
         'silent 'inhibit-cookies)
      (goto-char (point-max))
      (eval-print-last-sexp)))
  (load bootstrap-file nil 'nomessage))

;; Also install use-package and Org.
(straight-use-package 'org)
(straight-use-package 'use-package)
(customize-set-variable 'straight-use-package-by-default t)
(customize-set-variable 'straight-host-usernames
                        '((github . "sdaaish")
                          (gitlab . "sdaaish")))

Diminish

(use-package diminish)

Garbage collection

Try new package for GC.

(use-package gcmh
  :diminish gcmh-mode
  :custom
  (gcmh-idle-delay 3)
  :config
  (gcmh-mode 1))

Org mode

Install org mode and contrib.

;; Install latest version of org and org-plus-contrib
(use-package org
  :bind (:map org-mode-map
              ("C-c C-<tab>" . org-force-cycle-archived)
              ("C-c C-h" . org-tags-view)
              ("C-*" . org-jump-to-heading-beginning))
  :hook (org-mode . (lambda ()
                           (customize-set-variable 'org-use-speed-commands t))))

(use-package org-contrib)

Shortcut key

Add a keybinding for org-speed-commands. From https://github.com/revrari/emacs_elements_chapter_2/blob/main/org-speed-commands.org

(defun org-jump-to-heading-beginning ()
  "Jump to the beginning of the line of the previous Org heading."
  (interactive)
  (org-back-to-heading)
  (beginning-of-line))

Variables

Setting variables and constants for my directories and files.

My variables

(defvar my/init-dir (file-name-directory (or load-file-name (buffer-file-name))))
(defvar my/emacs-orgfile (expand-file-name "emacs.org" my/init-dir))
(defvar my/emacs-elfile (expand-file-name "init.el" my/init-dir))

No littering

Try to keep user-emacs-directory clean with the package no-littering.

(use-package no-littering)

OneDrive

(cond ((eq system-type 'gnu/linux)(defconst my/onedrive-dir (expand-file-name "OneDrive/" "~")))
      ((eq system-type 'windows-nt)(defconst my/onedrive-dir (expand-file-name  "OneDrive/" (getenv "UserProfile")))))

Emacs synced files

(defconst my/emacs-shared-dir (concat my/onedrive-dir "emacs/"))

Private emacs-file

File with personal stuff.

(defconst my/private-orgfile (expand-file-name "private.org" my/emacs-shared-dir))
(defconst my/private-elfile (expand-file-name "private.el" my/emacs-shared-dir))

Backup-directory

(defconst my/emacs-backup-dir
   (expand-file-name "backup/" no-littering-var-directory))

Repositories

(if (eq system-type 'gnu/linux)
    (defconst my/repo-dir (expand-file-name "repos/" "~")))
(if (eq system-type 'windows-nt)
    (defconst my/repo-dir (concat (getenv "UserProfile") "\\Repos\\")))

Org-mode variables

Set the variables for org-mode files. Use separate files to store agenda and refiling targets, to improve performance.

(defun my/read-lines (filePath)
  "Return a list of lines of a file at filePath."
  (if (file-exists-p filePath)
      (with-temp-buffer
        (insert-file-contents filePath)
        (split-string (buffer-string) "\n" t))))

(defun my/fullpath (filepath directory)
  "Concatenate directory to names in filepath and return as list."
  (let (value)
    (setq list (my/read-lines filepath))
    (dolist (shortfile list value)
      (setq fullpath (concat directory shortfile))
      (setq value (cons fullpath value)))))

;; Define constants
(defconst my/org-directory (expand-file-name "Org/" my/onedrive-dir))
(defconst my/notes-file (expand-file-name "notes.org" my/org-directory))
(defconst my/diary-file (expand-file-name "diary.org" my/org-directory))
(defconst my/org-agenda-files (expand-file-name ".agenda-files" my/org-directory))
(defvar my/mobile-target-file (expand-file-name  ".mobile-files" my/org-directory))
;; My org-files directory
(setq org-directory my/org-directory)
;; Org-agenda can read from a file
(setq org-agenda-files my/org-agenda-files)
;; Store notes here
(setq org-default-notes-file my/notes-file)
;; Choose targets to refile to.
(customize-set-variable 'org-refile-targets '((nil :maxlevel . 3)(org-agenda-files :maxlevel . 3)))
;; Files for mobile sync
(defvar my/mobile-files (my/fullpath my/mobile-target-file my/org-directory))

Initializing

Message-buffer

Increase message-buffer

(setq message-log-max (* 256 1024))

Bugfix for ELPA

Apparently som error with TLS 1.3 for Elpa and older versions of emacs.

(if (and (version< emacs-version "26.3") (>= libgnutls-version 30604))
    (setq gnutls-algorithm-priority "NORMAL:-VERS-TLS1.3"))

Certificates

Add some extra CA's for Emacs that are missing on Windows et al. Let's Encrypt as an example.

customCA.pem is a file with open CA-issuers and localCA.pem is a file that contain private or local issuers.

(require 'gnutls)
(add-to-list 'gnutls-trustfiles (expand-file-name "SSL/customCA.pem" user-emacs-directory))
(when (file-exists-p (expand-file-name "SSL/localCA.pem" user-emacs-directory))
  (add-to-list 'gnutls-trustfiles (expand-file-name "SSL/localCA.pem" user-emacs-directory)))

Hydra config

Hydras is keyboard mapping through menus.

Hydra

;; Hydra keymapping support
(use-package hydra)

Toggle stuff

Use "C-c v" to toggle values.

(require 'whitespace)
(defhydra hydra-toggle (:color pink :timeout 3)
  "
        _a_ abbrev-mode:       %`abbrev-mode
        _c_ flycheck-mode:     %`flycheck-mode
        _d_ debug-on-error:    %`debug-on-error
        _f_ auto-fill-mode:    %`auto-fill-function
        _t_ truncate-lines:    %`truncate-lines
        _v_ visual-lines:      %`visual-line-mode
        _w_ whitespace-mode:   %`whitespace-mode
        _l_ linenumber:        %`display-line-numbers-mode
        _r_ relative-lines:    %`display-line-numbers-type
        _R_ rainbow-delimiters %`rainbow-delimiters-mode
        _C_ rainbow-mode       %`rainbow-mode
  "
  ("a" abbrev-mode nil)
  ("c" flycheck-mode nil)
  ("C" rainbow-mode nil)
  ("d" toggle-debug-on-error nil)
  ("f" auto-fill-mode nil)
  ("l" my/line-number-t nil)
  ("r" my/line-number-relative nil)
  ("R" rainbow-delimiters-mode nil)
  ("t" toggle-truncate-lines nil)
  ("v" visual-line-mode nil)
  ("w" whitespace-mode nil)
  ("q" nil "cancel" :color blue))
(bind-key "C-c v" 'hydra-toggle/body)

Zoom text size

Use Ctrl+NumPad (+-) to zoom in or out text scale.

(global-set-key (kbd "C-<kp-add>") 'text-scale-increase)
(global-set-key (kbd "C-<kp-subtract>") 'text-scale-decrease)
(setq text-scale-mode-step 1.05)

Change font

Change fonts with C-<f2>.

(defhydra hydra-font (global-map "<f2>" :timeout 3)
  "Change fonts to next/previous"
  ("n" my/cycle-font-next "next font")
  ("p" my/cycle-font-previous "previous font")
  ("q" nil "cancel" :color blue))

Emacs init files.

Hydra for quick access to emacs files, "<f8> i".

(defhydra hydra-config-files (:color blue :columns 3)
  "Emacs config files"
  ("c" (find-file custom-file) "customize.el")
  ("e" (find-file my/emacs-orgfile) "emacs.org")
  ("i" (find-file my/emacs-elfile) "init.el")
  ("j" (find-file (expand-file-name "early-init.el" user-emacs-directory)) "early-init.el")
  ("k" my/server-shutdown "Save&kill")
  ("p" (find-file my/private-orgfile) "private.org")
  ("r" (load-file user-init-file) "Reload emacs")
  ("s" (find-file (expand-file-name "my-cheats.el" (expand-file-name "lisp/" "~/.config/"))) "Cheat sheet")
  ("q" nil "cancel"))
(bind-key "<f8> i" 'hydra-config-files/body)
(defun my/server-shutdown ()
  "Save buffers, Quit, and Shutdown (kill) server"
  (interactive)
  (save-some-buffers)
  (kill-emacs)
  )

Hydra for org

Switch between org-buffers, "<f8> o".

(defhydra hydra-org-stuff (:color blue :columns 3)
  "Org mode stuff"
  ("c" my/org-gcal-sync "Sync Google Calender")
  ("g" my/org-mobile-sync "Synchronize mobile")
  ("P" org-publish-project "org-publish-project")
  ("o" org-iswitchb "Switch org-buffer")
  ("r" org-revert-all-org-buffers "Refresh all org-buffers")
  ("s" org-save-all-org-buffers "Save Org buffers")
  ("v" org-tags-view)
  ("q" nil "cancel"))
(bind-key "<f8> o" 'hydra-org-stuff/body)
(defun my/org-gcal-sync()
  "Synchronizes Google calendar with Org"
  (interactive)
  (org-save-all-org-buffers)
  (org-gcal-sync))
(defun my/org-mobile-sync()
  "Synchronizes agenda files with mobile app."
  (interactive)
  (org-save-all-org-buffers)
  (org-mobile-pull)
  (org-mobile-push)
  (message "Synced mobile agendas."))

Launcher

Launch various programs, "C-c b"

(defhydra hydra-launcher (:color blue :columns 4)
  "Launch programs"
  ("b" hydra-better-shell/body "Better Shell")
  ("c" cheat-sh "Cheat sheet online")
  ("e" eshell "Eshell")
  ("E" eww "EWW")
  ("f" free-keys "Free keys")
  ("g" (browse-url "https://git-scm.com/docs/") "Git Book")
  ("h" man "man")
  ("H" (browse-url "http://localhost:1313/") "Local Hugo site")
  ("n" hackernews "Hackernews")
  ("p" (powershell) "Powershell")
  ("r" (browse-url "http://www.reddit.com/r/emacs/") "Reddit")
  ("t" (counsel-tramp) "Counsel-TRAMP")
  ("T" twit "Twitter mode")
  ("R" bjm/elfeed-load-db-and-open "RSS")
  ("s" shell "Shell")
  ("v" (shell-command (concat "code " buffer-file-name)) "VSCode")
  ("w" (browse-url "http://www.emacswiki.org/") "Emacs Wiki")
  ("W" wiki-summary "Wiki summary")
  ("q" nil "quit"))
(bind-key "C-c b" 'hydra-launcher/body)

Straight

Hydra for straight, from Hydra Wiki.

  (defhydra hydra-straight-helper (:hint nil)
    "
  _c_heck all       |_f_etch all     |_m_erge all      |_n_ormalize all   |p_u_sh all
  _C_heck package   |_F_etch package |_M_erge package  |_N_ormlize package|p_U_sh package
  ----------------^^+--------------^^+---------------^^+----------------^^+------------||_q_uit||
  _r_ebuild all     |_p_ull all      |_v_ersions freeze|_w_atcher start   |_g_et recipe
  _R_ebuild package |_P_ull package  |_V_ersions thaw  |_W_atcher quit    |prun_e_ build
  _h_ Describe package"
    ("c" straight-check-all)
    ("C" straight-check-package)
    ("r" straight-rebuild-all)
    ("R" straight-rebuild-package)
    ("f" straight-fetch-all)
    ("F" straight-fetch-package)
    ("p" straight-pull-all)
    ("P" straight-pull-package)
    ("m" straight-merge-all)
    ("M" straight-merge-package)
    ("n" straight-normalize-all)
    ("N" straight-normalize-package)
    ("u" straight-push-all)
    ("U" straight-push-package)
    ("v" straight-freeze-versions)
    ("V" straight-thaw-versions)
    ("w" straight-watcher-start)
    ("W" straight-watcher-quit)
    ("g" straight-get-recipe)
    ("e" straight-prune-build)
    ("h" describe-package)
    ("q" nil))
(global-set-key (kbd "C-h P") 'hydra-straight-helper/body)

Git and projects

Magit

Magit is a Git-tool, probably the best porcelain in the world!

(use-package magit
  :diminish magit-status
  :bind ("C-x g" . magit-status)
  :config
  (setq magit-completing-read-function 'ivy-completing-read)
  (if (eq system-type 'windows-nt)
      (setq-default with-editor-emacsclient-executable "emacsclientw.exe")
    (setq-default with-editor-emacsclient-executable "emacsclient"))
  :custom (magit-submodule-list-columns
           '(("Path" 35 magit-modulelist-column-path nil)
             ("Version" 25 magit-repolist-column-version
              ((:sort magit-repolist-version<)))
             ("Branch" 15 magit-repolist-column-branch nil)
             ("B<U" 3 magit-repolist-column-unpulled-from-upstream
              ((:right-align t)
               (:sort <)))
             ("B>U" 3 magit-repolist-column-unpushed-to-upstream
              ((:right-align t)
               (:sort <)))
             ("B<P" 3 magit-repolist-column-unpulled-from-pushremote
              ((:right-align t)
               (:sort <)))
             ("B>P" 3 magit-repolist-column-unpushed-to-pushremote
              ((:right-align t)
               (:sort <)))
             ("B" 3 magit-repolist-column-branches
              ((:right-align t)
               (:sort <)))
             ("S" 3 magit-repolist-column-stashes
              ((:right-align t)
               (:sort <))))))

Magit Forge

Manage github things from emacs.

(use-package forge
  :after gh)

Magit-gitflow

Enable support for git-flow. Why? See https://jeffkreeftmeijer.com/git-flow/.

(use-package magit-gitflow
  :after magit
  :hook
  (magit-mode . turn-on-magit-gitflow)
  :config
  (setq magit-gitflow-release-finish-arguments '("--fetch" "--push")))

magit-find-file

Package to support git ls-files.

(use-package magit-find-file
  :after magit
  :bind ("C-c m" . magit-find-file-completing-read))

Gist

Create and download gists from emacs.

(use-package gh
  :commands gist)
(use-package gist
  :config (setq gist-view-gist t)
  :bind (("C-x j" . gist-list)))

Git-link

Copy git links to kill-ring.

(use-package git-link
  :config
  (defhydra hydra-git-link (:color blue)
    "Copy git-link"
    ("h" git-link-homepage "Copy homepage")
    ("l" git-link "Copy link")
    ("c" git-link-commit "Copy commit"))
  :bind ("C-c L" . hydra-git-link/body))

Yasnippets

Yasnippet

Load yasnippet and some templates.

(use-package yasnippet
  :init
  (yas-global-mode 1)
  :bind (("C-c y" . hydra-yasnippet/body)
         :map yas-minor-mode-map
         ("C-c i" . yas-expand))
  :commands (yasnippet)
  :config (add-to-list 'yas-snippet-dirs (expand-file-name "snippets/" "~/.config/")))

Extra snippets

Load more snippets

(use-package yasnippet-snippets
  :after yasnippet)

ivy-yasnippet

(use-package ivy-yasnippet
  :bind ("C-x y" . ivy-yasnippet))

Hydra for yasnippet

From https://github.com/abo-abo/hydra/wiki/YASnippet

(defhydra hydra-yasnippet (:pre (yas-minor-mode t)
                                :color blue :hint nil)
  "
                    ^YASnippets^
      -----------------------------------
      Actions:    Load/Visit:   Modes:

      _i_nsert     _d_irectory    _c_ompany-yas
      _t_ryout     _f_ile         _g_lobal: %`yas-global-mode
      _n_ew        _l_ist         _m_inor: %`yas-minor-mode
      _e_xtra      _a_ll
"
  ("c" company-yasnippet)
  ("d" yas-load-directory)
  ("e" yas-activate-extra-mode)
  ("i" yas-insert-snippet)
  ("f" yas-visit-snippet-file :color blue)
  ("n" yas-new-snippet)
  ("t" yas-tryout-snippet)
  ("l" yas-describe-tables)
  ("g" yas-global-mode)
  ("m" yas-minor-mode)
  ("a" yas-reload-all))

Projectile

Find or switch to projects easy, and use counsel-projectile.

(defhydra hydra-projectile-other-window (:color teal)
  "projectile-other-window"
  ("f"  projectile-find-file-other-window        "file")
  ("g"  projectile-find-file-dwim-other-window   "file dwim")
  ("d"  projectile-find-dir-other-window         "dir")
  ("b"  projectile-switch-to-buffer-other-window "buffer")
  ("q"  nil                                      "cancel" :color blue))

(defhydra hydra-projectile (:color teal :hint nil)
  "
                   PROJECTILE: %(projectile-project-root)

                   Find File            Search/Tags          Buffers                Cache
              ------------------------------------------------------------------------------------------
                _F_: file            _a_: ag                _i_: Ibuffer           _c_: cache clear
               _ff_: file dwim       _g_: update gtags      _b_: switch to buffer  _x_: remove known project
               _fd_: file curr dir   _m_: multi-occur       _k_: Kill all buffers  _X_: cleanup non-existing
                _r_: recent file                                               ^^^^_z_: cache current
                _d_: dir

              "
  ("a"   projectile-ag)
  ("b"   projectile-switch-to-buffer)
  ("c"   projectile-invalidate-cache)
  ("d"   projectile-find-dir)
  ("s-f" projectile-find-file)
  ("F"   projectile-find-file)
  ("ff"  projectile-find-file-dwim)
  ("fd"  projectile-find-file-in-directory)
  ("g"   ggtags-update-tags)
  ("i"   projectile-ibuffer)
  ("k"   projectile-kill-buffers)
  ("m"   projectile-multi-occur)
  ("p"   projectile-switch-project "switch project")
  ("r"   projectile-recentf)
  ("x"   projectile-remove-known-project)
  ("X"   projectile-cleanup-known-projects)
  ("z"   projectile-cache-current-file)
  ("'"   hydra-projectile-other-window/body "open other window")
  ("q"   nil "cancel" :color blue))

(use-package projectile
  :diminish projectile-mode
  :init (when (file-directory-p "~/repos")
          (setq projectile-project-search-path '("~/repos")))
  :config
  (projectile-mode t)
  (setq projectile-completion-system 'ivy)
  (setq projectile-switch-project-action 'projectile-dired)
  :bind (("C-c p" . hydra-projectile/body)
         (:map projectile-mode-map
               ("C-c P" . projectile-command-map))))

(use-package counsel-projectile
  :init (counsel-projectile-mode 1))

Verify code

Flycheck

Use flycheck to check code.

(use-package flycheck
  :custom ((flycheck-checker-error-threshold 3000)
           (flycheck-display-errors-delay 1.4))
  :hook (((emacs-lisp-mode powershell-mode sh-mode) .
          (lambda () (flycheck-mode 1)))

         ((flycheck-after-syntax-check) .
          (lambda ()
            (if flycheck-current-errors
                (flycheck-list-errors)
              (when (get-buffer "*Flycheck errors*")
                (switch-to-buffer "*Flycheck errors*")
                (kill-buffer (current-buffer))
                (delete-window)))))))

Avy

(use-package avy-flycheck
  :after avy)

Packages

Winner-mode

Winner is used to restore windows.

(use-package winner
  :config (winner-mode 1))

Bind-key

Use the bind-key package (used by use-package).

(use-package bind-key
    :bind ("C-h B" . describe-personal-keybindings))

diff-hl

Highlight differences with diff-hl, which works better than git-gutter.

(use-package diff-hl
:hook ((prog-mode vc-dir-mode) . diff-hl-mode))

line-numbers

Use relative linenumbers.

(defun my/line-number-relative ()
  "Display relative line numbers."
  (interactive)
  (setq-local display-line-numbers-type 'visual)
  (display-line-numbers-mode 'toggle))

(defun my/line-number-t ()
  "Display absolute line numbers."
  (interactive )
  (setq-local display-line-numbers-type t)
  (display-line-numbers-mode 'toggle))

Indentation

Use aggressive mode for indentation. Use to be auto-indent, but aggressive seems better.

(use-package aggressive-indent
  :config (global-aggressive-indent-mode t))

which-key

(use-package which-key
  :diminish which-key-mode
  :init (which-key-mode t)
  :custom
  (which-key-idle-delay 0.2)
  (which-key-sort-order 'which-key-key-order-alpha))

Company

Auto completion.

Company-mode

Complete anything

(use-package company
:diminish
:config
  (global-company-mode t)
  (setq company-idle-delay 0))

Company-shell

Add more functions to company

(use-package company-shell
  :config
  (add-to-list 'company-shell-modes '(bat-mode powershell-mode))
  :hook (shell-mode . (lambda ()
                             (if shell-mode
                                 (add-to-list 'company-backends '(company-shell company-shell-env)))
                             (delete '(company-shell company-shell-env) 'company-backends))))

Company-keymapfix

A fix to enable [tab] to expand yasnippets etc in company-mode-map. From StackOverflow. Another tip is in Reddit.

(defun company-yasnippet-or-completion ()
  (interactive)
  (let ((yas-fallback-behavior nil))
    (unless (yas-expand)
      (call-interactively #'company-complete-common))))

(add-hook 'company-mode-hook (lambda ()
                               (substitute-key-definition 'company-complete-common
                                                          'company-yasnippet-or-completion
                                                          company-active-map)))

Company backends

(defun company-emacs-lisp-mode ()
  "Set up `company-mode' for `emacs-lisp-mode'."
  (set (make-local-variable 'company-backends)
       '((company-yasnippet
          :with
          company-elisp
          company-dabbrev-code
          company-files))))
(add-hook 'emacs-lisp-mode-hook 'company-emacs-lisp-mode)

ace-window

Switch windows and frames quickly.

(use-package ace-window
  :custom
  (aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l))
  (aw-background nil)
  (aw-dispatch-always t)
  :bind (("M-o" . ace-window)
         ("C-x o" . aw-flip-window))
  :custom-face (aw-leading-char-face
                ((t (:foreground "light sky blue"
                                 :background "#434343"
                                 :weight bold :height 2.0)))))

Resize windows

Use resize-window for changing size.

(use-package resize-window
  :bind ("C-;" . resize-window))

Pretty bullets

This was slow before, in emacs 25.1, but seems to work now in version 25.2.

(use-package org-bullets
  :custom (org-bullets-bullet-list  '("" "" "" "" ""))
  :hook (org-mode . org-bullets-mode))

Better shell

(use-package better-shell
      :config
  (defhydra hydra-better-shell (:color blue :columns 2)
    "Better Shell commands"
    ("s" better-shell-shell "Cycle shell" :color red)
    ("c" better-shell-for-current-dir  "New shell for current dir")
    ("r" better-shell-remote-open "Open remote shell")
    ("h" better-shell-sudo-here "Sudo here")
    ("p" better-shell-for-projectile-root "Shell for Projectile root")
    ("q" nil "cancel")
    ("RET" nil))
  :bind ("C-c S" . hydra-better-shell/body))

Copy-as-format

Copy with formatting.

(use-package copy-as-format
  :config
  (defhydra hydra-copy-as-format (:color blue :columns 3)
    "Copy as format"
    ("a" copy-as-format-asciidoc "asciidoc")
    ("d" copy-as-format-disqus   "disqus")
    ("g" copy-as-format-github   "github/lab/bucket")
    ("H" copy-as-format-hipchat  "hipchat")
    ("h" copy-as-format-html     "html")
    ("j" copy-as-format-jira     "jira")
    ("m" copy-as-format-markdown "markdown")
    ("M" copy-as-format-mediawik "mediawiki")
    ("o" copy-as-format-org-mode "org-mode")
    ("p" copy-as-format-pod      "pod")
    ("r" copy-as-format-rst      "rst")
    ("s" copy-as-format-slack    "slack")
    ("q" nil "quit"))
  :bind ("C-c w" . hydra-copy-as-format/body)
  )

Try

Use try to test packages.

(use-package try
  :commands try)

htmlize

Needed by org-babel-export

(use-package htmlize)

ipcalc

IP subnet calculation. To use it, evaluate (ipcalc "10.0.0.0/8") for example.

(use-package ipcalc
  :bind ("C-c i" . ipcalc))

Treemacs

Directory navigating explorer-style.

(use-package treemacs
  :bind (("C-x t" . treemacs)
         :map treemacs-mode-map
         ("C-x t" . treemacs-toggle))
  :config
  (setq treemacs-follow-after-init t
        treemacs-show-hidden-files t)
  (treemacs-follow-mode t)
  (pcase (cons (not (null (executable-find "git")))
               (not (null (executable-find "python3")))
               (`(t . t)
                (treemacs-git-mode 'extended))
               (`(t . _)
                (treemacs-git-mode 'simple)))))

ztree

Cool directory package.

(use-package ztree
  :bind ("C-x z" . ztree-dir)
  :config (setq-default ztree-dir-show-filtered-files t))

Verify-url

Check urls in an file.

(use-package verify-url)

Undo-tree

Make undo more intuitive.

(use-package undo-tree
  :diminish
  :demand
  :config
  (global-undo-tree-mode 1)
  (setq undo-tree-visualizer-diff t)
  :bind (("C-z" . undo)
         ("C-S-z" . undo-tree-redo)))

RSS stuff

Use elfeed ass RSS-reader, plus extras.

Elfeed-org

Organise RSS with org-mode.

(use-package elfeed-org
  :after elfeed
  :config (setq rmh-elfeed-org-files (list (expand-file-name "elfeed.org" my/org-directory))
                rmh-elfeed-org-auto-ignore-invalid-feeds nil))

Elfeed-goodies

Some extras

(use-package elfeed-goodies
  :config (elfeed-goodies/setup))

Elfeed

Read RSS-feeds. From http://pragmaticemacs.com/emacs/read-your-rss-feeds-in-emacs-with-elfeed/

(use-package elfeed
  :config
  (setq elfeed-db-directory (expand-file-name ".cache/elfeeddb" user-emacs-directory))
  (setq elfeed-search-filter "@1-days-ago +unread")
  (set-face-attribute 'elfeed-search-unread-title-face nil :weight 'normal :foreground "khaki2")

  (defface elfeed-emacs
    '((t :foreground "cyan"))
    "Marks Emacs in Elfeed."
    :group 'elfeed)

  (push '(emacs elfeed-emacs)
        elfeed-search-face-alist)

  (defface elfeed-security
    '((t :foreground "hot pink"))
    "Marks Security in Elfeed."
    :group 'elfeed)

  (push '(security elfeed-security)
        elfeed-search-face-alist)

  (defface elfeed-windows
    '((t :foreground "sky blue"))
    "Marks Windows in Elfeed."
    :group 'elfeed)

  (push '(windows elfeed-windows)
        elfeed-search-face-alist)

  (defface elfeed-network
    '((t :foreground "SpringGreen1"))
    "Marks Network in Elfeed."
    :group 'elfeed)

  (push '(network elfeed-network)
        elfeed-search-face-alist)

  ;; Toggle star for post
  (defalias 'elfeed-toggle-star
    (elfeed-expose #'elfeed-search-toggle-all 'star))

  (defun bjm/elfeed-load-db-and-open ()
    "Wrapper to load the elfeed db from disk before opening"
    (interactive)
    (elfeed-db-load)
    (elfeed-org)
    (elfeed-goodies/setup)
    (elfeed)
    (elfeed-search-update--force)
    (elfeed-search-set-filter "@1-months-ago"))

  ;;write to disk when quiting
  (defun bjm/elfeed-save-db-and-bury ()
    "Wrapper to save the elfeed db to disk before burying buffer"
    (interactive)
    (elfeed-db-save)
    (quit-window))

  ;;Mark as read, from https://cestlaz.github.io/posts/using-emacs-29%20elfeed/
  (defun elfeed-mark-all-as-read ()
    (interactive)
    (mark-whole-buffer)
    (elfeed-search-untag-all-unread))

  :bind (("C-x w" . bjm/elfeed-load-db-and-open)
         :map elfeed-search-mode-map
         ("h" . my/hydra-elfeed/body)
         ("m" . elfeed-toggle-star)
         ("R" . elfeed-mark-all-as-read)
         ("q" . bjm/elfeed-save-db-and-bury)))

Hydra

A hydra for elfeed.

(defhydra my/hydra-elfeed (:color blue :hint nil :columns 4)
   "Elfeed commands"
   ("b" (elfeed-search-browse-url) "Browse")
   ("fd" (elfeed-search-set-filter "@6-months-ago") "default")
   ("fc" (elfeed-search-set-filter "@6-months-ago +code") "code")
   ("fe" (elfeed-search-set-filter "@6-months-ago +emacs") "emacs")
   ("fs" (elfeed-search-set-filter "@6-months-ago +security") "security")
   ("ft" (elfeed-search-set-filter "@1-days-ago +unread") "today")
   ("fw" (elfeed-search-set-filter "@7-days-ago +unread") "Week")
   ("*" (elfeed-search-set-filter "@6-months-ago +star") "filter star")
   ("g" elfeed-search-update--force "Update feed")
   ("G" elfeed-search-fetch "Update all")
   ("L" elfeed-goodies/toggle-logs "Logs")
   ("m" (elfeed-toggle-star) "star")
   ("R" (elfeed-mark-all-as-read) "Mark all as read")
   ("T" (elfeed-search-set-filter "@1-day-ago") "Today")
   ("S" elfeed-search-set-filter "Set filter")
   ("s" elfeed-search-live-filter "Search")
   ("p" previous-line "previous")
   ("n" next-line "next")
   ("Q" bjm/elfeed-save-db-and-bury  "Quit, save DB")
   ("q" nil "quit")
   )

hungry-mode

Delete whitespace more efficiently.

(use-package hungry-delete
  :diminish hungry-delete-mode
  :config
  (global-hungry-delete-mode t)
  :custom (hungry-delete-except-modes '(minibuffer-mode)))

avy

Jump to any character.

(use-package avy
  :bind (("C-." . avy-goto-char)
         ("C-:" . avy-goto-char-2)))

Silversearcher

Use ag to search for stuff. Requires silversearcher-ag to be installed in the system.

(use-package ag
  :commands counsel-ag)

Ripgrep

Use ripgrep to search for files. See Manual.

(use-package rg
  :config (rg-enable-default-bindings))

Macrostep

To check the expanded macro. Useful with use-package.

(use-package macrostep
  :bind ("C-c e" . macrostep-mode))

docker

(use-package docker
:bind ("C-c d" . docker))

apib-mode

Support files in apib format, API Blueprint

(use-package apib-mode)

Rainbows

Use different colors for delimeters to increase readability.

(use-package rainbow-delimiters
      :hook
      ((org-mode prog-mode) . rainbow-delimiters-mode))

Rainbow colors

Colorize numbers and text.

(use-package rainbow-mode
  :diminish rainbow-mode)

Restclient

A client to make REST-calls from emacs and Org-mode.

(use-package restclient
  :commands restclient
  :config
  (use-package ob-restclient
    :after org)
  (use-package company-restclient
    :after company
    :hook (restclient-mode .
                           (lambda ()
                             (set (make-local-variable 'company-backends)
                                  '(company-restclient))))))

Smart parenthesis

Automatically insert parenthesis.

(use-package smartparens
  :diminish
  :config (sp-local-pair 'org-mode "=" "=")
  :hook
  ((org-mode prog-mode shell-mode) . smartparens-mode))

rfc-mode

(use-package rfc-mode
  :config (setq rfc-mode-directory (expand-file-name "rfc/cache" no-littering-var-directory)))

Disable-mouse

No mice!

(use-package disable-mouse
  :hook (after-init)
  :custom (disable-mouse-mode-global-lighter nil)
  :config (global-disable-mouse-mode t))

Whitespace butler

Help to keep config clean.

(use-package ws-butler
  :diminish
  :hook ((prog-mode org-mode conf-mode) . ws-butler-mode))

Dumb Jump

Jump to definition support. Requires ag or rg to work efficiently. (Install with scoop on Windows.)

(use-package dumb-jump
  :custom
  (xref-show-definitions-function #'xref-show-definitions-completing-read)
  :init
  (add-hook 'xref-backend-functions #'dumb-jump-xref-activate))

Private and local stuff

Load private stuff

This load a local file with private info. Untangle with function in init.el.

(if (file-exists-p my/private-orgfile)
    (when (not (and (file-exists-p my/private-elfile)
                    (file-newer-than-file-p my/private-elfile my/private-orgfile)))
      (my/tangle-config-org my/private-orgfile my/private-elfile)))

;; Load the el-file
(if (file-exists-p my/private-elfile)
    (load-file my/private-elfile))

See also: http://dotemacs.de/multiemacs.html

Load secret stuff

Load secret stuff from this encrypted org-file.

EasyPG

Since we use "use-package" to load builtin function, add ":ensure nil".

(use-package epa-file
:straight (:type built-in)
  :config
  (setq epa-file-select-keys nil)
  (setq epa-file-encrypt-to "8A114B0F26AA73E8")
  (setq epa-file-cache-passphrase-for-symmetric-encryption t)
  (setq epg-pinentry-mode 'loopback))

Org-crypt

enable encryption of org-files.

(use-package org-crypt
:straight (:type built-in)
  :config
  (org-crypt-use-before-save-magic)
  (setq org-crypt-tag-matcher "encrypt")
  (add-to-list 'org-tags-exclude-from-inheritance (quote "encrypt"))
  (add-to-list 'org-tags-exclude-from-inheritance (quote "crypt")))

Load secrets from this file

This part dont work yet.

;;(if (file-exists-p (expand-file-name "secret.org.gpg" my/emacs-shared-dir))
;; (org-babel-load-in-session-maybe (expand-file-name "secret.org.gpg" my/emacs-shared-dir)))

Authinfo file

Define path for .authinfo-file

(use-package auth-source-pass
  :config
  (setq auth-sources (list (expand-file-name "emacs/.authinfo.gpg" my/onedrive-dir)))
  (setq auth-source-pass-port-separator "#")
  (setq auth-source-debug t)
  (add-to-list 'auth-source-protocols '(scp "scp" "22") t)
  (auth-source-pass-enable))

password-store

Use unix password-store

(use-package password-store
  :after auth-source-pass)
(use-package pass
  :after password-store
  :bind ("C-x p" . pass))

Custom file for customize

Use a separate file for emacs "customize".

(setq custom-file (expand-file-name "customize.el" user-emacs-directory))
(when (file-exists-p custom-file)
  (load custom-file 'noerror))

Use only "'" instead of "quotes" for customize.

(advice-add 'custom-save-all :around
            (lambda (orig)
              (let ((print-quoted t))
                (funcall orig))))

Lisp

My own Lisp-files

;; Local lisp-directory
(when (not (file-exists-p "lisp"))
      (make-directory (concat user-emacs-directory "lisp") t))
(add-to-list 'load-path (concat user-emacs-directory "lisp"))

Use a shared LISP-directory between installed Emacsen. Emacs for Windows have the HOME variable defined as default.

(setq lispdir (let (lispdir) (expand-file-name ".config/lisp/" (getenv "HOME"))))

(when (file-exists-p lispdir)
  (add-to-list 'load-path lispdir))

Tuning

Garbage collection

Tries to change the variable dynamic. From https://bling.github.io/blog/2016/01/18/why-are-you-changing-gc-cons-threshold/

(defun my-minibuffer-setup-hook ()
  (setq gc-cons-threshold (* 50 1024 1024)))

(defun my-minibuffer-exit-hook ()
  (setq gc-cons-threshold (* 5 1024 1024)))

(defun my-projectile-before-switch-project-hook ()
  (setq gc-cons-threshold (* 50 1024 1024)))

(add-hook 'minibuffer-setup-hook #'my-minibuffer-setup-hook)
(add-hook 'minibuffer-exit-hook #'my-minibuffer-exit-hook)
(add-hook 'projectile-before-switch-project-hook #'my-projectile-before-switch-project-hook)

File encoding settings

Windows Clipboard uses different encoding.

(when (eq system-type 'windows-nt)
  (set-clipboard-coding-system 'utf-16le-dos))

Sentence

(setq sentence-end-double-space nil)

Keyboard settings

Windows keys (W32)

(when (eq system-type 'windows-nt)
     (setq w32-capslock-is-shiftlock nil)
     (setq w32-enable-caps-lock nil))

Set-mark for lxss

Set mark-command for Windows env

(bind-key "M-SPC" 'set-mark-command)

ibuffer

Use ibuffer for buffers. Sort them accordingly. ibuffer is a built in command but use use-package for simpler configuration. projectile-ibuffer is also available with projectile.

(use-package ibuffer
  :straight (:type built-in)
  :bind ("C-x C-b" . ibuffer)
  :config
  (setq ibuffer-saved-filter-groups
        (quote (("default"
                 ("Dired" (mode . dired-mode))
                 ("Shell" (or
                           (mode . eshell-mode)
                           (mode . shell-mode)))
                 ("PowerShell" (mode . powershell-mode))
                 ("code" (mode . prog-mode))
                 ("Magit" (or
                           (name . "^magit")
                           (name . "\\*magithub.*")))
                 ("Emacs" (or
                           (name . "^\\*scratch\\*$")
                           (name . "^\\*Messages\\*$")
                           (mode . emacs-lisp-mode)))
                 ("Errors" (or
                            (name . ".*error*")
                            (name . ".*[wW]arning")
                            (mode . special-mode)))
                 ("Tramp" (or (filename . "^\\/scp:")
                              (name . "^\\*tramp")))
                 ("iBuffer" (mode . ibuffer-mode))
                 ("Gists" (name . "^\\*gist.*"))
                 ("Org" (or
                         (mode . org-mode)
                         (name . "^\\*Org Agenda\\*$")))
                 ("Help" (or (name . "\\*Help\\*")
                             (name . "\\*Apropos\\*")
                             (name . "\\*info\\*")
                             (mode . help-mode)
                             (mode . helpful-mode))))
                ("Help"
                 ("Man" (mode . man-mode))
                 ("Help" (or (name . "\\*Help\\*")
                             (name . "\\*Apropos\\*")
                             (name . "\\*info\\*")
                             (mode . help-mode)
                             (mode . helpful-mode)))
                 ("Magit" (name . "^magit"))
                 ("dired" (mode . dired-mode)))
                ("Org"
                 ("Org" (or
                         (mode . org-mode)
                         (name . "^\\*Org Agenda\\*$")))))))
  (customize-set-variable 'ibuffer-show-empty-filter-groups nil)
  (customize-set-variable 'ibuffer-expert t)
  (customize-set-variable 'ibuffer-use-other-window t)
  :hook (ibuffer-mode .
                      (lambda ()
                        (ibuffer-auto-mode 1)
                        (ibuffer-switch-to-saved-filter-groups "default")
                        (unless (eq ibuffer-sorting-mode 'alphabetic)
                          (ibuffer-do-sort-by-alphabetic)))))

ibuffer-vc

Get status by version-control.

(use-package ibuffer-vc
  :config
  (setq ibuffer-formats
        '((mark modified read-only vc-status-mini " "
                (name 18 18 :left :elide)
                " "
                (size 9 -1 :right)
                " "
                (mode 16 16 :left :elide)
                " "
                (vc-status 16 16 :left)
                " "
                filename-and-process)))
  :hook (ibuffer-mode .
                      (lambda ()
                        (ibuffer-vc-set-filter-groups-by-vc-root)
                        (unless (eq ibuffer-sorting-mode 'alphabetic)
                          (ibuffer-do-sort-by-alphabetic))))
  )

ibuffer-projectile

Group buffers based on projectile.

(use-package ibuffer-projectile
  :bind (:map ibuffer-mode-map
              ("c" . ibuffer-projectile-set-filter-groups)
              ("/ -" . ibuffer-filter-by-directory)))

ivy, swiper and counsel

These are really useful packages. http://oremacs.com/swiper/ Replaced IDO with Ivy.

(use-package ivy
  :diminish ivy-mode
  :custom (ivy-initial-inputs-alist nil)
  :config
  (ivy-mode 1)
  (setq ivy-use-virtual-buffers t
        ivy-count-format "(%d/%d) "
        enable-recursive-minibuffers t)
  :bind
  ("C-x C-f" . counsel-find-file)
  ("C-c C-S-F" . counsel-recentf)
  ("C-c C-S-R" . ivy-resume)
  ("C-s" . swiper)
  ("C-r" . swiper)
  ("C-c g" . counsel-git)
  ("C-c j" . counsel-git-grep)
  ("C-c k" . counsel-ag)
  ("C-c r" . counsel-rg)
  ("C-c G" . counsel-search))

Amx

Use amx instead of smex for smart executionlist. But keep the old save-filename for now.

(use-package amx
  :custom
  (amx-save-file (expand-file-name "smex-save.el" no-littering-var-directory))
  :config
  (amx-mode t))

Swiper

(use-package swiper
  :config
  (setq ivy-use-selectable-prompt t
        swiper-action-recenter t
        swiper-include-line-number-in-search t
        swiper-goto-start-of-match t
        swiper-stay-on-quit nil)
  (set-face-background 'swiper-line-face "Light Slate Grey"))

Counsel

(use-package counsel
  :diminish
  :config
  (setq counsel-describe-function-function #'helpful-callable
        counsel-describe-variable-function #'helpful-variable)
  (counsel-mode 1)
  :bind
  ("M-x" . counsel-M-x)
  ("C-h f" . counsel-describe-function)
  ("C-h v" . counsel-describe-variable))

Ivy hydra

(use-package ivy-hydra)

Ivy rich

(use-package ivy-rich
  :init  (ivy-rich-mode 1)
  :config
  (setcdr (assq t ivy-format-functions-alist) #'ivy-format-function-line)
  (customize-set-variable 'ivy-rich-path-style 'abbrev))

Counsel-tramp

Use counsel to navigate hosts.

(use-package counsel-tramp
  :commands counsel-tramp
  :hook
  (counsel-tramp-pre-command .
                                  (lambda ()
                                    (global-aggressive-indent-mode 0)
                                    (projectile-mode 0)
                                    (editorconfig-mode 0)
                                    (yas-minor-mode 0)
                                    (setq make-backup-files nil)
                                    (setq create-lockfiles nil)))
  (counsel-tramp-quit .
                           (lambda ()
                             (global-aggressive-indent-mode 1)
                             (projectile-mode 1)
                             (editorconfig-mode 1)
                             (yas-minor-mode 1)
                             (setq make-backup-files t)
                             (setq create-lockfiles t))))

Windmove

Move between windows quickly.

(when (fboundp 'windmove-default-keybindings)
  (windmove-default-keybindings))
(define-key org-read-date-minibuffer-local-map (kbd "<left>") (lambda () (interactive) (org-eval-in-calendar '(calendar-backward-day 1))))
(define-key org-read-date-minibuffer-local-map (kbd "<right>") (lambda () (interactive) (org-eval-in-calendar '(calendar-forward-day 1))))
(define-key org-read-date-minibuffer-local-map (kbd "<up>") (lambda () (interactive) (org-eval-in-calendar '(calendar-backward-week 1))))
(define-key org-read-date-minibuffer-local-map (kbd "<down>") (lambda () (interactive) (org-eval-in-calendar '(calendar-forward-week 1))))

Orgmode customizations

Make windmove work in org-mode:

(add-hook 'org-shiftup-final-hook 'windmove-up)
(add-hook 'org-shiftleft-final-hook 'windmove-left)
(add-hook 'org-shiftdown-final-hook 'windmove-down)
(add-hook 'org-shiftright-final-hook 'windmove-right)
(setq org-support-shift-select 'always)

Own stuff

Toggle truncate lines

(setq-default truncate-lines nil)
(setq truncate-partial-width-windows nil)
(bind-key "C-c t" 'toggle-truncate-lines)

Wrap long lines

Visual-line-mode affects the variable word-wrap (toggle-word-wrap).

(setq-default visual-line-mode t)

No case-sensitive for search

(setq-default case-fold-search t)

Turn off case sensitivity for buffers

(customize-set-variable 'read-buffer-completion-ignore-case t)

Scrolling hydra

Key bindings for scrolling.

(defhydra hydra-scroll (:color pink)
  "Scroll buffers"
  ("v" scroll-up-command "Up")
  ("b" scroll-down-command "Down")
  ("M-v" scroll-down-command)
  ("V" scroll-other-window "Other window up")
  ("B" scroll-other-window-down "Other window down")
  ("q" nil "cancel"))
(bind-key "M-v" 'hydra-scroll/body)

Theme and settings

Theme

Load custom themes.

(use-package doom-themes
  :config (load-theme 'doom-vibrant t nil))

Define function to load theme in server mode.

(defun my/load-themes ()
  "Loads my themes."
  (interactive)
  (load-theme 'doom-vibrant t nil))

Load different theme if in gui or terminal

(unless (not (display-graphic-p))
  (load-theme 'tango-dark t)
  (my/load-themes))

Theme when emacs run as daemon.

This loads theme when emacs starts up as a daemon

(add-hook 'after-make-frame-functions
          (lambda (frame)
            (select-frame frame)
            (my/load-themes)))

Theme-chooser

Switch betweens selected themes with "C-<".

(use-package theme-looper
  :bind (("C-<" . theme-looper-select-theme-from-all)))

Fonts

Use Cascadia Code Nerd Font

(set-face-attribute 'default nil :font "CaskaydiaCove Nerd Font-12")
(set-face-attribute 'fixed-pitch nil :family "CaskaydiaCove Nerd Font Mono-12")
(set-face-attribute 'fixed-pitch-serif nil :family "CaskaydiaCove Nerd Font Mono-12")
(set-face-attribute 'variable-pitch nil :family "CaskaydiaCove Nerd Font-12")
(add-to-list 'default-frame-alist '(font . "CaskaydiaCove Nerd Font-12"))
(set-frame-font "CaskaydiaCove Nerd Font-11" nil t)
(add-to-list 'default-frame-alist '(fullscreen . maximized))

(defun demo-mode-on ()
  "Increases text-size when presenting."
  (interactive)
  (set-frame-font "CaskaydiaCove Nerd Font Mono-14" nil t))

(defun demo-mode-off ()
  "Decrease text-size to normal."
  (interactive)
  (set-frame-font "CaskaydiaCove Nerd Font-11" nil t))

Emojis

Emojis need a special font, setup based on what exists on the system. https://unicode.org/emoji/charts/full-emoji-list.html

(set-fontset-font
 t 'emoji
 (cond
  ((member "Apple Color Emoji" (font-family-list)) "Apple Color Emoji")
  ((member "Noto Color Emoji" (font-family-list)) "Noto Color Emoji")
  ((member "Noto Emoji" (font-family-list)) "Noto Emoji")
  ((member "Segoe UI Emoji" (font-family-list)) "Segoe UI Emoji")
  ((member "Symbola" (font-family-list)) "Symbola")))

Minibuffer and echo area

Change font for the echo area (messages from Emacs) and also for the minibuffer, input text. From Emacs Wiki.

(defun my-minibuffer-setup-hook ()
  (setq-local face-remapping-alist '((minibuffer-prompt (:foreground "#51afef" :height 1.2)))))
(defun my-minibuffer-setup-hook ()
  (setq-local face-remapping-alist '((default (:foreground "#51afef" :height 1.2)))))

(add-hook 'minibuffer-setup-hook 'my-minibuffer-setup-hook)

All the icons

All the icons is a standard set of icons used by doom modeline et al.

(use-package all-the-icons)

Startup settings

Things that we dont want during or after startup

;; Startup settings
(setq inhibit-splash-screen t
      inhibit-startup-screen t
      initial-scratch-message nil
      initial-major-mode 'org-mode)

;; No menubar, toolbar or scrollbar
(defun my/no-toolbars ()
  "Dont load toolbars or menubars, if in gui-mode"
  (when (display-graphic-p)
  (tool-bar-mode -1)
  (menu-bar-mode -1)
  (set-scroll-bar-mode nil)))

;; Load this when started as server (daemon)
(add-hook 'after-make-frame-functions
  (lambda (frame)
  (select-frame frame)
  (my/no-toolbars)))

;; Don't display toolbars when in gui-mode
(when (display-graphic-p)
  (my/no-toolbars))

;; Start in fullscreen when server
(set-frame-parameter nil 'fullscreen 'fullboth)

Powerline-mode

Use powerline in the message bar.

(use-package powerline
  :config
  (powerline-default-theme))

Customisations

Initial settings

(setq-default major-mode 'text-mode)
(display-line-numbers-mode -1)
(column-number-mode t)
(transient-mark-mode t)
(show-paren-mode t)
(customize-set-variable 'show-paren-style 'mixed)
(setq-default line-spacing 1)
(setq-default show-trailing-whitespace nil)
(setq-default indicate-empty-lines t)
(customize-set-variable 'apropos-do-all t)
(global-subword-mode t)
(diminish 'subword-mode)

Indents and tabs

(setq-default indent-tabs-mode nil)
(setq-default tab-width 2)
(setq-default tab-always-indent 'complete)      ;;Use tabs as indents, 2ch width

Newline settings

(setq mode-require-final-newline t)
(setq next-line-add-newlines nil)
(setq require-final-newline t)

Global highlight mode

(global-hl-line-mode nil)

Recent files

Record old openen files

(recentf-mode 1)
(setq recentf-max-menu-items 25)
(add-to-list 'recentf-exclude no-littering-var-directory)
(add-to-list 'recentf-exclude no-littering-etc-directory)
(add-to-list 'recentf-exclude (expand-file-name "straight/" user-emacs-directory))
(global-set-key (kbd "C-c C-r") 'recentf-open-files)

Reverting

Map <F5> to revert-buffer. But only revert if the file is not modified.

(global-set-key
  (kbd "<f5>")
  (lambda (&optional force-reverting)
  "Interactive call to revert-buffer. Ignoring the auto-save
  file and not requesting for confirmation. When the current buffer
  is modified, the command refuses to revert it, unless you specify
  the optional argument: force-reverting to true."
  (interactive "P")
  ;;(message "force-reverting value is %s" force-reverting)
  (if (or force-reverting (not (buffer-modified-p)))
  (revert-buffer :ignore-auto :noconfirm)
  (error "The buffer has been modified"))))

Setup autorevert.

(customize-set-variable 'global-auto-revert-mode t)
(customize-set-variable 'global-auto-revert-non-file-buffers t)

Bookmarks

Save bookmarks all the time.

(customize-set-variable 'bookmark-save-flag 1)
(customize-set-variable 'bookmark-version-control t)

Language

Spellchecking, use Flycheck with aspell. Need to load some other dictionaries. And to fix the flycheck setup. Read more at Flycheck-aspell.

(use-package flycheck-aspell
  :custom
  (cond
   ((executable-find "aspell")
    (ispell-program-name (executable-find "aspell"))
    (ispell-extra-args '("--sug-mode=ultra" "--lang=en_GB" "--add-extra-dicts=sv")))
   (t (setq ispell-program-name nil)))
  (ispell-dictionary "en_GB")
  (ispell-alternate-dictionary "sv")
  (ispell-silently-savep t)
  :config (flycheck-aspell-define-checker "org"
            "Org" ("--add-filter" "url")
            (org-mode))
  (add-to-list 'flycheck-checkers 'org-aspell-dynamic))

Dired customizations

Changes for local keyboard.

(use-package dired
  :straight (:type built-in)
  :hook ( dired-mode . dired-hide-details-mode)
  :bind ("C-x C-d" . dired)
  :custom  (dired-listing-switches "-laGho"))

Dired-single

Use this package to reuse the dired buffers.

(use-package dired-single
  :bind (("C-x d" . dired-single-magic-buffer)
         ([remap dired-find-file] . dired-single-buffer)
         ([remap dired-mouse-find-file-other-window] . dired-single-buffer-mouse)
         ([remap dired-up-directory] . dired-single-up-directory)
         (:map dired-mode-map
               ("'" . dired-single-up-directory))))

Dired all the icons

Use icons with dired.

(use-package all-the-icons-dired
:hook (dired-mode . all-the-icons-dired-mode))

No beeps

No beep.

(setq visible-bell t)

No blinking cursor

Disable the blinking cursor.

(setq no-blinking-cursor -1)

Buffer setup

Unique buffernames with uniquify.

(use-package uniquify
  :straight (:type built-in)
  :config
  (setq uniquify-buffer-name-style 'forward))

Time

Display time as 24-hour format

(setq display-time-24hr-format t)

Eldoc

Some eldoc settings.

(setq eldoc-idle-delay 0.1)
(diminish 'eldoc-mode)

Help-settings

From Find-func. Find function faster and jump to function directly.

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

Regular expressions

Use string as default syntax for regexp-builder.

(setq reb-re-syntax 'string)
(add-hook 'reb-mode-hook
          (lambda()
            (define-key reb-mode-map "C-c C-q" 'reb-quit)))

Info mode

Customizations for Info.

(bind-key "'" 'Info-up Info-mode-map)

Narrowing

Enable narrowing.

(put 'narrow-to-region 'disabled nil)
(put 'narrow-to-page   'disabled nil)

User interface

No popup dialog.

(customize-set-variable 'use-dialog-box nil)

Hippie expand

Hippie expands text automagically.

(global-set-key [remap dabbrev-expand] 'hippie-expand)

Abbrev mode

Abbrev autocorrects words. And load common abbreviations.

(setq-default abbrev-mode t)
(customize-set-variable 'save-abbrevs 'silently)
(setq abbrev-files (directory-files lispdir t "abbrev.*"))
(defun load-abbrev-files (list)
  "Load abbrev files."
  (let (value)
    (dolist (file list value)
      (if (file-readable-p file)
          (read-abbrev-file file)))))

(load-abbrev-files abbrev-files)

;; From https://stackoverflow.com/questions/17557186/turn-off-abbrev-mode-in-emacs-minibuffer
;; Disable abbrev in minibuffer.
(defun conditionally-disable-abbrev ()
  ""
  (abbrev-mode -1))

(add-hook 'minibuffer-setup-hook 'conditionally-disable-abbrev)
(add-hook 'minibuffer-exit-hook (lambda () (abbrev-mode 1)))

Diminish stuff

(diminish 'org-indent-mode)
(diminish 'abbrev-mode)
(diminish 'visual-line-mode)

Mouse

Hide the mouse pointer.

(mouse-avoidance-mode "banish")

Change yes-or-no to y-n

;; Press y or n for yes or no
(defalias 'yes-or-no-p 'y-or-n-p)

Eshell

Use the Emacs Lisp extended shell.

(setenv "PAGER" "cat")
(bind-key "C-c RET" 'eshell)

Use eshell built in functions for sudo. See this discussion for details.

(require 'em-tramp) ; to load eshell’s sudo
(require 'password-cache) ;Load password-cache
(setq eshell-prefer-lisp-functions t
      eshell-prefer-lisp-variables t
      password-cache t
      password-cache-expiry 3600
      eshell-history-size 10000
      eshell-buffer-maximum-lines 10000
      eshell-hist-ignoredups t
      eshell-scroll-to-bottom-on-input t)
(customize-set-variable 'eshell-aliases-file (expand-file-name ".config/eshell/aliases" (getenv "HOME")))
(with-eval-after-load 'esh-opt
  (setq eshell-destroy-buffer-when-process-dies t)
  (setq eshell-visual-commands '("htop" "zsh" "vim")))

Eshell prompt

Use a more estetic prompt even in eshell.

(use-package eshell-git-prompt
  :straight (eshell-git-prompt :fork t)
  :config (eshell-git-prompt-use-theme 'robbyrussell)
  :custom-face
  (eshell-git-prompt-directory-face ((t (:foreground "cornflower blue"))))
  (eshell-git-prompt-robyrussell-git-face ((t (:foreground "cyan"))))
  (eshell-git-prompt-robyrussell-branch-face ((t (:foreground "deepskyblue"))))
  (eshell-git-prompt-robyrussell-git-dirty-face ((t (:foreground "orange"))))
  (eshell-git-prompt-exit-fail-face ((t (:foreground "red")))))

Shell

Settings for the inferior shell. Replace cmd.exe with pwsh.exe on Windows.

(cond ((eq system-type 'windows-nt)
       (setq explicit-shell-file-name "pwsh.exe"
             explicit-pwsh.exe-args '())))

Backup

Backup and autosave options, + history

Backup of files

Saves backup of files in emacs-homedir. Keeps several versions of the files.

;; From https://github.com/magnars/.emacs.d
;; Write backup files to own directory
(setq backup-directory-alist
      `((".*" . ,my/emacs-backup-dir)))

;; Make backups of files, even when they're in version control
(setq delete-old-versions t
      version-control t
      vc-make-backup-files t
      backup-by-copying t
      kept-old-versions 10
      kept-new-versions 20
      auto-save-interval 50
      delete-by-moving-to-trash t)

Save current position

Go back to where you last were in the file.

;; Save point position between sessions
(use-package saveplace
  :config
  (save-place-mode 1)
  (setq save-place-file (expand-file-name ".places" no-littering-var-directory)))

Save history

Save a history of edited files.

(setq savehist-file (expand-file-name ".savehist" no-littering-var-directory))
(savehist-mode 1)
(setq
 history-length 50
 history-delete-duplicates t
 savehist-save-minibuffer-history t
 savehist-additional-variables
 '(kill-ring
   search-ring
   regexp-search-ring))

Super-save

Save buffers when idle

(use-package super-save
  :diminish super-save-mode
  :custom
  (super-save-auto-save-when-idle t)
  (super-save-idle-duration 8)
  (super-save-remote-files nil)
  (super-save-exclude '(".gpg"))
  (auto-save-default nil)
  (auto-save-no-message t)
  :config
  (add-to-list 'super-save-triggers 'ace-window)
  (add-to-list 'super-save-triggers 'magit-status)
  (add-to-list 'super-save-hook-triggers 'find-file-hook)
  (add-to-list 'super-save-hook-triggers 'org-after-refile-insert-hook)
  :hook (prog-mode . (lambda ()
                       (super-save-mode 1))))

Denote

Try out Denote to take notes. For more info see the Denote Manual. This is mostly copied from the sample config.

(defhydra hydra-denote (:color teal :hint nil)
  "
             Note                         Type                       Rename
             -------------------------------------------------------------------------------
             _n_: New                     _i_: Link                  _r_: Rename file
             _a_: New from region         _I_: Add links             _R_: Rename using Front Matter
             _j_: Journal                 _m_: Add missing links     _x_: Split Org subtree
             _s_: Subdirectory            _b_: Backlink              ^
             _N_: Choose type            _ff_: Find File             _q_: Quit
             _d_: Date                   _fb_: Find backlink
             _t_: Template                _F_: Open Denote directory
    "
  ("a"  my/denote-create-new-note-from-region)
  ("j"  my/denote-journal)
  ("n"  #'denote)
  ("N"  #'denote-type)
  ("d"  #'denote-date)
  ("s"  #'denote-subdirectory)
  ("t"  #'denote-template)
  ("i"  #'denote-link)
  ("I"  #'denote-link-add-links)
  ("m"  #'denote-link-add-missing-links)
  ("b"  #'denote-link-backlinks)
  ("ff"  #'denote-link-find-file)
  ("fb"  #'denote-link-find-backlink)
  ("F"  (find-file denote-directory))
  ("r"  #'denote-rename-file)
  ("R"  #'denote-rename-file-using-front-matter)
  ("x"  my/denote-split-org-subtree :base-map org-mode-map)
  ("q"  nil "cancel" :color blue))

(use-package denote
  :commands (hydra-denote/body denote)
  :custom
  (denote-directory (expand-file-name "notes/denote/" my/onedrive-dir))
  (denote-dired-directories (list denote-directory))
  (denote-date-prompt-use-org-read-date t)
  (denote-known-keywords '("emacs" "project" "powershell"))
  :hook
  ((dired-mode . denote-dired-mode-in-directories)
   (find-file . denote-link-buttonize-buffer))
  :bind (("C-c n" . hydra-denote/body)
         (:map dired-mode-map
               ("C-c C-d C-i" . #'denote-link-dired-marked-notes)
               ("C-c C-d C-r" . #'denote-dired-rename-marked-files)
               ("C-c C-d C-R" . #'denote-dired-rename-marked-files-using-front-matter))))

Denote journal

Create a journal directly with denote.

(defun my/denote-journal ()
  "Create an entry tagged 'journal', while prompting for a title."
  (interactive)
  (denote
   (denote--title-prompt)
   '("journal")))

Capture denote with org

Capture notes for denote with org-capture. Create a specific template for this.

(with-eval-after-load 'org-capture
  (setq denote-org-capture-specifiers "%l\n%i\n%?")
  (add-to-list 'org-capture-templates
               '("d" "New denote, note with Denote)" plain
                 (file denote-last-path)
                 #'denote-org-capture
                 :no-save t
                 :immediate-finish nil
                 :kill-buffer t
                 :jump-to-captured t)))

Split org header to denote

Inside an org-file, split the header and move it to a denote file instead.

(defun my/denote-split-org-subtree ()
  "Create new Denote note as an Org file using current Org subtree."
  (interactive)
  (let ((text (org-get-entry))
        (heading (org-get-heading :no-tags :no-todo :no-priority :no-comment))
        (tags (org-get-tags)))
    (delete-region (org-entry-beginning-position) (org-entry-end-position))
    (denote heading tags 'org)
    (insert text)))

Create denote from region

Create a denote from the active region.

(defun my/denote-create-new-note-from-region (beg end)
  "Create note whose contents include the text between BEG and END.
Prompt for title and keywords of the new note."
  (interactive "r")
  (if-let (((region-active-p))
           (text (buffer-substring-no-properties beg end)))
      (progn
        (denote (denote--title-prompt) (denote--keywords-prompt))
        (insert text))
    (user-error "No region is available")))

Denote templates

Add templates to denote.

(with-eval-after-load 'denote
  (customize-set-variable 'denote-templates
                          `((memo . ,(concat "* Content"
                                             "\n\n"
                                             "* Topics"
                                             "\n\n"))
                            (meeting-notes . ,(concat "* Notes\n"
                                                      "- Subject:\n"
                                                      "- Date:\n"
                                                      "- Attendees:\n"))))
  (when (file-readable-p (expand-file-name "denote-templates.el" user-emacs-directory))
    (load-file (expand-file-name "denote-templates.el" user-emacs-directory))))

Org-mode stuff

Read Org Beginners Customization Guide for info about this.

Org-mode variables

Other variables

Customize org-mode settings.

(setq org-use-sub-superscripts '{})
(setq org-export-with-sub-superscripts '{})
(setq org-export-coding-system 'utf-8)
(setq org-export-backends '(ascii html latex odt org))
(setq org-export-use-babel t)
(setq org-html-validation-link nil)
(setq org-agenda-skip-deadline-prewarning-if-scheduled t)
(setq org-agenda-skip-scheduled-if-done t)
(setq org-agenda-skip-scheduled-if-deadline-is-shown "repeated-after-deadline")
(setq org-agenda-include-diary nil)
(setq org-agenda-span 14)
(setq org-log-done 'time)
(setq org-log-redeadline 'time)
(setq org-log-reschedule 'time)
(setq org-log-refile 'time)
(setq org-log-into-drawer t)
(setq org-enforce-todo-checkbox-dependencies t)
(setq org-enforce-todo-dependencies t)
(setq org-agenda-dim-blocked-tasks t)
(setq org-fast-tag-selection-single-key t)
(setq org-use-fast-todo-selection t)
(setq org-enable-priority-commands nil)
(setq org-src-preserve-indentation t)
(setq org-confirm-babel-evaluate 'my/org-confirm-babel-evaluate)
(setq org-ellipsis "  ")

Refile

Refiling notes settings.

(setq org-refile-use-outline-path 'file)
(setq org-refile-allow-creating-parent-nodes 'confirm)
(setq org-outline-path-complete-in-steps nil)

Org-modules

To be able to execute code in org mode these should be loaded.

(require 'ob-shell)
(require 'ob-eshell)
(require 'ob-python)
(require 'ob-C)

Org-files

My org-files for Todo-list and agenda. Store the filenames to use for agenda in a separate file.

Keywords

Keywords, keybindings and colors for headlines in org-mode.

(setq org-todo-keywords
      '((sequence "TODO(t!)" "IN-PROGRESS(p!)" "NEXT(n!)" "WAITING(w@/!)" "|" "DONE(d@)")
        (sequence "IDEA(i!)" "READ(r!)" "|")
        (sequence "REPORT(z!)" "BUG(b!)" "|" "RESOLVED(x@)")
        (sequence "|" "CANCELED(c@)" "DELEGATED(l@)" "SOMEDAY(s!)")))
(setq org-todo-keyword-faces
      '(("TODO" . (:foreground "cyan" :weight bold))
        ("IN-PROGRESS" . (:foreground "yellow" :weight bold))
        ("NEXT" . (:foreground "yellow" :weight bold))
        ("DONE" . (:foreground "green" :weight bold))
        ("WAITING" . (:foreground "red" :weight bold))
        ("SOMEDAY" . (:foreground "gray" :weight bold))
        ("IDEA" . (:foreground "dark orange" :weight bold))
        ("READ" . (:foreground "dark orange" :weight bold))
        ("BUG" . (:foreground "magenta" :weight bold))
        ("REPORT" . (:foreground "cyan" :weight bold))))
(bind-key "C-c l" 'org-store-link)
(bind-key "C-c a" 'org-agenda)
(bind-key "C-c c" 'org-capture)

Org Archiving

Separate file for archiving stuff. Use datetree syntax.

(setq my/org-archive-file (expand-file-name "archive/archive.org" my/org-directory))
(when (not (file-exists-p (file-name-directory my/org-archive-file)))
      (make-directory (file-name-directory my/org-archive-file) t))
(setq org-archive-location (concat my/org-archive-file "::datetree/* From %s"))

Org custom agenda

For more info about this, see Org Agenda Custom Commands.

(setq org-agenda-custom-commands
      '(("c" "Weekly schedule"
         ((agenda ""
                  ((org-agenda-span 10)
                   (org-agenda-start-on-weekday nil)
                   (org-agenda-repeating-timestamp-show-all t)
                   (org-agenda-skip-function '(org-agenda-skip-entry-if 'deadline 'scheduled))))
          (alltodo ""
                   ((org-agenda-time-grid nil)
                    (org-deadline-warning-days 90))))
         ((org-agenda-compact-blocks t)))

        ("d" "Upcoming dates"
         ((agenda ""
                  ((org-agenda-entry-types '(:deadline))))
          (agenda ""
                  ((org-agenda-entry-types '(:scheduled)))))
         ((org-agenda-time-grid nil)
          (org-agenda-start-on-weekday nil)
          (org-agenda-span 1)
          (org-deadline-warning-days 14)
          (org-agenda-time-grid nil)
          (org-agenda-compact-blocks t)))

        ("l" "Log for last week"
         ((agenda ""
                  ((org-agenda-span 14)
                   (org-agenda-start-day "-7d")
                   (org-agenda-repeating-timestamp-show-all t)
                   (org-agenda-include-inactive-timestamps t))))
         ((org-agenda-compact-blocks t)))

        ("h" . "Hemma|Huset")
        ("hh" "Agenda and Home-related tasks" tags-todo "Hemma|Huset"
         ((agenda "")
          (org-agenda-sorting-strategy '(priority-up effort-down))))
        ("hc" "Todo" tags-todo "Cyklar"
         ((agenda "")
          (todo "TODO|IN-PROGRESS")
          (org-agenda-sorting-strategy '(priority-up effort-down))))
        ("hf" "Todo" tags-todo "Fordon"
         ((agenda "")
          (todo "TODO|IN-PROGRESS")
          (org-agenda-sorting-strategy '(priority-up effort-down))))
        ("hu" "Todo" tags-todo "Huset"
         ((agenda "")
          (todo "TODO|IN-PROGRESS")
          (org-agenda-sorting-strategy '(priority-up effort-down))))

        ("w" "Agenda and Office-related tasks" tags-todo "work|office"
         ((agenda "")
          (todo "TODO|IN-PROGRESS")
          (org-agenda-sorting-strategy '(priority-up effort-down))))
        ))

Org-templates

A few templates to speed up capture.

(setq org-capture-templates
      `(("t" "To do items" entry (file+headline my/notes-file "To Do Items")
         "* TODO %^{Description of todo}\nAdded: %U\n\n%?" :prepend t)

        ;; Blog
        ("b" "Blog idea" entry (file+headline my/notes-file "Blog Topics")
         "* IDEA %^{Title} :Blog:\nAdded: %U\n\n%?" :prepend t)

        ;;Links
        ("l" "Link" entry (file+headline my/notes-file "Links")
         "* [[%^C][%^{Title}]]  %^G\nAdded: %U\n%?" :prepend t)

        ;; Notes
        ("n" "Note" entry (file+headline my/notes-file "Notes")
         "* %^{Title} :NOTE:\n%U\n%a\n\n%?" :clock-in t :clock-resume t)

        ;; Idea
        ("i" "Idea" entry (file+headline my/notes-file "Someday")
         "* IDEA %^{Title}\nAdded: %U\n%?" :prepend t)

        ;; Journal
        ("j" "Journal" entry (file+olp+datetree my/diary-file)
         "* %^{Enter title}\n%U\n%?" :clock-in t :clock-resume t)

        ;; Notes for code
        ("c" "Coding stuff")
        ("cc" "note with code" entry (file+headline my/notes-file "Code")
         "* %? \nAdded: %U\n#+begin_src %^{Language?|emacs-lisp|sh|powershell|python|html}\n%^C\n#+end_src\n")
        ("cs" "note with code, source" entry (file+headline my/notes-file "Code")
         "* %? \nAdded: %U\n#+begin_src %^{Language?|emacs-lisp|sh|powershell|python|html}\n%^C\n#+end_src\n%a\n")

        ;; Reports and bugs
        ("r" "Reporting")
        ("rb" "Bug" entry (file+headline my/notes-file "Reports")
         "* BUG %^{Description of bug} %^G\nAdded: %U\n%?")
        ("rr" "Report" entry (file+headline my/notes-file "Reports")
         "* REPORT %^{Description of report} %^G\nAdded: %U\n#+begin_example\n%^C\n#+end_example\n%?")
        ))

Localized calender

Use swedish calendar, from sv-kalender.

(load "sv-kalender")

Local name calendar

Celebrate names in calendar, load in org-agenda. From https://github.com/matsl/sv-kalender-namnsdagar/.

(load "sv-kalender-namnsdagar")

Org-Mobile

This copys files to MobileOrg dir where the MobileOrg app can read/write data.

(use-package org-mobile
  :straight (:type built-in)
  :init
  (autoload 'org-mobile-pull "org-mobile" nil t)
  (autoload 'org-mobile-push "org-mobile" nil t)
  :config
  (setq org-mobile-directory (expand-file-name "mobileorg/" my/emacs-shared-dir))
  (setq org-mobile-inbox-for-pull (expand-file-name "sync.org" my/org-directory))
  (setq org-mobile-files my/mobile-files)
  (setq org-mobile-agendas 'default)
  (setq org-mobile-force-id-on-agenda-items nil))

A simple setup here

Org-projects

Publish my org-files to html-dir. Org-publish tutorial Use backtick "`" and comma "," to use variable-expansion in the alist. See StackoverFlow

(require 'ox-publish)

(setq org-publish-timestamp-directory (expand-file-name ".org-timestamps/" no-littering-var-directory))
(setq org-publish-project-alist
`(("org" :components ("org-notes" "org-static"))
("org-notes"
:base-directory ,my/org-directory
:base-extension "org"
:publishing-directory ,(concat my/onedrive-dir "emacs/html")
:recursive t
:publishing-function org-html-publish-to-html
:headline-levels 4
:auto-preamble t
)
("org-static"
 :base-directory ,my/org-directory
 :base-extension "css\\|js\\|png\\|jpg\\|gif\\|pdf\\|mp3\\|ogg\\|swf"
 :publishing-directory ,(concat my/onedrive-dir "emacs/html")
 :recursive t
 :publishing-function org-publish-attachment
 )
("OL-event"
:base-directory ,(concat my/repo-dir "OL-Event/")
:base-extension "org"
:publishing-directory ,(concat my/repo-dir "OL-Event/")
:publishing-function org-gfm-export-to-markdown
:recursive t
)))

Org exports

ox-reveal

For presentations from org-mode. Homepage

(use-package ox-reveal
  :load-path "vendor/org-reveal"
  :after ox
  :config
  (setq org-reveal-root (concat "file://" (expand-file-name  "vendor/reveal.js" user-emacs-directory))))

ox-hugo

(use-package ox-hugo
  :after ox)

Export GHF markdown

Github-flavoured markdown

(use-package ox-gfm
  :after ox)

Export Jira

Export org as Jira.

(use-package ox-jira
  :after ox)

Export Confluence

Export to Atlassian Confluence.

(use-package ox-confluence
  :after ox)

org2jekyll

To make it possible to write in org and publish as jekyll.

(use-package org2jekyll)

Export mediawiki

(use-package ox-wk)

Export Trac-wiki

(use-package ox-trac)

Export markdown

(use-package auto-org-md
  :after ox)

Org tangle init files

Untangle init files automatically when save with org-babel. From Emacs From Scratch: Everything in Babel.

(defun my/org-babel-tangle-config ()
  (when (string-equal (buffer-file-name) my/emacs-orgfile)
    (let ((org-confirm-babel-evaluate nil))
      (org-babel-tangle))))

(add-hook 'org-mode-hook (lambda () (add-hook 'after-save-hook #'my/org-babel-tangle-config)))

Custom to check evaluation status

From Irreal.

(defun babel-confirm (flag)
  "Report the setting of org-confirm-babel-evaluate.
If invoked with C-u, toggle the setting"
  (interactive "P")
  (if (equal flag '(4))
      (setq org-confirm-babel-evaluate (not org-confirm-babel-evaluate)))
  (message "Babel evaluation confirmation is %s"
           (if org-confirm-babel-evaluate "on" "off")))

Custom to disable verification of evaluation.

From Mike Hamrick, GitLab.

(defun my/org-confirm-babel-evaluate (lang body)
  "Don't confirm code execution for these languages."
  (not (member lang '("python" "emacs-lisp" "shell" "powershell" "perl" "elisp" "eshell"))))

Org clock settings

Settings for org clock.

(org-clock-persistence-insinuate)
(setq org-clock-display-default-range 'thisweek)
(setq org-clock-persist t)
(setq org-clock-idle-time 60)
(setq org-clock-history-length 35)
(setq org-clock-in-resume t)
(setq org-clock-out-remove-zero-time-clocks t)

Language support

Add support for different programming languages and configuration files.

Powershell mode

Powershell-mode is useful.

(use-package powershell
  :straight (powershell :fork t)
  :commands powershell
  :config
  (setq powershell-eldoc-def-files (list (expand-file-name ".config/eldoc/powershell-eldoc.el" (getenv "HOME"))))
  (if (eq system-type 'gnu/linux)
      (setq powershell-location-of-exe "/usr/bin/pwsh")
    (setq powershell-location-of-exe "pwsh.exe")))
;; Comment these out while troubleshooting.
;;    (setq explicit-powershell\.exe-args '("-NoLogo" "-NoProfile" "-Command" "-"))
;;    (setq explicit-pwsh\.exe-args '("-NoLogo" "-NoProfile" "-Command" "-")))

Babel for powershell

(use-package ob-powershell
  :config (require 'ob-powershell)
  :custom (ob-powershell-powershell-command "pwsh -NoProfile -NoLogo"))

Load babel languages

(org-babel-do-load-languages
 'org-babel-load-languages
 '((shell      . t)
   (eshell     . t)
   (python     . t)
   (lisp       . t)
   (powershell . t)
   (perl       . t)
   (emacs-lisp . t)))

Markdown-mode

(use-package markdown-mode
  :commands
    (markdown-mode gfm-mode)
  :mode
    (("README\\.md\\'" . gfm-mode)
    ("\\.md\\'" . markdown-mode)
    ("\\.markdown\\'" . markdown-mode))
  :init
    (setq markdown-command "multimarkdown")
  :config
    (add-to-list 'auto-mode-alist '("\\.markdown\\'" . markdown-mode))
    (add-to-list 'auto-mode-alist '("\\.md\\'" . markdown-mode))
    (add-to-list 'auto-mode-alist '("README\\.md\\'" . gfm-mode)))

Markdown preview mode

(use-package markdown-preview-mode
  :commands markdown-preview)

SSH-config

Add mode for configuring .ssh/config and other related to SSH.

(use-package ssh-config-mode
:config
 (add-to-list 'auto-mode-alist '("/\\.ssh/config\\'"     . ssh-config-mode))
 (add-to-list 'auto-mode-alist '("/sshd?_config\\'"      . ssh-config-mode))
 (add-to-list 'auto-mode-alist '("/known_hosts\\'"       . ssh-known-hosts-mode))
 (add-to-list 'auto-mode-alist '("/authorized_keys2?\\'" . ssh-authorized-keys-mode))
 (add-hook 'ssh-config-mode-hook 'turn-on-font-lock)
)

Git

Modes for editing git-files

git-modes

(use-package git-modes
  :config
  (add-to-list 'auto-mode-alist (cons "/.dockerignore\\'" 'gitignore-mode)))

Autohotkey-mode

(use-package ahk-mode)

Yara-files

Mode that supports editing of Yara-files.

(use-package yara-mode)

Elastic search mode

(use-package es-mode
      :config
  (add-to-list 'auto-mode-alist '("\\.es$" . es-mode)))

Logstash-mode

Use logstash-mode for conf-files in logstash-directories.

(use-package logstash-conf
  :mode  (("logstash.*\\.conf\\'" . logstash-conf-mode)
          ("pipeline.*\\.conf\\'" . logstash-conf-mode)))

ini-mode

Windows ini-files.

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

CSV

Read csv-files.

(use-package csv-mode)

Docker file mode

Support Dockerfile.

(use-package dockerfile-mode)

Docker compose

Support Docker Compose files.

(use-package docker-compose-mode)

Toml-Mode

Support .toml-files, eg for Hugo.

(use-package toml-mode)

X509

Support for certificate files, with a hydra to navigate options.

(use-package x509-mode
  :config
  (add-to-list 'auto-mode-alist '("\\.cer\\'" . x509-mode))
  (add-to-list 'auto-mode-alist '("\\.crt\\'" . x509-mode))
  (add-to-list 'auto-mode-alist '("\\.crl\\'" . x509-mode))
  (add-to-list 'auto-mode-alist '("\\.csr\\'" . x509-mode))
  (add-to-list 'auto-mode-alist '("\\.pem\\'" . x509-mode))
  (add-to-list 'auto-mode-alist '("\\.key\\'" . x509-mode))
  (defhydra hydra-x509 (:color blue :columns 2)
    "X509 commands"
    ("a" x509-viewasn1 "View ASN1")
    ("c" x509-viewcert "View certificate")
    ("d" x509-viewdh "View DH")
    ("k" x509-viewkey "View key")
    ("r" x509-viewcrl "View CRL")
    ("q" nil "cancel"))
  :bind (:map x509-mode-map
              ("h" . hydra-x509/body))
  )

JSON-mode

Edit JSON-files.

(use-package json-mode
  :hook (json-mode . (lambda ()
                                   (make-local-variable 'js-indent-level)
                                   (setq js-indent-level 2))))

javascript

Add proxy .pac-files to javascript-mode.

(add-to-list 'auto-mode-alist '("\\.pac\\'" . javascript-mode))
(add-to-list 'auto-mode-alist '("wpad\\.dat\\'" . javascript-mode))

C# and .NET

C#

Support for C#, C-sharp.

(use-package csharp-mode
  :config
  (defun my/csharp-hook()
    (electric-pair-local-mode 1))
  :hook (csharp-mode . my/csharp-hook))

Dotnet

Interface to dotnet.

(use-package dotnet
  :hook (csharp-mode . dotnet-mode))

.NET-files

Support for dotnet-files.

(use-package csproj-mode)

Go language

(use-package go-mode)

LISP

Common LISP

Install C Lisp helper

(use-package slime
  :config
  (setq inferior-lisp-program "/usr/bin/sbcl"))

(use-package slime-company)

IELM

An Interactive mode for Emacs LISP.

(use-package ielm
  :straight (:type built-in)
  :custom (ielm-noisy nil))

LUA

For nmap script-engine files.

(use-package lua-mode
  :config
  (add-to-list 'auto-mode-alist '("\\.lua$" . lua-mode))
  (add-to-list 'auto-mode-alist '("\\.nse$" . lua-mode))
  (add-to-list 'interpreter-mode-alist '("lua" . lua-mode)))

Editorconfig

Elpy

A python helper.

(use-package elpy
  :custom (python-indent-offset 4))

To get automatic settings for git repositories. https://editorconfig.org/

(use-package editorconfig
  :diminish
  :hook (prog-mode . editorconfig-mode))

Chezmoi

Starting to use chezmoi for my dotfiles. Install the package to interact with that.

(use-package chezmoi
  :config (setq-default chezmoi-template-display-p t)
  :bind
  ("C-c C f" .  #'chezmoi-find)
  ("C-c C s" .  #'chezmoi-write)
  :hook (chezmoi-mode . (lambda ()
                               (if chezmoi-mode
                                   (add-to-list 'company-backends 'chezmoi-company-backend)
                                 (delete 'chezmoi-company-backend 'company-backends)))))

Help systems

Package-archives

Use Melpa only to list packages and read about them.

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

Cheat.sh

Check out stuff on https://cheat.sh/

(use-package cheat-sh
  :commands cheat-sh)

Free keys

To list what keys are free in different modes. Very useful.

(use-package free-keys
  :commands free-keys)

Info-colors

Colorisation of Info-text.

(use-package info-colors
  :hook (Info-selection . info-colors-fontify-node)
  :custom-face
  (info-colors-lisp-code-block ((t (:foreground "LightSkyBlue" :weight normal))))
  (info-xref ((t (:foreground "DeepSkyBlue" :weight normal))))
  (Info-quoted ((t (:foreground "SkyBlue" :weight normal)))))

helpful

A more helpful package for Emacs help.

(use-package helpful
  :custom (counsel-describe-function-function #'helpful-callable)
  (counsel-describe-variable-function #'helpful-variable)
  :custom-face (helpful-heading ((t (:foreground "GreenYellow" :weight bold))))
  :bind (("C-h h" . #'helpful-at-point)
         ("C-h C" . #'helpful-command)
         ("C-h F" . #'helpful-function)
         ("C-h M" . #'helpful-macro)
         ([remap describe-key] . helpful-key)
         ([remap describe-variable] . helpful-variable)
         ([remap describe-function] . helpful-callable)
         ([remap describe-symbol] . helpful-callable)
         ([remap describe-command] . helpful-command)))

External utilities

hackernews

Read hackernews in emacs.

(use-package hackernews
  :commands hackernews
  :custom-face
  (hackernews-link ((t (:foreground "gold" :weight normal))))
  (hackernews-link-visited ((t (:foreground "LimeGreen" :weight normal))))
  :config
  (customize-set-variable 'hackernews-visited-links-file (concat my/emacs-shared-dir "shared/visited-links.el"))
  (customize-set-variable 'hackernews-items-per-page 60)
  (customize-set-variable 'hackernews-item-format "%-7s%-80t %15c\n"))

StackExchange

Query Stackexchange from emacs.

(use-package sx
  :config
  (setq sx-cache-directory (expand-file-name "sx/cache/" no-littering-var-directory))

  (defhydra hydra-sx (:color blue :columns 4)
    "Stack Exchange"
    ("t" sx-tab-all-questions "All questions")
    ("i" sx-inbox "Inbox")
    ("o" sx-open-link "Open link")
    ("u" sx-tab-unanswered-my-tags "Unanswered")
    ("a" sx-ask "Ask")
    ("s" sx-search "Search")
    ("q" nil "Cancel"))

  :bind ("C-c x" . hydra-sx/body))

wiki-summary

Use wiki search from emacs

(use-package wiki-summary
  :commands wiki-summary)

XKCD

Show images from xkcd. With hydra.

(use-package xkcd
  :commands xkcd
  :config
  (defhydra hydra-xkcd (:color pink :hint nil)
    "
   ^Navigate^              ^Move^             ^Extra^
   -----------------------------------------------------------
   _b_: Browse             ^_k_ ↑^            _e_: Explanation
   _r_: Random         ← _h_    _l_ →         _c_: Copy link
   _g_: Update             ^_j_ ↓^            _a_: Alternate text
   _G_: Get                  ^^             ^^_q_: Quit
   "
    ("b"       xkcd-open-browser)
    ("r"       xkcd-rand)
    ("a"       xkcd-alt-text)
    ("g"       xkcd-get-latest)
    ("S-g"     xkcd-get)
    ("G"       xkcd-get)
    ("j"       scroll-up-command)
    ("SPC"     scroll-up-command)
    ("k"       scroll-down-command)
    ("S-SPC"   scroll-up-command)
    ("<left>"  xkcd-prev)
    ("h"       xkcd-prev)
    ("<right>" xkcd-next)
    ("l"       xkcd-next)
    ("e"       xkcd-open-explanation-browser)
    ("c"       xkcd-copy-link)
    ("q"       xkcd-kill-buffer :color blue)
    )
  :bind (:map xkcd-mode-map
              ("h" . hydra-xkcd/body))
  :hook (xkcd-mode . hydra-xkcd/body))

ePub reader

An ebook reader.

(defun my-nov-font-setup ()
  (face-remap-add-relative 'variable-pitch :family "CaskaydiaCove Nerd Font Mono"
                           :height 1.0))
(use-package nov
  :config (add-to-list 'auto-mode-alist '("\\.epub\\'" . nov-mode))
  :hook (nov-mode . my-nov-font-setup))

Links

The end

Just record a last message, to know that the whole file has been loaded.

;; Garbage collector - decrease threshold
(add-hook 'after-init-hook (lambda () (setq gc-cons-threshold (* 5 1024 1024))))

;; Turn of debug
(setq debug-on-error nil)
(setq debug-on-quit nil)

;;; Measure the startup time
(message "*** Finished emacs @ %s in %s" (my/format-time (current-time)) (my/startup-timer))
(message "*** This is the last line of the config. Startup time=%3.5s ***" (emacs-init-time))

(provide 'init)
;;; init.el ends here

Created: 2023-08-16 Wed 19:46

Validate