Miscellaneous Programming stuff

This file holds some miscellaneous configuration for various progamming and text environments

Indent guides

Sometimes I want to visualize indentation. The MELPA package highlight-indent-guides seems to work quite nice for this.

I am currently using the character for this, but there are a few other options here:

  • ¦
(use-package highlight-indent-guides
  :ensure t
  :config
  (setq highlight-indent-guides-method 'character)
  (setq highlight-indent-guides-character ?│)
  (setq highlight-indent-guides-auto-enabled nil)
  ;; use M-x indent-guides RET to toggle
  (defalias 'indent-guides 'highlight-indent-guides-mode)
  <<do.misc.indent-guides/color>>)

Based on the selected theme, we modify the color of the indent guides a little.

(cond
 ((eq do.theme/enabled-theme 'dark)
  (set-face-foreground 'highlight-indent-guides-character-face "#2d2d2d"))
 ((eq do.theme/enabled-theme 'light)
  (plan9/with-color-variables (set-face-foreground 'highlight-indent-guides-character-face blue-light))))

Markdown

Org > Markdown, but I do sometimes use it…

(use-package markdown-mode
  :ensure t
  :commands
  (markdown-mode gfm-mode)
  :bind (:map markdown-mode-map ("C-<tab>" . yas-expand))
  :mode
  (("README\\.md\\'" . gfm-mode)
   ("\\.md\\'" . markdown-mode)
   ("\\.text\\'" . markdown-mode)
   ("\\.markdown\\'" . markdown-mode))
  :init
  (setq markdown-command "markdown")
  :config
  (add-hook 'markdown-mode-hook (lambda () (auto-fill-mode t)))
  (add-hook 'markdown-mode-hook 'flyspell-mode))

HTML

When editing HTML, I want to have the proper syntax highligting according to what kind of block I'm in. web-mode does this.

(use-package web-mode
  :ensure t
  :mode
  (("\\.html?\\'" . web-mode)
   ("\\.htm?\\'" . web-mode))
  :config
  (defun do.misc.web-mode/hooks ()
    "Hooks for Web mode."
    (setq web-mode-markup-indent-offset 2)
    (setq web-mode-css-indent-offset 2)
    (setq-local electric-pair-inhibit-predicate
                (lambda (c)
                  (if (char-equal c ?{) t (electric-pair-default-inhibit c)))))
  (add-hook 'web-mode-hook  #'do.misc.web-mode/hooks))

TODO Javascript (not using right now)

Activate js2-mode instead of standard js-mode.

(use-package ac-js2 :ensure t)

(use-package js2-mode
  :ensure t
  :pin "melpa"
  :mode (("\\.js\\'" . js2-mode))
  :interpreter (("node" . js2-mode))
  :config
  (add-hook 'js2-mode-hook 'ac-js2-mode)
  (setq
   js2-basic-offset 2
   js2-highlight-level 3)
  (defalias 'run-node 'nodejs-repl))

Hy

Hy is lisp running in the Python interpreter! That means all of the power of matplotlib, numpy, and scipy with the power of lisp!

(use-package hy-mode
  :ensure t
  :config
  (add-hook 'hy-mode-hook #'paredit-mode)
  (add-hook 'hy-mode-hook #'rainbow-delimiters-mode))

TODO Clojure (not using right now)

clojure-mode for editing

(use-package clojure-mode
  :ensure t
  :config
  (add-hook 'clojure-mode-hook #'rainbow-delimiters-mode)
  (add-hook 'clojure-mode-hook #'paredit-mode))

(use-package clojure-mode-extra-font-locking
  :ensure t
  :after clojure-mode)

CIDER for interaction

(use-package cider
  :ensure t
  :config
  (add-hook 'cider-repl-mode-hook '(lambda () (setq-local ml-interactive? t)))
  (add-hook 'cider-repl-mode-hook #'no-trailing-whitespace)
  (add-hook 'cider-repl-mode-hook #'rainbow-delimiters-mode)
  (add-hook 'cider-repl-mode-hook #'paredit-mode))

Common Lisp

LISP REPL choice

Default to ECL.

(cond
 ((executable-find "ecl") (setq inferior-lisp-program "ecl"))
 ((executable-find "sbcl") (setq inferior-lisp-program "sbcl"))
 ((executable-find "clisp") (setq inferior-lisp-program "clisp")))

LISP REPL hooks

(defun do.misc.lisp/repl-hooks ()
  (setq global-hl-line-mode nil)
  (setq-local ml-interactive? t) ;; for mode line
  (setq show-trailing-whitespace nil))
(add-hook 'inferior-lisp-mode-hook 'do.misc.lisp/repl-hooks)
(add-hook 'ielm-mode-hook 'do.misc.lisp/repl-hooks)

SLIME

(use-package slime
  :ensure slime-company
  :commands slime
  :config
  (slime-setup '(slime-fancy slime-company))
  (add-hook 'slime-repl-mode-hook 'do.misc.lisp/repl-hooks))

Rust

Some code for rust development

(use-package rust-mode
  :ensure t
  :mode "\\.rs\\'"
  :init
  (setq lsp-rust-server 'rust-analyzer)
  :hook
  (rust-mode . lsp)
  :config
  (setq rust-format-on-save t)
  :bind (:map rust-mode-map
         ("C-c r" . rust-run)
         ("C-c c" . rust-compile)
         ("C-c t" . rust-test)))

Rainbow-mode

Rainbow-mode can be quite useful sometimes.

(use-package rainbow-mode
  :ensure t)

Protobuf mode

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

Dockerfile mode

(use-package dockerfile-mode
  :ensure t
  :mode "Dockerfile\\(?:\\..*\\)?\\'")

PKGBUILD mode

(use-package pkgbuild-mode
  :ensure t
  :mode "PKGBUILD")

YAML

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

Lua

(use-package lua-mode
  :defer t
  :ensure t
  :mode ("\\.lua$" . lua-mode))

Go

(use-package go-mode
  :ensure t
  :mode ("\\.go\\'" . go-mode)
  :init
  (defun do.misc.go/mode-hook ()
    "Locally change some prog-mode settings for Go."
    ;; compilation
    (setq-local compile-command
                (concat "echo \"\\n;; BUILD\" && "
                        "go build -v && "
                        "echo \"\\n;; TEST\" && "
                        "go test -v && "
                        "echo \"\\n;; LINT\" && "
                        "golint"))
    (setq-local compilation-read-command nil)
    (setq-local compilation-scroll-output t)
    ;; LSP settings
    (setq-local lsp-gopls-staticcheck t)
    (setq-local lsp-eldoc-render-all t)
    (setq-local lsp-gopls-complete-unimported t)
    ;; format before saving
    (make-variable-buffer-local 'before-save-hook)
    (add-hook 'before-save-hook #'lsp-format-buffer)
    (add-hook 'before-save-hook #'lsp-organize-imports)
    ;; finally, start LSP.
    (lsp-deferred))
  (add-hook 'go-mode-hook #'do.misc.go/mode-hook)
  :bind ; some keybindings for easy compilation
  (:map go-mode-map
        ("C-c C-C" . compile)
        ("M-." . godef-jump)))

PowerShell

(use-package powershell
  :ensure t)

Scala

I use Scala mainly for writing/learning Chisel.

(use-package scala-mode
  :ensure t
  :interpreter ("scala" . scala-mode)
  :bind (:map scala-mode-map
         ("C-c c" . sbt-do-compile)
         ("C-c t" . sbt-do-test)
         ("C-c r" . sbt-do-run)))

(use-package lsp-metals
  :ensure t
  :hook (scala-mode . lsp))

(use-package sbt-mode
  :ensure t
  :commands sbt-start sbt-command
  :config
  ;; WORKAROUND: https://github.com/ensime/emacs-sbt-mode/issues/31
  ;; allows using SPACE when in the minibuffer
  (substitute-key-definition
   'minibuffer-complete-word
   'self-insert-command
   minibuffer-local-completion-map)
  ;; sbt-supershell kills sbt-mode:  https://github.com/hvesalai/emacs-sbt-mode/issues/152
  (setq sbt:program-options '("-Dsbt.supershell=false"))
  :hook ((scala-mode . sbt-start)
         (sbt-mode . (lambda () (setq-local ml-interactive? t) (no-trailing-whitespace)))))

Unfill paragraph

(defun unfill-paragraph ()
  (interactive)
  (let ((fill-column (point-max)))
    (fill-paragraph nil)))

(defun unfill-region ()
  (interactive)
  (let ((fill-column (point-max)))
    (fill-region (region-beginning) (region-end) nil)))

Quick Access Menu

This code uses org-mks to create a "Quick Access" menu bound to C-c q, which I can pop up from anywhere in Emacs and access some commonly-used stuff.

(require 'org-macs)

(defvar do.misc/quick-access-menu-table nil
  "A list of (key description callable) tuples that make up my quick access menu.

This is implemented using `org-mks'. This is meant to be a quick
customizable menu that I pop up as part of my global config.")

(defun do.misc/format-quick-access-menu-table (table)
  "Loop through `do.misc/quick-access-menu-alist', if we
  encounter the symbol SEPARATOR, modify the previous entry to
  add a good-looking separator."
  (let ((out))
    (dolist (elem table)
      (when (listp elem)
        (push elem out))
      (when (and (symbolp elem) (eq elem 'separator))
        (let* ((prev (pop out)))
          (push (list (nth 0 prev) (concat (nth 1 prev) "\n\n============\n") (nth 2 prev)) out))))
    (nreverse out)))

(defun do.misc/quick-access-menu ()
  "Pop up the quick access menu."
  (interactive)
  (let ((selection (org-mks (do.misc/format-quick-access-menu-table do.misc/quick-access-menu-table)
                            "Quick Access\n============"
                            "Selection: ")))
    (when selection
      (funcall (indirect-function (nth 2 selection))))))

(global-set-key (kbd "C-c q") #'do.misc/quick-access-menu)

colorize compilation buffer

From here.

(use-package ansi-color
  :config
  (defun do.minimal/colorize-compilation-buffer ()
    (when (eq major-mode 'compilation-mode)
      ;; this seemingly breaks in emacas 28
      ;; (ansi-color-apply-on-region compilation-filter-start (point-max))
      ;; this helps (not a thorough) investigation
      (ansi-color-apply-on-region (point-min-marker) (point-max-marker))))
  :hook (compilation-filter . do.minimal/colorize-compilation-buffer))