jmn / emacs-literate

Literate emacs config file

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Emacs Literate Configuration

Configuration

Table of Contents

About this file

This is an Emacs literate configuration template originally written by Andrés Gasson and adapted by Jussi Norlund. It contains the basic structure of a literate config along with some optimizations to ensure a fast load time.

Org File Tweaks

There are a few tweaks included in this org file that make it a little easier to work with.

Automatically Tangle

First there is a property defined on the file:

header-args :tangle yes

This tells emacs to automatically tangle (include) all code blocks in this file when generating the code for the config, unless the code block explicitly includes :tangle no as the above code block does.

Visibility Settings

Next we have a property defined on the Configuration heading that defines the visibility that tells org to show it’s direct children on startup. This way a clean outline of all sub headings under Configuration is shown each time this file is opened in org-mode.

Table of Contents

Finally, there is a Table of Contents heading that includes the tag: :TOC_3_gh:. This tells an org-mode package toc-org to generate a table of contents under this heading that has a max depth of 3 and is created using Github-style hrefs. This table of contents is updated everytime the file is saved and makes for a functional table of contents that works property directly on github.

Personal Information

Let’s set some variables with basic user information.

(setq user-full-name "Jussi Norlund"
      user-mail-address "mail@jmnorlund.net")

Emacs Initialisation

Settings

We’re going to increase the gc-cons-threshold to a very high number to decrease the load and compile time. We’ll lower this value significantly after initialization has completed. We don’t want to keep this value too high or it will result in long GC pauses during normal usage.

(eval-and-compile
  (setq gc-cons-threshold 402653184
        gc-cons-percentage 0.6))

Disable certain byte compiler warnings to cut down on the noise. This is a personal choice and can be removed if you would like to see any and all byte compiler warnings.

(setq byte-compile-warnings '(not free-vars unresolved noruntime lexical make-local))

Some default settings aka sanity defaults

;;; Code:
;; menu shit remove
(mapc
 (lambda (mode)
   (when (fboundp mode)
     (funcall mode -1)))
 '(menu-bar-mode tool-bar-mode scroll-bar-mode))

;;; Initialisation
(setq inhibit-default-init t
      inhibit-startup-echo-area-message t
      inhibit-startup-screen t
      initial-scratch-message nil)

;; warn when opening files bigger than 100MB
(setq large-file-warning-threshold 100000000)

(defconst gas-savefile-dir (expand-file-name "savefile" user-emacs-directory))

;; create the savefile dir if it doesn't exist
(unless (file-exists-p gas-savefile-dir)
  (make-directory gas-savefile-dir))

;;; UI
;; the blinking cursor is nothing, but an annoyance
(blink-cursor-mode -1)

;; disable the annoying bell ring
(setq ring-bell-function 'ignore)

;; disable startup screen
(setq inhibit-startup-screen t)

;; nice scrolling
(setq scroll-margin 0
      scroll-conservatively 100000
      scroll-preserve-screen-position 1)

;; mode line settings
(line-number-mode t)
(column-number-mode t)
(size-indication-mode t)

;; enable y/n answers
(fset 'yes-or-no-p 'y-or-n-p)

;; more useful frame title, that show either a file or a
;; buffer name (if the buffer isn't visiting a file)
(setq frame-title-format
      '((:eval (if (buffer-file-name)
                   (abbreviate-file-name (buffer-file-name))
                 "%b"))))

;; Productive default mode
(setq initial-major-mode 'org-mode)

;; When on a tab, make the cursor the tab length.
(setq-default x-stretch-cursor t)

;; Keep emacs Custom-settings in separate file.
(setq custom-file (expand-file-name "custom.el" user-emacs-directory))
(when (file-exists-p custom-file)
(load custom-file))

;; store all backup and autosave files in the tmp dir
(setq backup-directory-alist
      `((".*" . ,temporary-file-directory)))
(setq auto-save-file-name-transforms
      `((".*" ,temporary-file-directory t)))

;; revert buffers automatically when underlying files are changed externally
(global-auto-revert-mode t)

;; Make backups of files, even when they're in version control.
(setq vc-make-backup-files t)

;; Fix empty pasteboard error.
(setq save-interprogram-paste-before-kill nil)

Package Management

straight.el

Straight.el is a modern package manager for emacs, it allows me to load packages directly from Git/GitHub. It also integrates with use-package (see later in file).

 (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))
 (straight-use-package 'use-package)
 (use-package el-patch
 :straight t)
 (setq straight-use-package-by-default t)

Package Settings

We’re going to set the load-path ourselves and avoid calling (package-initilize) (for performance reasons) so we need to set package--init-file-ensured to true to tell package.el to not automatically call it on our behalf. Additionally we’re setting package-enable-at-startup to nil so that packages will not automatically be loaded for us since use-package will be handling that.

(eval-and-compile
  (setq load-prefer-newer t
        package-user-dir "~/.emacs.d/elpa"
        package--init-file-ensured t
        package-enable-at-startup nil)

  (unless (file-directory-p package-user-dir)
    (make-directory package-user-dir t)))

Use-Package Settings

Tell use-package to always defer loading packages unless explicitly told otherwise. This speeds up initialization significantly as many packages are only loaded later when they are explicitly used.

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

Manually Set Load Path

We’re going to set the load path ourselves so that we don’t have to call package-initialize at runtime and incur a large performance hit. This load-path will actually be faster than the one created by package-initialize because it appends the elpa packages to the end of the load path. Otherwise any time a builtin package was required it would have to search all of third party paths first.

(eval-and-compile
  (setq load-path (append load-path (directory-files package-user-dir t "^[^.]" t))))

Initialise Package Management

Next we are going to require package.el and add our additional package archives, ‘melpa’ and ‘org’. Afterwards we need to initialize our packages and then ensure that use-package is installed, which we promptly install if it’s missing. Finally we load use-package and tell it to always install any missing packages.

Note that this entire block is wrapped in eval-when-compile. The effect of this is to perform all of the package initialization during compilation so that when byte compiled, all of this time consuming code is skipped. This can be done because the result of byte compiling use-package statements results in the macro being fully expanded at which point use-package isn’t actually required any longer.

Since the code is automatically compiled during runtime, if the configuration hasn’t already been previously compiled manually then all of the package initialization will still take place at startup.

(eval-when-compile
  (require 'package)

  (unless (assoc-default "melpa" package-archives)
    (add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/") t))

  (package-initialize)
  (unless (package-installed-p 'use-package)
    (package-refresh-contents)
    (package-install 'use-package))
  (unless (package-installed-p 'bind-key)
    (package-refresh-contents)
    (package-install 'bind-key))
  (require 'use-package)
  (require 'bind-key)
  (setq use-package-always-ensure t)
  )

Packages

Display

;;  (load-theme 'modus-vivendi)
(use-package monokai-theme
  :ensure t
  :defer 1
  )
(use-package solarized-theme
  :disabled t
  :ensure t
  :defer nil
  (load-theme 'solarized-selenized-dark 'no-confirm))

(load-theme 'monokai t)

;;
;; Update the colour of the company-mode context menu to fit the Monokai theme
;; @source: https://github.com/search?q=deftheme+company-tooltip&type=Code
;;
(deftheme monokai-overrides)

(let ((class '((class color) (min-colors 257)))
      (terminal-class '((class color) (min-colors 89))))

  (custom-theme-set-faces
   'monokai-overrides

   ;; Linum and mode-line improvements (only in sRGB).
   `(linum
     ((,class :foreground "#75715E"
              :background "#49483E")))
   `(mode-line-inactive
     ((,class (:box (:line-width 1 :color "#2c2d26" :style nil)
                    :background "#2c2d26"))))

   ;; Custom region colouring.
   `(region
     ((,class :foreground "#75715E"
              :background "#49483E")
      (,terminal-class :foreground "#1B1E1C"
                       :background "#8B8878")))

   ;; Additional modes
   ;; Company tweaks.
   `(company-tooltip-common
     ((t :foreground "#F8F8F0"
         :background "#474747"
         :underline t)))

   `(company-template-field
     ((t :inherit company-tooltip
         :foreground "#C2A1FF")))

   `(company-tooltip-selection
     ((t :background "#349B8D"
         :foreground "#BBF7EF")))

   `(company-tooltip-common-selection
     ((t :foreground "#F8F8F0"
         :background "#474747"
         :underline t)))

   `(company-scrollbar-fg
     ((t :background "#BBF7EF")))

   `(company-tooltip-annotation
     ((t :inherit company-tooltip
         :foreground "#C2A1FF")))

   ;; Popup menu tweaks.
   `(popup-menu-face
     ((t :foreground "#A1EFE4"
         :background "#49483E")))

   `(popup-menu-selection-face
     ((t :background "#349B8D"
         :foreground "#BBF7EF")))

   ;; Circe
   `(circe-prompt-face
     ((t (:foreground "#C2A1FF" :weight bold))))

   `(circe-server-face
     ((t (:foreground "#75715E"))))

   `(circe-highlight-nick-face
     ((t (:foreground "#AE81FF" :weight bold))))

   `(circe-my-message-face
     ((t (:foreground "#E6DB74"))))

   `(circe-originator-face
     ((t (:weight bold))))))

old Use material theme

(use-package material-theme
  :ensure t
  :disabled t
  :config
  (load-theme 'material 'no-confirm))

(use-package zenburn-theme
  :ensure t
  :disabled t
  :init
  (load-theme 'zenburn 'no-confirm))

(use-package time
  :config
  (setq display-time-24hr-format t
        display-time-default-load-average nil)
;;  (display-time-mode)
)

(use-package windmove
  :config
  ;; use shift + arrow keys to switch between visible buffers
  (windmove-default-keybindings))

;; diminish mode symbols
(use-package diminish
  :ensure t
)
;; delight minor and major modes
(use-package delight
  :ensure t
)

highlights

;; highlight the current line
(global-hl-line-mode +1)

(use-package diff-hl
  :ensure t
  :defer nil
  :config
  (global-diff-hl-mode +1)
  (add-hook 'dired-mode-hook 'diff-hl-dired-mode)
  (add-hook 'magit-post-refresh-hook 'diff-hl-magit-post-refresh))

LineNumbers

(setq linum-format "%4d")

(defun my-linum-mode-hook ()
  (linum-mode t))

 (add-hook 'find-file-hook 'my-linum-mode-hook)

Timestamps

(defun format-date (format)
  (let ((system-time-locale "en_NZ.UTF-8"))
    (insert (format-time-string format))))

(defun insert-date ()
  (interactive)
  (format-date "%A, %B %d %Y"))

(defun insert-date-and-time ()
  (interactive)
  (format-date "%Y-%m-%d %H:%M:%S"))

Fonts

There is a new wonderful coding font that I discovered recently called the Input (Font for Code). This is a really neat font that works particularly well. You just have to go to their site, define the characteristics you want for it, download and install it locally.

   ;;Use the Input Sans font size 12

   (if (eq system-type 'darwin)
	(set-frame-font "Input Sans Condensed-14")
     (set-frame-font "InputSansCondensed-14")
     )

And the best coloured highlighting of selected text needs to be both bright, but not obscure the white text in the foreground (see list-colors-display). Favorites so far are purple4 and DarkOrange3:

(set-face-background 'region "DarkOrange3")
(use-package dynamic-fonts
  :disabled t
  :ensure t
  :config
  (progn
    (setq dynamic-fonts-preferred-monospace-point-size 10
          dynamic-fonts-preferred-monospace-fonts
          (-union '("Source Code Pro") dynamic-fonts-preferred-monospace-fonts))
    (dynamic-fonts-setup)))

Whitespace

;; Emacs modes typically provide a standard means to change the
;; indentation width -- eg. c-basic-offset: use that to adjust your
;; personal indentation width, while maintaining the style (and
;; meaning) of any files you load.
(setq-default indent-tabs-mode nil)   ;; don't use tabs to indent
(setq-default tab-width 4)            ;; but maintain correct appearance

;; Newline at end of file
(setq require-final-newline t)

;; delete the selection with a keypress
(delete-selection-mode t)

(use-package whitespace
  :bind ("C-c T w" . whitespace-mode)
  :delight " 🗒️"
  :init
   (setq whitespace-line-column nil
          whitespace-display-mappings '((space-mark 32 [183] [46])
                                           (newline-mark 10 [9166 10])
                                           (tab-mark 9 [9654 9] [92 9])))
  ;(dolist (hook '(prog-mode-hook text-mode-hook))
  ;  (add-hook hook #'whitespace-mode))
  (add-hook 'before-save-hook #'whitespace-cleanup)
  :config
  (setq whitespace-line-column 80) ;; limit line length
  (setq whitespace-style '(face tabs empty trailing lines-tail))
  (set-face-attribute 'whitespace-space       nil :foreground "#666666" :background nil)
  (set-face-attribute 'whitespace-newline     nil :foreground "#666666" :background nil)
  (set-face-attribute 'whitespace-indentation nil :foreground "#666666" :background nil)
)

Wordsmithing

options for dealing with text and words.

[[https://forums.gentoo.org/viewtopic-p-8694208.html?sid=c47a21173fe5bee690cfd82cd06bf96b][Gentoo Forums
View topic - emacs rust clippy integration issue [fixed]​]]
(prefer-coding-system 'utf-8)
(set-default-coding-systems 'utf-8)
(set-terminal-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)

;; hippie expand is dabbrev expand on steroids
(setq hippie-expand-try-functions-list '(try-expand-dabbrev
                                         try-expand-dabbrev-all-buffers
                                         try-expand-dabbrev-from-kill
                                         try-complete-file-name-partially
                                         try-complete-file-name
                                         try-expand-all-abbrevs
                                         try-expand-list
                                         try-expand-line
                                         try-complete-lisp-symbol-partially
                                         try-complete-lisp-symbol))

;; use hippie-expand instead of dabbrev
(global-set-key (kbd "M-/") #'hippie-expand)
(global-set-key (kbd "s-/") #'hippie-expand)

  ;; abbrev mode setup
;; (use-package abbrev
;;   :ensure nil
;;   :diminish abbrev-mode
;;   :config
;;   (if (file-exists-p abbrev-file-name)
;;       (quietly-read-abbrev-file)))

;; (use-package flyspell
;;   :config
;;     (when (eq system-type 'windows-nt)
;;       (add-to-list 'exec-path "C:/Program Files (x86)/Aspell/bin/"))
;;     (setq ispell-program-name "aspell" ; use aspell instead of ispell
;;          ispell-extra-args '("--sug-mode=ultra"))
;;     (add-hook 'text-mode-hook #'flyspell-mode)
;;     (add-hook 'prog-mode-hook #'flyspell-prog-mode)
;;   :delight "")

(use-package flycheck
  :ensure t
  :config
  (add-hook 'after-init-hook #'global-flycheck-mode)
  :delight "")

Red Warnings

Various keywords (in comments) are now flagged in a Red Error font:

(use-package hl-todo
  :hook (prog-mode . hl-todo-mode)
  :config
  (setq hl-todo-highlight-punctuation ":"
        hl-todo-keyword-faces
        `(("TODO"       warning bold)
          ("FIXME"      error bold)
          ("HACK"       font-lock-constant-face bold)
          ("REVIEW"     font-lock-keyword-face bold)
          ("NOTE"       success bold)
          ("DEPRECATED" font-lock-doc-face bold))))
(add-hook 'prog-common-hook
          (lambda ()
            (font-lock-add-keywords nil
                                    '(("\\<\\(FIX\\|FIXME\\|TODO\\|BUG\\|HACK\\):"
                                       1 font-lock-warning-face t)))))

Fill Mode

Automatically wrapping when you get to the end of a line (or the fill-region):

(use-package fill
  :bind (("C-c T f" . auto-fill-mode)
         ("C-c T t" . toggle-truncate-lines))
  :init (add-hook 'org-mode-hook 'turn-on-auto-fill)
  :diminish auto-fill-mode)

Global keys

company mode TAB

(global-set-key (kbd "TAB") #'company-indent-or-complete-common)

Which-key

Many command sequences may be logical, but who can remember them all? While I used to use guide-key to display the final function name, it isn’t as nice as which-key.

(use-package which-key
  :ensure t
  :config
(which-key-mode +1))

Files

Use dired Plus dired-x

 ;; (use-package dired
 ;;   :ensure nil
 ;; ;  :defer t
 ;;   :config
 ;;   ;; dired - reuse current buffer by pressing 'a'
 ;;   (progn
 ;;     (put 'dired-find-alternate-file 'disabled nil)

 ;;     ;; always delete and copy recursively
 ;;     (setq dired-recursive-deletes 'always)
 ;;     (setq dired-recursive-copies 'always)

 ;;     ;; if there is a dired buffer displayed in the next window, use its
 ;;     ;; current subdir, instead of the current subdir of this dired buffer
 ;;     (setq dired-dwim-target t)

 ;;     ;; enable some really cool extensions like C-x C-j(dired-jump)
 ;;     (require 'dired-x)
 ;;    )
 ;;   )

 ;; revert buffers automatically when underlying files are changed externally
(global-auto-revert-mode t)

 ;;; Completion, snippets
 (use-package company
   :diminish company-mode
   :ensure t
   :config
   (progn
     (global-company-mode t)
     (bind-key "M-TAB" 'company-select-next company-active-map)
     (setq company-tooltip-align-annotations t
           company-dabbrev-downcase nil
           company-dabbrev-code-everywhere t
           company-dabbrev-ignore-case nil))
    )

save place and recent files

;; Save point position between sessions.
(use-package saveplace
   :ensure nil  ;; as not loading packages
   :config
   (setq save-place-file (expand-file-name "saveplace" gas-savefile-dir))
   ;; activate if for all buffers
   (setq-default save-place t)
 )

(use-package savehist
  :config
  (setq savehist-additional-variables
        ;; search entries
        '(search-ring regexp-search-ring)
        ;; save every minute
        savehist-autosave-interval 60
        ;; keep the home clean
        savehist-file (expand-file-name "savehist" gas-savefile-dir))
  (savehist-mode +1)
 )

(use-package recentf
  :config
  (setq recentf-save-file (expand-file-name "recentf" gas-savefile-dir)
        recentf-max-saved-items 500
        recentf-max-menu-items 15
        ;; disable recentf-cleanup on Emacs start, because it can cause
        ;; problems with remote files aka tramp
        recentf-auto-cleanup 'never)
  (recentf-mode +1)
 )

;; Looks like a big mess, but it works.
(defun recentf-ido-find-file ()
  "Find a recent file using ido."
  (interactive)
  (let ((file (ido-completing-read "Choose recent file: " recentf-list nil t)))
    (when file
      (find-file file))))

  (bind-key "C-x f" 'recentf-ido-find-file )

Git

I like git-gutter-fringe:

(use-package git-gutter-fringe
   :ensure t
   :diminish git-gutter-mode
   :init (setq git-gutter-fr:side 'right-fringe)
   :config (global-git-gutter-mode t))

I want to have special mode for Git’s configuration file:

(use-package gitconfig-mode
  :ensure t)

(use-package gitignore-mode
  :ensure t)

What about being able to see the Git blame in a buffer?

(use-package mo-git-blame
   :ensure t)

Run mo-git-blame-current to see the goodies.

Magit

Git is already part of Emacs. However, Magit is sweet. Don’t believe me? Check out this video.

(use-package magit
  :ensure t
  :requires ido-completing-read+
  :commands magit-status magit-blame
  :defer nil
  :init
  (defadvice magit-status (around magit-fullscreen activate)
    (window-configuration-to-register :magit-fullscreen)
    ad-do-it
    (delete-other-windows))
  :config
  (setq magit-branch-arguments nil
        ;; use ido to look for branches
        magit-completing-read-function 'magit-ido-completing-read
        ;; don't put "origin-" in front of new branch names by default
        magit-default-tracking-name-function 'magit-default-tracking-name-branch-only
        magit-push-always-verify nil
        ;; Get rid of the previous advice to go into fullscreen
        magit-restore-window-configuration t)

  :bind ("C-c m" . magit-status))

I like having Magit to run in a full screen mode, and add the above defadvice idea from Sven Magnars.

Note: Use the smerge-mode that is now part of Emacs.

Projectile

Projectile is a quick and easy project management package that “just works”. We’re going to install it and make sure it’s loaded immediately.

(use-package projectile
  :ensure projectile
;;  :demand t
;;  :bind ("s-p" . projectile-command-map)
  :config
  (progn
    (setq projectile-enable-caching t)
    (setq projectile-require-project-root nil)
    (setq projectile-completion-system 'ivy)
    (add-to-list 'projectile-globally-ignored-files ".DS_Store")
  )
  :defer (projectile-cleanup-known-projects)
  :delight '(:eval (concat "𝓟/" (projectile-project-name)))
)

(use-package ivy
  :ensure t
  :config
    (ivy-mode 1)
    (setq ivy-use-virtual-buffers t)
    (setq enable-recursive-minibuffers t)
    (global-set-key (kbd "C-c C-r") 'ivy-resume)
    (global-set-key (kbd "<f6>") 'ivy-resume)
  :delight )

(use-package swiper
  :disabled t
  :ensure t
  :config
  (global-set-key "\C-s" 'swiper)
)

(use-package counsel
  :ensure t
  :config
  (global-set-key (kbd "M-x") 'counsel-M-x)
  (global-set-key (kbd "C-x C-f") 'counsel-find-file)
  (global-set-key (kbd "<f1> f") 'counsel-describe-function)
  (global-set-key (kbd "<f1> v") 'counsel-describe-variable)
  (global-set-key (kbd "<f1> l") 'counsel-find-library)
  (global-set-key (kbd "<f2> i") 'counsel-info-lookup-symbol)
  (global-set-key (kbd "<f2> u") 'counsel-unicode-char)
  (global-set-key (kbd "C-c g") 'counsel-git)
  (global-set-key (kbd "C-c j") 'counsel-git-grep)
  (global-set-key (kbd "C-c k") 'counsel-ag)
  (global-set-key (kbd "C-x l") 'counsel-locate)
  (define-key minibuffer-local-map (kbd "C-r") 'counsel-minibuffer-history)
)

Ido

(use-package ibuffer
  :bind ("C-x C-b" . ibuffer))

(use-package ibuffer-projectile
  :ensure t
  :config
  (add-hook 'ibuffer-hook #'ibuffer-projectile-set-filter-groups))

(use-package ido
  :ensure t
  :init (ido-mode)
  :config
  (setq ido-enable-flex-matching t
        ido-completion-buffer nil
        ido-use-faces nil))

;; (use-package flx-ido
;;   :ensure t
;;   :init (flx-ido-mode))

(use-package ido-vertical-mode
  :ensure t
  :init (ido-vertical-mode))

Undo

(use-package undo-tree
  :diminish undo-tree-mode
  :ensure t)

;; Add parts of each file's directory to the buffer name if not unique
   (setq uniquify-buffer-name-style 'forward)
   (setq uniquify-separator "/")
   (setq uniquify-after-kill-buffer-p t)
   (setq uniquify-ignore-buffers-re "^\\*")

Org

(use-package org
  :straight (:type built-in)
  :delight org-mode ""
  :config
  (defun jmn/url-get-title (url &optional descr)
    "Takes a URL and returns the value of the <title> HTML tag,
     Thanks to https://frozenlock.org/tag/url-retrieve/ for documenting url-retrieve"
    (let (
          (buffer (url-retrieve-synchronously url))
          (title nil))
      (save-excursion
        (set-buffer buffer)
        (goto-char (point-min))
        (search-forward-regexp "<title>\\([^<]+?\\)</title>")
        (setq title (match-string 1 ) )
        (kill-buffer (current-buffer)))
      title))

  (setq org-make-link-description-function 'jmn/url-get-title)
  )

MacOS

MacOS Customisations

;; Are we on a mac?
(setq is-mac (equal system-type 'darwin))

(when (display-graphic-p)
  (if is-mac
  (menu-bar-mode 1)))

;; Make Meta command and add Hyper.
(when is-mac
 (setq mac-option-modifier nil
     mac-command-modifier 'meta
  x-select-enable-clipboard t)

  ;; Change command to meta.
;;  (setq mac-command-modifier 'super)
;;  (setq mac-option-modifier 'meta)
  ;; not sure what hyper is (setq ns-function-modifier 'hyper)

  ;; Use right option for special characters.
;;  (setq mac-right-option-modifier 'none)

  ;; Remove date and battery status from modeline
  (display-time-mode -1)
  (display-battery-mode -1)


  )

Toc-org

Let’s install and load the toc-org package after org mode is loaded. This is the package that automatically generates an up to date table of contents for us.

(use-package toc-org
  :after org
  :init (add-hook 'org-mode-hook #'toc-org-enable))

Programming

Eldoc

(use-package eldoc
  :defer     t
  :diminish  eldoc-mode)

Prettify code

   ;; ----- Base set of pretty symbols.
   (defvar base-prettify-symbols-alist '(("<=" . ?≤)
                                      (">=" . ?≥)
                                      ("<-" . ?←)
                                      ("->" . ?→)
                                      ("<=" . ?⇐)
                                      ("=>" . ?⇒)
                                      ("lambda" .  ))
   )

   (defun gas-lisp-prettify-symbols-hook ()
    "Set pretty symbols for lisp modes."
     (setq prettify-symbols-alist base-prettify-symbols-alist))

   (defun gas-js-prettify-symbols-hook ()
     "Set pretty symbols for JavaScript."
     (setq prettify-symbols-alist
        (append '(("function" . )) base-prettify-symbols-alist)))

   (defun gas-clj-prettify-symbols-hook ()
     "Set pretty symbols for Clojure(script)."
     (setq prettify-symbols-alist
        (append '(("fn" . λ)) base-prettify-symbols-alist)))

   (defun other-prettify-symbols-hook ()
     "Set pretty symbols for non-lisp programming modes."
     (setq prettify-symbols-alist
        (append '(("==" . ?≡)
                           ("!=" . ?≠))
             base-prettify-symbols-alist)))

;; Hook 'em up.
(add-hook 'emacs-lisp-mode-hook #'gas-lisp-prettify-symbols-hook)
(add-hook 'web-mode-hook        #'other-prettify-symbols-hook)
(add-hook 'js-mode-hook         #'gas-js-prettify-symbols-hook)
(add-hook 'prog-mode-hook       #'other-prettify-symbols-hook)
(add-hook 'clojure-mode-hook    #'gas-clj-prettify-symbols-hook)

(global-prettify-symbols-mode 1)

Elisp

  (add-hook 'emacs-lisp-mode-hook #'eldoc-mode)
  (add-hook 'emacs-lisp-mode-hook #'rainbow-delimiters-mode)
  (define-key emacs-lisp-mode-map (kbd "C-c C-c") #'eval-defun)
  (define-key emacs-lisp-mode-map (kbd "C-c C-b") #'eval-buffer)
  (add-hook 'lisp-interaction-mode-hook #'eldoc-mode)
  (add-hook 'eval-expression-minibuffer-setup-hook #'eldoc-mode)

(use-package ielm
  :config
  (add-hook 'ielm-mode-hook #'eldoc-mode)
  (add-hook 'ielm-mode-hook #'rainbow-delimiters-mode))

Clojure

lets try out aggressive-indent

(use-package aggressive-indent
 :ensure t)

The clojure-mode project seems to be the best (and works well with Cider).

   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   ;; inferior lisp
   (setq inferior-lisp-program "lein figwheel")

   ;; inf-clojure test
   (use-package inf-clojure
     :ensure t
     )

   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   ;; inf-clojure

   (setq inf-clojure-lein-cmd "lein figwheel")
   ;; minor-mode adds key-bindings
   ;(add-hook 'clojure-mode-hook 'inf-clojure-minor-mode)

   (use-package clojure-mode
      :ensure t
      :mode ("\\.\\(clj\\|cljs\\|edn\\|boot\\)$" . clojure-mode )
      :config
       (progn
         (setq clojure-align-forms-automatically t)
         (add-hook 'clojure-mode-hook #'company-mode)
         (add-hook 'clojure-mode-hook #'linum-mode)
         (add-hook 'clojure-mode-hook #'subword-mode)
         ;;(add-hook 'clojure-mode-hook #'paredit-mode)
         (add-hook 'clojure-mode-hook #'smartparens-strict-mode)
         (add-hook 'clojure-mode-hook #'rainbow-delimiters-mode)
         (add-hook 'clojure-mode-hook #'eldoc-mode))
       ;;  (add-hook 'clojure-mode-hook #'idle-highlight-mode)
      ;; :bind (("C-c d f" . cider-code))
       :delight "clj"
)

Parens

(use-package paren
  :ensure nil
  :config
  (show-paren-mode +1))

Use paredit

(use-package paredit
 :disabled t
:delight ""
:ensure t
:config
(add-hook 'emacs-lisp-mode-hook #'paredit-mode)
 ;; enable in the *scratch* buffer
 (add-hook 'lisp-interaction-mode-hook #'paredit-mode)
 (add-hook 'ielm-mode-hook #'paredit-mode)
 (add-hook 'lisp-mode-hook #'paredit-mode)
 (add-hook 'clojure-mode-hook #'paredit-mode)
 (add-hook 'eval-expression-minibuffer-setup-hook #'paredit-mode))

Use smartparens

(use-package smartparens
:ensure    smartparens
:init      (progn
             (require 'smartparens)
             (load-library "smartparens-config"))

:config   (progn
            (smartparens-global-mode t)
            (sp-local-pair 'emacs-lisp-mode "`" nil :when '(sp-in-string-p))
            (sp-with-modes '(html-mode sgml-mode nxml-mode web-mode)
              (sp-local-pair "<" ">"))
:delight ""))

use rainbow delimiters

(use-package rainbow-delimiters
  :ensure t)

;; Don't show anything for rainbow-mode.
(use-package rainbow-mode
  :delight)

Cider

da-bomb!

(use-package cider
  :defer t
  :ensure t
  ;;  :commands (cider cider-connect cider-jack-in)
  :init
  (setq cider-auto-select-error-buffer t
        ;; go right to the REPL buffer when it's finished connecting
        cider-repl-pop-to-buffer-on-connect 'display-only
        cider-repl-use-clojure-font-lock t
        ;; Wrap when navigating history.
        cider-repl-wrap-history t
        cider-repl-history-size 1000
        ;; When there's a cider error, show its buffer and switch to it
        cider-show-error-buffer t
        cider-auto-select-error-buffer t
        nrepl-hide-special-buffers t
        ;; Stop error buffer from popping up while working in buffers other than the REPL:
        nrepl-popup-stacktraces nil
        ;; Where to store the cider history.
        cider-repl-history-file "~/.emacs.d/cider-history"
        )

  :config
  (progn ;; (defalias 'cji 'cider-jack-in)
    (add-hook 'cider-mode-hook #'eldoc-mode)
    (add-hook 'cider-repl-mode-hook #'eldoc-mode)
    ;;  (add-hook 'cider-repl-mode-hook #'smartparens-strict-mode)
    (add-hook 'cider-repl-mode-hook #'company-mode)
    (add-hook 'cider-mode-hook #'company-mode)
    (add-hook 'cider-repl-mode-hook #'cider-company-enable-fuzzy-completion)
    (add-hook 'cider-mode-hook #'cider-company-enable-fuzzy-completion)
    ;; (add-hook 'cider-repl-mode-hook #'paredit-mode)
    (add-hook 'cider-repl-mode-hook #'rainbow-delimiters-mode)
    )
  :diminish  (cider-mode . "")
  )

(setq cider-cljs-lein-repl
      "(cond
   (and (resolve 'user/run) (resolve 'user/browser-repl)) ;; Chestnut projects
   (eval '(do (user/run)
             (user/browser-repl)))

   (try
    (require 'figwheel-sidecar.repl-api)
    (resolve 'figwheel-sidecar.repl-api/start-figwheel!)
    (catch Throwable _))
   (eval '(do (figwheel-sidecar.repl-api/start-figwheel!)
             (figwheel-sidecar.repl-api/cljs-repl)))

   (try
    (require 'cemerick.piggieback)
    (resolve 'cemerick.piggieback/cljs-repl)
    (catch Throwable _))
   (eval '(cemerick.piggieback/cljs-repl (cljs.repl.rhino/repl-env)))

   :else
   (throw (ex-info \"Failed to initialise CLJS repl. Add com.cemerick/piggieback
       and optionally figwheel-sidecar to your project.\" {})))")

Rust

~~I currently am prefering to use Rustic together with eglot because I sometimes use standalone rust files which aren’t yet supported by lsp-mode. But they are supported experimentally (customize rustic-enable-detached-file-support) in Rustic with eglot. ~~ I wish there was standalone file support in lsp-mode.

(use-package rustic)
(use-package cargo
  :straight (:host github :repo "jmn/cargo.el"
         :branch "master"))

Javascript

JavaScript should have three parts:

  • Syntax highlight (already included)
  • Syntax verification (with flycheck)
  • Interactive REPL … using Skewer

LSP - Language Server Protocol

(use-package lsp-mode
    :init
    ;; set prefix for lsp-command-keymap (few alternatives - "C-l", "C-c l")
    (setq lsp-keymap-prefix "C-c l")
    :defer nil
    :demand t
    :hook (
           (js-mode . lsp)
           (rust-mode . lsp)
           (lsp-mode . lsp-enable-which-key-integration)

           ;; FIXME: This requires me to open rustic twice to have clippy interation.
           (rustic-mode . (lambda ()
                            (lsp-deferred)
                            (flycheck-add-next-checker 'lsp 'rustic-clippy)))
           )
    :commands lsp)

(use-package lsp-ui :commands lsp-ui-mode)

JS Mode

(use-package typescript-mode)
(add-to-list 'auto-mode-alist '("\\.ts\\'" . js-jsx-mode))
(add-to-list 'auto-mode-alist '("\\.tsx\\'" . js-jsx-mode))

Colour defined variables with color-identifiers-mode:

(use-package color-identifiers-mode
    :ensure t
    :init
      (add-hook 'js-mode-hook 'color-identifiers-mode))

Flycheck and JSHint

While editing JavaScript is baked into Emacs, it is quite important to have flycheck validate the source based on jshint, and eslint. Let’s prefer eslint:

(add-hook 'js2-mode-hook
          (lambda () (flycheck-select-checker "javascript-eslint")))

Now load and edit a JavaScript file, like jshint-code-test.js.

Refactoring JavaScript

The js2-refactor mode should start with C-c . and then a two-letter mnemonic shortcut.

  • ef is extract-function: Extracts the marked expressions out into a new named function.
  • em is extract-method: Extracts the marked expressions out into a new named method in an object literal.
  • ip is introduce-parameter: Changes the marked expression to a parameter in a local function.
  • lp is localize-parameter: Changes a parameter to a local var in a local function.
  • eo is expand-object: Converts a one line object literal to multiline.
  • co is contract-object: Converts a multiline object literal to one line.
  • eu is expand-function: Converts a one line function to multiline (expecting semicolons as statement delimiters).
  • cu is contract-function: Converts a multiline function to one line (expecting semicolons as statement delimiters).
  • ea is expand-array: Converts a one line array to multiline.
  • ca is contract-array: Converts a multiline array to one line.
  • wi is wrap-buffer-in-iife: Wraps the entire buffer in an immediately invoked function expression
  • ig is inject-global-in-iife: Creates a shortcut for a marked global by injecting it in the wrapping immediately invoked function expression
  • ag is add-to-globals-annotation: Creates a /*global */ annotation if it is missing, and adds the var at point to it.
  • ev is extract-var: Takes a marked expression and replaces it with a var.
  • iv is inline-var: Replaces all instances of a variable with its initial value.
  • rv is rename-var: Renames the variable on point and all occurrences in its lexical scope.
  • vt is var-to-this: Changes local var a to be this.a instead.
  • ao is arguments-to-object: Replaces arguments to a function call with an object literal of named arguments. Requires yasnippets.
  • 3i is ternary-to-if: Converts ternary operator to if-statement.
  • sv is split-var-declaration: Splits a var with multiple vars declared, into several var statements.
  • uw is unwrap: Replaces the parent statement with the selected region.
(use-package js2-refactor
  :ensure t
  :init   (add-hook 'js2-mode-hook 'js2-refactor-mode)
  :config (js2r-add-keybindings-with-prefix "C-c ."))

Skewer

I also configure Skewer for my HTML and CSS files, we need to do the same for JavaScript:

(use-package skewer-mode
   :ensure t
   :init (add-hook 'js2-mode-hook 'skewer-mode))

Kick things off with run-skewer, and then:

C-x C-e
`skewer-eval-last-expression’
C-M-x
`skewer-eval-defun’
C-c C-k
`skewer-load-buffer’

JSON mode

(use-package json-mode
  :ensure    json-mode
  :config    (bind-keys :map json-mode-map
                        ("C-c i" . json-mode-beautify))
  :mode      ("\\.\\(json\\)$" . json-mode))

YAML

(use-package yaml-mode
  :mode ("\\.\\(yml\\|yaml\\|\\config\\|sls\\)$" . yaml-mode)
  :ensure yaml-mode
  :defer t)

C

(use-package cc-mode
 :config
 (progn
   (add-hook 'c-mode-hook (lambda () (c-set-style "bsd")))
   (add-hook 'java-mode-hook (lambda () (c-set-style "bsd")))
   (setq tab-width 2)
   (setq c-basic-offset 2)))

CSS

(use-package css-mode
  :config (setq css-indent-offset 2)
)

Terraform

pretty terraform highlighting

;;(use-package terraform-mode
;;    :defer t
;;    :init
;;     (progn
;;       (require 'company-terraform)
;;       (company-terraform-init)
;;      )
;;    :config (setq terraform-indent-level 2)
;;    )

Post Initialisation

Let’s lower our GC thresholds back down to a sane level.

(setq gc-cons-threshold 16777216
      gc-cons-percentage 0.1)

About

Literate emacs config file


Languages

Language:Emacs Lisp 88.2%Language:Makefile 11.8%