23 KiB
Programming language configuration
Makefile
Defines an auto-insert for Makefiles. Assumes C but it's very easy to change it for C++.
(use-package emacs
:auto-insert
(("[mM]akefile\\'" . "Makefile skeleton")
""
"CC=gcc
CFLAGS=-Wall -Wextra -Werror -Wswitch-enum -ggdb -fsanitize=address -std=c11
LIBS=
ARGS=
OUT=main.out
SRC=src
DIST=build
CODE=$(addprefix $(SRC)/, ) # add source files here
OBJECTS=$(CODE:$(SRC)/%.c=$(DIST)/%.o)
DEPDIR:=$(DIST)/dependencies
DEPFLAGS=-MT $@ -MMD -MP -MF
DEPS:=$(CODE:$(SRC)/%.c=$(DEPDIR):%.d) $(DEPDIR)/main.d
.PHONY: all
all: $(OUT)
$(OUT): $(DIST)/$(OUT)
$(DIST)/$(OUT): $(OBJECTS) $(DIST)/main.o | $(DIST)
$(CC) $(CFLAGS) $^ -o $@ $(LIBS)
$(DIST)/%.o: $(SRC)/%.c | $(DIST) $(DEPDIR)
$(CC) $(CFLAGS) $(DEPFLAGS) $(DEPDIR)/$*.d -c $< -o $@ $(LIBS)
.PHONY: run
run: $(DIST)/$(OUT)
./$^ $(ARGS)
.PHONY:
clean:
rm -rfv $(DIST)/*
$(DIST):
mkdir -p $(DIST)
$(DEPDIR):
mkdir -p $(DEPDIR)
-include $(DEPS)
"
_))
I use PDFs mostly for reading reports or papers. Though Emacs isn't my preferred application for viewing PDFs (I highly recommend Zathura), similar to most things with Emacs, having a PDF viewer builtin can be a very useful asset.
For example if I were editing an org document which I was eventually compiling into a PDF, my workflow would be much smoother with a PDF viewer within Emacs that I can open on another pane.
WAIT PDF tools
pdf-tools provides the necessary functionality for viewing PDFs.
There is no proper PDF viewing without this package.
evil-collection provides a setup for this mode, so use that.
(use-package pdf-tools
:mode ("\\.[pP][dD][fF]\\'" . pdf-view-mode)
:straight t
:display
("^.*pdf$"
(display-buffer-same-window)
(inhibit-duplicate-buffer . t))
:config
(pdf-tools-install-noverify)
(with-eval-after-load "evil-collection"
(evil-collection-pdf-setup)))
PDF grep
PDF grep is a Linux tool that allows for searches against the text inside of PDFs similar to standard grep. This cannot be performed by standard grep due to how PDFs are encoded; they are not a clear text format.
(use-package pdfgrep
:after pdf-tools
:hook (pdf-view-mode-hook . pdfgrep-mode)
:general
(nmap
:keymaps 'pdf-view-mode-map
"M-g" #'pdfgrep))
WAIT SQL
The default SQL package provides support for connecting to common database types (sqlite, mysql, etc) for auto completion and query execution. I don't use SQL currently but whenever I need it it's there.
(use-package sql
:defer t
:straight nil
:init
(setq sql-display-sqli-buffer-function nil))
WAIT Ada
Check out ada-mode, my custom ada-mode
that replaces the default one. This mode just colourises stuff, and
uses eglot and a language server to do the hard work.
(use-package ada-mode
:straight nil
:load-path "elisp/"
:defer t
:config
(with-eval-after-load "eglot"
(add-hook 'ada-mode-hook #'eglot)))
NHexl
Hexl-mode is the inbuilt package within Emacs to edit hex and binary format buffers. There are a few problems with hexl-mode though, including an annoying prompt on revert-buffer.
Thus, nhexl-mode! It comes with a few other improvements. Check out the page yourself.
(use-package nhexl-mode
:straight t
:mode ("\\.bin" "\\.out"))
C/C++
Setup for C and C++ modes, using Emacs' default package: cc-mode.
cc-mode
Tons of stuff, namely:
auto-fill-modefor 80 char limit- Some keybindings to make evil statement movement is easy
- Lots of pretty symbols
- Indenting options and a nice (for me) code style for C (though aggressive indent screws with this a bit)
- Auto inserts to get a C file going
(use-package cc-mode
:defer t
:hook
(c-mode-hook . auto-fill-mode)
(c++-mode-hook . auto-fill-mode)
:general
(:keymaps '(c-mode-map c++-mode-map)
:states '(normal motion visual)
"(" #'c-beginning-of-statement
")" #'c-end-of-statement)
:pretty
(c-mode-hook
("puts" . "φ")
("fputs" . "ϕ")
("printf" . "ω")
("fprintf" . "Ω")
("NULL" . "Ø")
("true" . "⊨")
("false" . "⊭")
("!" . "¬")
("&&" . "∧")
("||" . "∨")
("for" . "∀")
("return" . "⟼"))
(c++-mode-hook
("nullptr" . "Ø")
("string" . "𝕊")
("vector" . "ℓ")
("puts" . "φ")
("fputs" . "ϕ")
("printf" . "ω")
("fprintf" . "Ω")
("NULL" . "Ø")
("true" . "⊨")
("false" . "⊭")
("!" . "¬")
("&&" . "∧")
("||" . "∨")
("for" . "∀")
("return" . "⟼"))
:init
(setq-default c-basic-offset 2)
(setq-default c-auto-newline nil)
(setq-default c-default-style '((other . "user")))
(defun +cc/copyright-notice ()
(let* ((lines (split-string (+license/copyright-notice) "\n"))
(copyright-line (car lines))
(rest (cdr lines)))
(concat
"* "
copyright-line
"\n"
(mapconcat
#'(lambda (x)
(if (string= x "")
""
(concat " * " x)))
rest
"\n"))))
:auto-insert
(("\\.c\\'" . "C skeleton")
""
"/" (+cc/copyright-notice) "\n\n"
" * Created: " (format-time-string "%Y-%m-%d") "\n"
" * Author: " user-full-name "\n"
" * Description: " _ "\n"
" */\n"
"\n")
(("\\.cpp\\'" "C++ skeleton")
""
"/" (+cc/copyright-notice) "\n\n"
" * Created: " (format-time-string "%Y-%m-%d") "\n"
" * Author: " user-full-name "\n"
" * Description: " _ "\n"
" */\n"
"\n")
(("\\.\\([Hh]\\|hh\\|hpp\\|hxx\\|h\\+\\+\\)\\'" . "C / C++ header")
(replace-regexp-in-string "[^A-Z0-9]" "_"
(string-replace "+" "P"
(upcase
(file-name-nondirectory buffer-file-name))))
"/" (+cc/copyright-notice) "\n\n"
" * Created: " (format-time-string "%Y-%m-%d") "\n"
" * Author: " user-full-name "\n"
" * Description: " _ "\n"
" */\n\n"
"#ifndef " str n "#define " str "\n\n" "\n\n#endif")
:config
(c-add-style
"user"
'((c-basic-offset . 2)
(c-comment-only-line-offset . 0)
(c-hanging-braces-alist (brace-list-open)
(brace-entry-open)
(substatement-open after)
(block-close . c-snug-do-while)
(arglist-cont-nonempty))
(c-cleanup-list brace-else-brace)
(c-offsets-alist
(statement-block-intro . +)
(substatement-open . 0)
(access-label . -)
(inline-open . 0)
(label . 0)
(statement-cont . +)))))
Clang format
Clang format comes inbuilt with clang, so download that before using this. Formats C/C++ files depending on a format (checkout the Clang format config file in my dotfiles).
(use-package clang-format
:straight nil
:load-path "/usr/share/clang/"
:after cc-mode
:commands (+code/clang-format-region-or-buffer
clang-format-mode)
;;; 2024-04-24: disabled as it's annoying on projects where a
;;; .clang-format isn't defined. Furthermore, does it make sense
;;; for *every* file you open and edit to have a format function run
;;; right after? seems a bit slow.
;; :hook
;; (c-mode-hook . clang-format-mode)
;; (c++-mode-hook . clang-format-mode)
:general
(code-leader
:keymaps '(c-mode-map c++-mode-map)
"f" #'+code/clang-format-region-or-buffer)
:config
(define-minor-mode clang-format-mode
"On save formats the current buffer via clang-format."
:lighter nil
(let ((save-func (proc (interactive)
(clang-format-buffer))))
(if clang-format-mode
(add-hook 'after-save-hook save-func nil t)
(remove-hook 'after-save-hook save-func t))))
(defun +code/clang-format-region-or-buffer ()
(interactive)
(if (mark)
(clang-format-region (region-beginning) (region-end))
(clang-format-buffer))))
cc org babel
To ensure org-babel executes language blocks of C/C++, I need to load
it as an option in org-babel-load-languages.
(use-package org
:after cc-mode
:init
(org-babel-do-load-languages
'org-babel-load-languages
'((C . t))))
WAIT D
D is a systems level programming language with C-style syntax. I
think it has some interesting ideas such as a toggleable garbage
collector. Here I just install the D-mode package, enable org-babel
execution of d-mode blocks and alias D-mode with d-mode.
(use-package d-mode
:defer t
:straight t
:config
(fset 'D-mode 'd-mode)
(with-eval-after-load "org-mode"
(setf (alist-get 'd org-babel-load-languages) t)))
Rust
(use-package rust-mode
:straight t
:general
(code-leader
:keymaps 'rust-mode-map
"f" #'rust-format-buffer)
(local-leader
:keymaps 'rust-mode-map
"c" #'rust-run-clippy)
:init
(setq rust-format-on-save t)
(with-eval-after-load "eglot"
(add-to-list 'eglot-server-programs '(rust-mode "rust-analyzer"))))
WAIT Racket
A scheme with lots of stuff inside it. Using it for a language design book so it's useful to have some Emacs binds for it.
(use-package racket-mode
:straight t
:hook (racket-mode-hook . racket-xp-mode)
:display
("\\*Racket.*"
(display-buffer-at-bottom)
(window-height . 0.25))
:init
(setq racket-documentation-search-location 'local)
:general
(nmap
:keymaps 'racket-describe-mode-map
"q" #'quit-window)
(nmap
:keymaps 'racket-mode-map
"gr" #'racket-eval-last-sexp)
(local-leader
:keymaps '(racket-mode-map racket-repl-mode-map)
"d" #'racket-repl-describe)
(local-leader
:keymaps 'racket-mode-map
"r" #'racket-run
"i" #'racket-repl
"e" #'racket-send-definition
"sr" #'racket-send-region
"sd" #'racket-send-definition))
WAIT CSharp
Haven't used C# in a while, but Emacs is alright for it with omnisharp.
(use-package csharp-mode
:defer t
:pretty
(csharp-mode-hook
("null" . "∅")
("string" . "𝕊")
("List" . "ℓ")
("WriteLine" . "φ")
("Write" . "ω")
("true" . "⊨")
("false" . "⊭")
("!" . "¬")
("&&" . "∧")
("||" . "∨")
("for" . "∀")
("return" . "⟼")))
Java
I kinda dislike Java, but if necessary I will code in it. Just setup a style and some pretty symbols. You can use LSP to get cooler features to be fair.
(use-package ob-java
:straight nil
:defer t
:pretty
(java-mode-hook
("println" . "φ")
("printf" . "ω")
("null" . "Ø")
("true" . "⊨")
("false" . "⊭")
("!" . "¬")
("&&" . "∧")
("||" . "∨")
("for" . "∀")
("return" . "⟼"))
:config
(with-eval-after-load "cc-mode"
(c-add-style
"java"
'((c-basic-offset . 4)
(c-comment-only-line-offset 0 . 0)
(c-offsets-alist
(inline-open . 0)
(topmost-intro-cont . +)
(statement-block-intro . +)
(knr-argdecl-intro . 5)
(substatement-open . 0)
(substatement-label . +)
(label . +)
(statement-case-open . +)
(statement-cont . +)
(arglist-intro . c-lineup-arglist-intro-after-paren)
(arglist-close . c-lineup-arglist)
(brace-list-intro first c-lineup-2nd-brace-entry-in-arglist c-lineup-class-decl-init-+ +)
(access-label . 0)
(inher-cont . c-lineup-java-inher)
(func-decl-cont . c-lineup-java-throws))))
(add-to-list 'c-default-style '(java-mode . "java")))
(with-eval-after-load "abbrev"
(define-abbrev-table 'java-mode-abbrev-table nil)
(add-hook 'java-mode-hook
(proc (setq-local local-abbrev-table java-mode-abbrev-table)))))
WAIT Haskell
Haskell is a static lazy functional programming language (what a mouthful). It's quite a beautiful language and really learning it will change the way you think about programming. However, my preferred functional language is still unfortunately Lisp so no extra brownie points there.
Here I configure the REPL for Haskell via the
haskell-interactive-mode. I also load my custom package
haskell-multiedit which allows a
user to create temporary haskell-mode buffers that, upon completion,
will run in the REPL. Even easier than making your own buffer.
(use-package haskell-mode
:hook
(haskell-mode-hook . haskell-indentation-mode)
(haskell-mode-hook . interactive-haskell-mode)
:custom
(haskell-interactive-prompt "[λ] ")
(haskell-interactive-prompt-cont "{λ} ")
(haskell-interactive-popup-errors nil)
(haskell-stylish-on-save nil)
(haskell-process-type 'stack-ghci)
:general
(shell-leader
"h" #'+shell/toggle-haskell-repl)
:display
("\\*haskell.**\\*"
(display-buffer-at-bottom)
(window-height . 0.25))
:config
(load (concat user-emacs-directory "elisp/haskell-multiedit.el"))
(+oreo/create-toggle-function
+shell/toggle-haskell-repl
"*haskell*"
haskell-interactive-bring
nil))
Python
Works well for python. If you have pyls it should be on your path, so
just run eglot if you need. But an LSP server is not necessary for a
lot of my time in python. Here I also setup org-babel for python
source code blocks.
(use-package python
:defer t
:straight nil
:pretty
(python-mode-hook
("None" . "Ø")
("list" . "ℓ")
("List" . "ℓ")
("str" . "𝕊")
("True" . "⊨")
("False" . "⊭")
("!" . "¬")
("&&" . "∧")
("||" . "∨")
("for" . "∀")
("print" . "φ")
("lambda" . "λ")
("return" . "⟼")
("yield" . "⟻"))
:init
(setq python-indent-offset 4)
:config
(with-eval-after-load "org-mode"
(setf (alist-get 'python org-babel-load-languages) t)))
Python shell
Setup for python shell, including a toggle option
(use-package python
:straight nil
:commands +python/toggle-repl
:general
(shell-leader
"p" #'run-python)
:display
("\\*Python\\*"
(display-buffer-at-bottom)
(window-height . 0.25)))
YAML
YAML is a data language which is useful for config files.
(use-package yaml-mode
:straight t)
HTML/CSS/JS
Firstly, web mode for consistent colouring of syntax.
(use-package web-mode
:mode ("\\.html" . web-mode)
:mode ("\\.js" . web-mode)
:mode ("\\.css" . web-mode)
:custom
((web-mode-code-indent-offset 2)
(web-mode-markup-indent-offset 2)
(web-mode-css-indent-offset 2)))
Emmet
Emmet for super speed code writing.
(use-package emmet-mode
:hook (web-mode-hook . emmet-mode)
:general
(imap
:keymaps 'emmet-mode-keymap
"TAB" #'emmet-expand-line
"M-j" #'emmet-next-edit-point
"M-k" #'emmet-prev-edit-point))
HTML Auto insert
(use-package web-mode
:defer t
:auto-insert
(("\\.html\\'" . "HTML Skeleton")
""
"<!doctype html>
<html lang=''>
<head>
<meta charset='utf-8'>
<meta http-equiv='x-ua-compatible' content='ie=edge'>
<title>"(read-string "Enter title: ") | """</title>
<meta name='description' content='" (read-string "Enter description: ") | "" "'>
<meta name='author' content='"user-full-name"'/>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<link rel='apple-touch-icon' href='/apple-touch-icon.png'>
<link rel='shortcut icon' href='/favicon.ico'/>
<!-- Place favicon.ico in the root directory -->
</head>
<body>
<!--[if lt IE 8]>
<p class='browserupgrade'>
You are using an <strong>outdated</strong> browser. Please
<a href='http://browsehappy.com/'>upgrade your browser</a> to improve
your experience.
</p>
<![endif]-->
"
_
" </body>
</html>"))
Typescript
A child language of javascript which compiles to it.
(use-package typescript-mode
:defer t
:init
(setq typescript-indent-level 2))
Common Lisp
Common Lisp is a dialect of Lisp, the most common one around. Emacs comes with builtin Lisp support of course, but a REPL would be nice.
Sly
Enter SLY. Sly is a fork of SLIME and is mandatory for lisp development on Emacs.
(use-package sly
:straight t
:init
(setq inferior-lisp-program "sbcl")
:display
("\\*sly-db"
(display-buffer-at-bottom)
(window-height . 0.5))
("\\*sly-"
(display-buffer-at-bottom)
(window-height . 0.25))
:config
(evil-set-initial-state 'sly-db-mode 'emacs)
(with-eval-after-load "org"
(setq-default org-babel-lisp-eval-fn #'sly-eval))
(with-eval-after-load "company"
(add-hook 'sly-mrepl-hook #'company-mode))
:general
(shell-leader
"s" #'sly-mrepl)
(nmap
:keymaps '(lisp-mode-map sly-mrepl-mode-map)
"gr" #'sly-eval-buffer
"gd" #'sly-edit-definition
"gR" #'sly-who-calls)
(local-leader
:keymaps '(lisp-mode-map sly-mrepl-mode-map)
"s" #'+shell/toggle-sly
"c" #'sly-compile-file
"a" #'sly-apropos
"d" #'sly-describe-symbol
"D" #'sly-documentation-lookup
"S" #'sly-mrepl-sync
"E" #'sly-eval-defun)
(local-leader
:keymaps 'lisp-mode-map
:infix "e"
"b" #'sly-eval-buffer
"e" #'sly-eval-last-expression
"f" #'sly-eval-defun
"r" #'sly-eval-region)
(nmap
:keymaps 'sly-inspector-mode-map
"q" #'sly-inspector-quit))
Emacs lisp
(use-package elisp-mode
:straight nil
:pretty
(lisp-mode-hook
("lambda" . "λ")
("t" . "⊨")
("nil" . "Ø")
("and" . "∧")
("or" . "∨")
("defun" . "ƒ")
("for" . "∀")
("mapc" . "∀")
("mapcar" . "∀"))
(emacs-lisp-mode-hook
("lambda" . "λ")
("t" . "⊨")
("nil" . "Ø")
("and" . "∧")
("or" . "∨")
("defun" . "ƒ")
("for" . "∀")
("mapc" . "∀")
("mapcar" . "∀"))
:general
(:states '(normal motion visual)
:keymaps '(emacs-lisp-mode-map lisp-mode-map)
")" #'sp-next-sexp
"(" #'sp-previous-sexp)
(nmmap
:keymaps '(emacs-lisp-mode-map lisp-interaction-mode-map)
"gr" #'eval-last-sexp)
(vmap
:keymaps '(emacs-lisp-mode-map lisp-interaction-mode-map)
"gr" #'eval-region))
WIP Hydra like Lispy
A Hydra which uses the Lispy package (by
abo-abo) to create a set of motions that allow movement around a lisp
file easily.
2024-04-18: Still working on this, quite rough around the edges.
(use-package lispy
:after (lisp-mode elisp-mode)
:hydra
(hydra-lispy
nil "Move around quickly in Lisp"
("h" #'lispy-left)
("j" ("t" #'lispy-teleport)
#'lispy-down)
("k" #'lispy-up)
("l" #'lispy-right)
("d" #'lispy-different)
("u" #'lispy-flow)
("o" #'lispy-oneline)
("m" #'lispy-multiline)
("N" #'lispy-narrow)
("W" #'lispy-widen)
("c" #'lispy-clone)
("fp" #'lispy-ace-paren)
("fs" #'lispy-ace-symbol :exit t)
("H" #'lispy-slurp)
("L" #'lispy-barf)
("M-h" #'lispy-move-left)
("M-j" #'lispy-move-down)
("M-k" #'lispy-move-up)
("M-l" #'lispy-move-right)
("C-g" nil))
:general
(nmmap
:keymaps '(emacs-lisp-mode-map lisp-mode-map)
"." #'hydra-lispy/body))
Lisp indent function
Add a new lisp indent function which indents newline lists more appropriately.
(use-package lisp-mode
:straight nil
:config
(defun +oreo/lisp-indent-function (indent-point state)
(let ((normal-indent (current-column))
(orig-point (point)))
(goto-char (1+ (elt state 1)))
(parse-partial-sexp (point) calculate-lisp-indent-last-sexp 0 t)
(cond
;; car of form doesn't seem to be a symbol, or is a keyword
((and (elt state 2)
(or (not (looking-at "\\sw\\|\\s_"))
(looking-at ":")))
(if (not (> (save-excursion (forward-line 1) (point))
calculate-lisp-indent-last-sexp))
(progn (goto-char calculate-lisp-indent-last-sexp)
(beginning-of-line)
(parse-partial-sexp (point)
calculate-lisp-indent-last-sexp 0 t)))
;; Indent under the list or under the first sexp on the same
;; line as calculate-lisp-indent-last-sexp. Note that first
;; thing on that line has to be complete sexp since we are
;; inside the innermost containing sexp.
(backward-prefix-chars)
(current-column))
((and (save-excursion
(goto-char indent-point)
(skip-syntax-forward " ")
(not (looking-at ":")))
(save-excursion
(goto-char orig-point)
(looking-at ":")))
(save-excursion
(goto-char (+ 2 (elt state 1)))
(current-column)))
(t
(let ((function (buffer-substring (point)
(progn (forward-sexp 1) (point))))
method)
(setq method (or (function-get (intern-soft function)
'lisp-indent-function)
(get (intern-soft function) 'lisp-indent-hook)))
(cond ((or (eq method 'defun)
(and (null method)
(> (length function) 3)
(string-match "\\`def" function)))
(lisp-indent-defform state indent-point))
((integerp method)
(lisp-indent-specform method state
indent-point normal-indent))
(method
(funcall method indent-point state))))))))
(setq-default lisp-indent-function #'+oreo/lisp-indent-function))