setup odin mode

This commit is contained in:
2026-01-09 10:04:55 -05:00
parent 9a35919db1
commit 2ffc66e4ad
4 changed files with 490 additions and 52 deletions

5
.gitignore vendored
View File

@@ -4,3 +4,8 @@ elpa/
transient/
tramp
auto-save-list
history
projects
eshell
parinfer-rust
.mc-lists.el

View File

@@ -5,11 +5,18 @@
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
'(package-selected-packages
'(aider browse-kill-ring cider company corfu exec-path-from-shell
haskell-mode haskell-ts-mode helm marginalia
markdown-ts-mode multiple-cursors orderless org-mode sly
terraform-mode tree-sitter-langs vertico visual-fill-column
yasnippet-snippets)))
'(aider browse-kill-ring caddyfile-mode cape cider company corfu
dockerfile-mode dumb-jump dumber-jump emacs-lldb
exec-path-from-shell flycheck fsharp-mode haskell-mode
haskell-ts-mode helm htmlize idris-mode marginalia
markdown-ts-mode multiple-cursors orderless org-mode
parinfer-rust-mode realgud-lldb rg sly terraform-mode
tree-sitter-langs vertico visual-fill-column
yasnippet-snippets zig-mode))
'(safe-local-variable-directories '("/Users/grant/programming/project/edit/"))
'(safe-local-variable-values
'((Package . CL-USER) (Syntax . ANSI-Common-Lisp) (Base . 10)
(flycheck-clang-includes . "SDL3-3.2.26/include"))))
(custom-set-faces
;; custom-set-faces was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.

208
init.el
View File

@@ -1,3 +1,5 @@
;; -*- lexical-binding: t; -*-
(require 'package)
(add-to-list 'package-archives
'("melpa" . "https://melpa.org/packages/") t)
@@ -6,6 +8,9 @@
(require 'use-package-ensure)
(require 'bind-key)
; If startup times are slow
; (setq use-package-verbose t)
(use-package emacs)
(setq tab-bar-show nil)
(setq inhibit-startup-message t)
@@ -27,12 +32,24 @@
(setq reb-re-syntax 'string)
(setq default-tab-width 4)
(setq-default tab-width 4)
(set-face-attribute 'default nil :height 160 :family "Monaco")
(set-face-attribute 'default nil :height 160 :family "Berkeley Mono")
(global-hl-line-mode 1)
(setq use-package-always-ensure t)
(setq mac-command-modifier 'control)
(setq is-mac (string= system-type "darwin"))
(setq-default cursor-type 'bar)
(defun hgh/disable-bar-cursor ()
(blink-cursor-mode -1))
(defun hgh/enable-bar-cursor ()
(blink-cursor-mode 1))
(add-hook 'activate-mark-hook 'hgh/disable-bar-cursor)
(add-hook 'deactivate-mark-hook 'hgh/enable-bar-cursor)
(when is-mac
(setq dired-use-ls-dired t
insert-directory-program "gls"
@@ -61,59 +78,93 @@
(defun hgh/project-ripgrep (regexp)
(interactive (list (read-from-minibuffer "Search (regexp): " (thing-at-point 'symbol))))
(ripgrep-regexp regexp (project-root (project-current))))
(rg regexp "*" (project-root (project-current))))
(defun hgh/current-date-time ()
(interactive)
(insert (format-time-string "%Y-%m-%d %H:%M:%S")))
(add-hook 'compilation-filter-hook 'ansi-color-compilation-filter)
(defun hgh/next-error ()
(interactive)
(if (eglot-managed-p)
(flymake-goto-next-error)
(next-error)))
;; key bindings
(keymap-global-set "M-o" #'other-window)
(keymap-global-set "M-i" #'imenu)
(keymap-global-set "C-M-." #'end-of-buffer)
(keymap-global-set "C-M-," #'beginning-of-buffer)
(keymap-global-set "C-." #'xref-find-definitions)
(keymap-global-set "C-," #'xref-go-back)
(keymap-global-set "<f5>" #'compile)
(keymap-global-set "C-c r r" #'revert-buffer)
(keymap-global-set "C-c C-c" #'comment-or-uncomment-region)
(keymap-global-set "M-]" #'forward-paragraph)
(keymap-global-set "M-[" #'backward-paragraph)
(keymap-global-set "C-h h" #'eldoc)
(keymap-global-set "C-]" #'flymake-goto-next-error)
(keymap-global-set "C-]" #'hgh/next-error)
(keymap-global-set "C-c e i" #'hgh/visit-init-file)
(keymap-global-set "C-c c" #'compile)
(keymap-global-set "C-x C-b" #'ibuffer)
(keymap-global-set "M-0" #'delete-window)
(keymap-global-set "M-1" #'delete-other-windows)
(keymap-global-set "M-2" #'split-window-below)
(keymap-global-set "M-3" #'split-window-right)
(require 'dired)
(setq dired-dwim-target t)
(keymap-set dired-mode-map "C-c C-c" #'wdired-change-to-wdired-mode)
(load-theme 'modus-vivendi-tinted t)
(load-theme 'modus-vivendi t)
(use-package exec-path-from-shell
:when is-mac
:config
(exec-path-from-shell-initialize))
(use-package man
:when is-mac
:custom
(manual-program "gman"))
(use-package magit
:defer t)
(use-package tree-sitter
:mode (("\\.tsx\\'" . tsx-ts-mode)
("\\.js\\'" . typescript-ts-mode)
("\\.mjs\\'" . typescript-ts-mode)
("\\.mts\\'" . typescript-ts-mode)
("\\.cjs\\'" . typescript-ts-mode)
("\\.ts\\'" . typescript-ts-mode)
("\\.jsx\\'" . tsx-ts-mode)
("\\.json\\'" . json-ts-mode))
:mode ((" \\.tsx\\'" . tsx-ts-mode)
(" \\.js\\'" . typescript-ts-mode)
(" \\.mjs\\'" . typescript-ts-mode)
(" \\.mts\\'" . typescript-ts-mode)
(" \\.cjs\\'" . typescript-ts-mode)
(" \\.ts\\'" . typescript-ts-mode)
(" \\.jsx\\'" . tsx-ts-mode)
(" \\.json\\'" . json-ts-mode))
:custom
(treesit-extra-load-path '("~/repos/tree-sitter-module/dist")))
(use-package tree-sitter-langs)
(use-package tree-sitter-langs
:defer t)
(use-package haskell-mode)
(use-package haskell-mode
:defer t)
(use-package company)
(defun enable-parinfer ()
(let ((buf (or (buffer-file-name) (buffer-name) "")))
(when (and
(not (s-contains? "sbcl" buf))
(not (s-contains? "ocicl" buf))
(not (string-prefix-p "*sly" buf)))
(parinfer-rust-mode 1)
(electric-quote-mode 1))))
(use-package parinfer-rust-mode
:hook ((lisp-mode emacs-lisp-mode) . enable-parinfer)
:config
(setq parinfer-rust-disable-troublesome-modes t))
(use-package sly
:defer t
:custom
(inferior-lisp-program "/opt/homebrew/bin/sbcl"))
@@ -147,13 +198,13 @@
:config
(global-corfu-mode 1))
(use-package cape
:init
(add-to-list 'completion-at-point-functions #'cape-dabbrev))
(use-package browse-kill-ring
:bind (("C-c y" . browse-kill-ring)))
(defun hgh/org-mode-setup ()
(org-indent-mode)
(visual-line-mode 1))
(defun hgh/org-mode-visual-fill ()
(setq visual-fill-column-width 120
visual-fill-column-center-text t)
@@ -173,7 +224,8 @@
(java-ts-mode . eglot-ensure)
(svelte-mode . eglot-ensure)
(haskell-mode . eglot-ensure)
(terraform-mode . eglot-ensure))
(terraform-mode . eglot-ensure)
(odin-mode . eglot-ensure))
:bind
(:map eglot-mode-map
("C-c r" . eglot-rename)
@@ -188,14 +240,18 @@
(cl-remove-if (lambda (c) (equal (car c) 'rust-mode))
eglot-server-programs))
(setf eglot-server-programs (cons (list '(rust-ts-mode rust-mode) "rust-analyzer" :initializationOptions '(:checkOnSave (:command "clippy")))
eglot-server-programs))
(setf eglot-server-programs
(append (list
(list '(rust-ts-mode rust-mode) "rust-analyzer" :initializationOptions '(:checkOnSave (:command "clippy")))
'(svelte-mode "svelteserver" "--stdio")
'(haskell-mode "haskell-language-server-wrapper" "--lsp"))
eglot-server-programs)))
(setf eglot-server-programs (cons '(svelte-mode "svelteserver" "--stdio")
eglot-server-programs))
(setf eglot-server-programs (cons '(haskell-mode "haskell-language-server-wrapper" "--lsp")
eglot-server-programs)))
(setenv "DOTNET_ROOT" "~/.local/share/mise/installs/dotnet/9")
(push '("\\.csproj$" . xml-mode) auto-mode-alist)
(push '("\\.vs$" . c-mode) auto-mode-alist)
(push '("\\.fs$" . c-mode) auto-mode-alist)
(push '("\\.sbclrc" . lisp-mode) auto-mode-alist)
;; paredit
@@ -209,18 +265,35 @@
(define-key paredit-mode-map (kbd "M-:") #'paredit-backward-barf-sexp)
(enable-paredit-mode))
(setq lisp-mode-hooks '((emacs-lisp-mode-hook emacs-lisp-mode)
(defvar lisp-mode-hooks nil)
(setf lisp-mode-hooks '((emacs-lisp-mode-hook emacs-lisp-mode)
(clojure-mode-hook clojure-mode)
(lisp-mode-hook lisp-mode)
(sly-mode-hook sly-mode)))
(add-hook 'lisp-mode-hook
(lambda ()
(set (make-local-variable 'lisp-indent-function)
'common-lisp-indent-function)
(setup-paredit)))
(defun hgh/rg (search)
(interactive "sSearch: ")
(compilation-start
(concat "rg --no-heading '" search "'")
'compilation-mode
(lambda (s)
(concat
"*"
(file-name-nondirectory (directory-file-name default-directory))
" rg*"))))
(use-package multiple-cursors
:init
(add-hook 'multiple-cursors-mode-enabled-hook
(lambda ()
(remove-hook 'activate-mark-hook 'hgh/disable-bar-cursor)
(remove-hook 'deactivate-mark-hook 'hgh/disable-bar-cursor)
(blink-cursor-mode 1)))
(add-hook 'multiple-cursors-mode-disabled-hook
(lambda ()
(add-hook 'activate-mark-hook 'hgh/disable-bar-cursor)
(add-hook 'deactivate-mark-hook 'hgh/disable-bar-cursor)
(blink-cursor-mode 1)))
:config
(global-set-key (kbd "C->") 'mc/mark-next-like-this)
(global-set-key (kbd "C-<") 'mc/mark-previous-like-this))
@@ -237,14 +310,6 @@
(use-package markdown-mode
:ensure t)
(use-package aider
:custom
(aider-args '("--model" "o4-mini" "--no-auto-accept-architect"))
:bind
("C-c a" . #'aider-transient-menu)
:config
(setenv "OPENAI_API_KEY" "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"))
;; Run Prettier only in certain major-modes before saving:
(defvar hgh/prettier-modes
'(tsx-ts-mode typescript-ts-mode typescript-ts-base-mode json-ts-mode javascript-mode js2-mode typescript-mode web-mode)
@@ -264,8 +329,59 @@
(use-package terraform-mode)
(use-package cider)
(use-package cider
:defer t)
(use-package org
:defer t
:custom
(org-todo-keywords '((sequence "TODO" "INPROGRESS" "DONE"))))
(org-todo-keywords '((sequence "TODO" "INPROGRESS" "DONE")))
(org-support-shift-select t)
(org-html-validation-link nil)
(org-html-head-include-default-style nil)
(org-html-head-include-scripts nil)
(org-html-head "<link rel=\"stylesheet\" href=\"https://cdn.simplecss.org/simple.min.css\" />")
:config
(org-indent-mode)
(require 'ox-publish)
(org-babel-do-load-languages
'org-babel-load-languages
'((shell . t)))
(setq org-publish-use-timestamps-flag nil)
(setq org-publish-project-alist
(list
(list "writings"
:base-directory "~/Documents/writings/content"
:publishing-directory "~/Documents/writings/public"
:exclude "~/Documents/writings/notes"
:recursive t
:time-stamp-file nil
:section-numbers nil
:with-creator t
:with-author nil))))
(use-package dumber-jump
:init
(add-hook 'xref-backend-functions #'dumber-jump-xref-activate))
(use-package flycheck)
; :init (global-flycheck-mode)
(use-package idris-mode)
(use-package htmlize)
(use-package zig-mode)
(use-package fsharp-mode)
(use-package caddyfile-mode)
(use-package dockerfile-mode)
(load-file (concat (file-name-parent-directory user-init-file) "odin-mode.el"))

310
odin-mode.el Normal file
View File

@@ -0,0 +1,310 @@
;;; odin-mode.el --- A minor mode for odin
;; Author: Ethan Morgan
;; Keywords: odin, language, languages, mode
;; Package-Requires: ((emacs "24.1"))
;; Homepage: https://github.com/glassofethanol/odin-mode
;; This file is NOT part of GNU Emacs.
;;; Code:
(require 'cl-lib)
(require 'rx)
(require 'js)
(defgroup odin nil
"Odin mode"
:group 'languages)
;; `compilation-mode' configuration
(eval-after-load 'compile
'(add-to-list 'compilation-error-regexp-alist '("^\\(.*?\\)(\\([0-9]+\\):\\([0-9]+\\).*" 1 2 3)))
(defconst odin-mode-syntax-table
(let ((table (make-syntax-table)))
(modify-syntax-entry ?\" "\"" table)
(modify-syntax-entry ?\\ "\\" table)
;; additional symbols
(modify-syntax-entry ?' "\"" table)
(modify-syntax-entry ?` "\"" table)
(modify-syntax-entry ?: "." table)
(modify-syntax-entry ?+ "." table)
(modify-syntax-entry ?- "." table)
(modify-syntax-entry ?% "." table)
(modify-syntax-entry ?& "." table)
(modify-syntax-entry ?| "." table)
(modify-syntax-entry ?^ "." table)
(modify-syntax-entry ?! "." table)
(modify-syntax-entry ?$ "." table)
(modify-syntax-entry ?= "." table)
(modify-syntax-entry ?< "." table)
(modify-syntax-entry ?> "." table)
(modify-syntax-entry ?? "." table)
;; Need this for #directive regexes to work correctly
(modify-syntax-entry ?# "_" table)
;; Modify some syntax entries to allow nested block comments
(modify-syntax-entry ?/ ". 124b" table)
(modify-syntax-entry ?* ". 23n" table)
(modify-syntax-entry ?\n "> b" table)
(modify-syntax-entry ?\^m "> b" table)
table))
(defconst odin-builtins
'("len" "cap"
"typeid_of" "type_info_of"
"swizzle" "complex" "real" "imag" "quaternion" "conj"
"jmag" "kmag"
"min" "max" "abs" "clamp"
"expand_to_tuple"
"init_global_temporary_allocator"
"copy" "pop" "unordered_remove" "ordered_remove" "clear" "reserve"
"resize" "new" "new_clone" "free" "free_all" "delete" "make"
"clear_map" "reserve_map" "delete_key" "append_elem" "append_elems"
"append" "append_string" "clear_dynamic_array" "reserve_dynamic_array"
"resize_dynamic_array" "incl_elem" "incl_elems" "incl_bit_set"
"excl_elem" "excl_elems" "excl_bit_set" "incl" "excl" "card"
"assert" "panic" "unimplemented" "unreachable"))
(defconst odin-keywords
'("import" "foreign" "package"
"where" "when" "if" "else" "for" "switch" "in" "notin" "do" "case"
"break" "continue" "fallthrough" "defer" "return" "proc"
"struct" "union" "enum" "bit_field" "bit_set" "map" "dynamic"
"auto_cast" "cast" "transmute" "distinct" "opaque"
"using" "inline" "no_inline"
"size_of" "align_of" "offset_of" "type_of"
"context"
;; "_"
;; Reserved
"macro" "const"))
(defconst odin-constants
'("nil" "true" "false"
"ODIN_OS" "ODIN_ARCH" "ODIN_ENDIAN" "ODIN_VENDOR"
"ODIN_VERSION" "ODIN_ROOT" "ODIN_DEBUG"))
(defconst odin-typenames
'("bool" "b8" "b16" "b32" "b64"
"int" "i8" "i16" "i32" "i64"
"i16le" "i32le" "i64le"
"i16be" "i32be" "i64be"
"i128" "u128"
"i128le" "u128le"
"i128be" "u128be"
"uint" "u8" "u16" "u32" "u64"
"u16le" "u32le" "u64le"
"u16be" "u32be" "u64be"
"f32" "f64"
"complex64" "complex128"
"quaternion128" "quaternion256"
"rune"
"string" "cstring"
"uintptr" "rawptr"
"typeid" "any"
"byte"))
(defconst odin-attributes
'("builtin"
"export"
"static"
"deferred_in" "deferred_none" "deferred_out"
"require_results"
"default_calling_convention" "link_name" "link_prefix"
"deprecated" "private" "thread_local"))
(defconst odin-proc-directives
'("#force_inline"
"#force_no_inline"
"#type")
"Directives that can appear before a proc declaration")
(defconst odin-directives
(append '("#align" "#packed"
"#any_int"
"#raw_union"
"#no_nil"
"#complete"
"#no_alias"
"#c_vararg"
"#assert"
"#file" "#line" "#location" "#procedure" "#caller_location"
"#load"
"#defined"
"#bounds_check" "#no_bounds_check"
"#partial") odin-proc-directives))
(defun odin-wrap-word-rx (s)
(concat "\\<" s "\\>"))
(defun odin-wrap-keyword-rx (s)
(concat "\\(?:\\S.\\_<\\|\\`\\)" s "\\_>"))
(defun odin-wrap-directive-rx (s)
(concat "\\_<" s "\\>"))
(defun odin-wrap-attribute-rx (s)
(concat "[[:space:]\n]*@[[:space:]\n]*(?[[:space:]\n]*" s "\\>"))
(defun odin-keywords-rx (keywords)
"build keyword regexp"
(odin-wrap-keyword-rx (regexp-opt keywords t)))
(defun odin-directives-rx (directives)
(odin-wrap-directive-rx (regexp-opt directives t)))
(defun odin-attributes-rx (attributes)
(odin-wrap-attribute-rx (regexp-opt attributes t)))
(defconst odin-identifier-rx "[[:word:][:multibyte:]_]+")
(defconst odin-hat-type-rx (rx (group (and "^" (1+ (any word "." "_"))))))
(defconst odin-dollar-type-rx (rx (group "$" (or (1+ (any word "_")) (opt "$")))))
(defconst odin-number-rx
(rx (and
symbol-start
(or (and (+ digit) (opt (and (any "eE") (opt (any "-+")) (+ digit))))
(and "0" (any "xX") (+ hex-digit)))
(opt (and (any "_" "A-Z" "a-z") (* (any "_" "A-Z" "a-z" "0-9"))))
symbol-end)))
(defconst odin-proc-rx (concat "\\(\\_<" odin-identifier-rx "\\_>\\)\\s *::\\s *\\(" (odin-directives-rx odin-proc-directives) "\\)?\\s *\\_<proc\\_>"))
(defconst odin-type-rx (concat "\\_<\\(" odin-identifier-rx "\\)\\s *::\\s *\\(?:struct\\|enum\\|union\\|distinct\\)\\s *\\_>"))
(defconst odin-font-lock-defaults
`(
;; Types
(,odin-hat-type-rx 1 font-lock-type-face)
(,odin-dollar-type-rx 1 font-lock-type-face)
(,(odin-keywords-rx odin-typenames) 1 font-lock-type-face)
(,odin-type-rx 1 font-lock-type-face)
;; Hash directives
(,(odin-directives-rx odin-directives) 1 font-lock-preprocessor-face)
;; At directives
(,(odin-attributes-rx odin-attributes) 1 font-lock-preprocessor-face)
;; Keywords
(,(odin-keywords-rx odin-keywords) 1 font-lock-keyword-face)
;; single quote characters
("'\\(\\\\.\\|[^']\\)'" . font-lock-constant-face)
;; Variables
(,(odin-keywords-rx odin-builtins) 1 font-lock-builtin-face)
;; Constants
(,(odin-keywords-rx odin-constants) 1 font-lock-constant-face)
;; Strings
;; ("\\\".*\\\"" . font-lock-string-face)
;; Numbers
(,(odin-wrap-word-rx odin-number-rx) . font-lock-constant-face)
;; Procedures
(,odin-proc-rx 1 font-lock-function-name-face)
("---" . font-lock-constant-face)
("\\.\\.<" . font-lock-constant-face)
("\\.\\." . font-lock-constant-face)
))
;; add setq-local for older emacs versions
(unless (fboundp 'setq-local)
(defmacro setq-local (var val)
`(set (make-local-variable ',var) ,val)))
(defconst odin--defun-rx "\(.*\).*\{")
(defmacro odin-paren-level ()
`(car (syntax-ppss)))
(defun odin-line-is-defun ()
"return t if current line begins a procedure"
(interactive)
(save-excursion
(beginning-of-line)
(let (found)
(while (and (not (eolp)) (not found))
(if (looking-at odin--defun-rx)
(setq found t)
(forward-char 1)))
found)))
(defun odin-beginning-of-defun (&optional count)
"Go to line on which current function starts."
(interactive)
(let ((orig-level (odin-paren-level)))
(while (and
(not (odin-line-is-defun))
(not (bobp))
(> orig-level 0))
(setq orig-level (odin-paren-level))
(while (>= (odin-paren-level) orig-level)
(skip-chars-backward "^{")
(backward-char))))
(if (odin-line-is-defun)
(beginning-of-line)))
(defun odin-end-of-defun ()
"Go to line on which current function ends."
(interactive)
(let ((orig-level (odin-paren-level)))
(when (> orig-level 0)
(odin-beginning-of-defun)
(end-of-line)
(setq orig-level (odin-paren-level))
(skip-chars-forward "^}")
(while (>= (odin-paren-level) orig-level)
(skip-chars-forward "^}")
(forward-char)))))
(defalias 'odin-parent-mode
(if (fboundp 'prog-mode) 'prog-mode 'fundamental-mode))
;;;###autoload
(define-derived-mode odin-mode odin-parent-mode "Odin"
:syntax-table odin-mode-syntax-table
:group 'odin
(setq bidi-paragraph-direction 'left-to-right)
(setq-local require-final-newline mode-require-final-newline)
(setq-local parse-sexp-ignore-comments t)
(setq-local comment-start-skip "\\(//+\\|/\\*+\\)\\s *")
(setq-local comment-start "//")
(setq-local comment-end "")
(setq-local indent-line-function 'js-indent-line)
(setq-local font-lock-defaults '(odin-font-lock-defaults))
(setq-local beginning-of-defun-function 'odin-beginning-of-defun)
(setq-local end-of-defun-function 'odin-end-of-defun)
(setq-local electric-indent-chars
(append "{}():;," electric-indent-chars))
(setq imenu-generic-expression
`(("type" ,(concat "^" odin-type-rx) 1)
("proc" ,(concat "^" odin-proc-rx) 1)))
(font-lock-ensure))
;;;###autoload
(add-to-list 'auto-mode-alist '("\\.odin\\'" . odin-mode))
(provide 'odin-mode)
;;; odin-mode.el ends here