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

7
.gitignore vendored
View File

@@ -3,4 +3,9 @@ eln-cache/
elpa/ elpa/
transient/ transient/
tramp tramp
auto-save-list 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. ;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right. ;; If there is more than one, they won't work right.
'(package-selected-packages '(package-selected-packages
'(aider browse-kill-ring cider company corfu exec-path-from-shell '(aider browse-kill-ring caddyfile-mode cape cider company corfu
haskell-mode haskell-ts-mode helm marginalia dockerfile-mode dumb-jump dumber-jump emacs-lldb
markdown-ts-mode multiple-cursors orderless org-mode sly exec-path-from-shell flycheck fsharp-mode haskell-mode
terraform-mode tree-sitter-langs vertico visual-fill-column haskell-ts-mode helm htmlize idris-mode marginalia
yasnippet-snippets))) 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
;; custom-set-faces was added by Custom. ;; custom-set-faces was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful. ;; 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) (require 'package)
(add-to-list 'package-archives (add-to-list 'package-archives
'("melpa" . "https://melpa.org/packages/") t) '("melpa" . "https://melpa.org/packages/") t)
@@ -6,6 +8,9 @@
(require 'use-package-ensure) (require 'use-package-ensure)
(require 'bind-key) (require 'bind-key)
; If startup times are slow
; (setq use-package-verbose t)
(use-package emacs) (use-package emacs)
(setq tab-bar-show nil) (setq tab-bar-show nil)
(setq inhibit-startup-message t) (setq inhibit-startup-message t)
@@ -27,12 +32,24 @@
(setq reb-re-syntax 'string) (setq reb-re-syntax 'string)
(setq default-tab-width 4) (setq default-tab-width 4)
(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 use-package-always-ensure t)
(setq mac-command-modifier 'control) (setq mac-command-modifier 'control)
(setq is-mac (string= system-type "darwin")) (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 (when is-mac
(setq dired-use-ls-dired t (setq dired-use-ls-dired t
insert-directory-program "gls" insert-directory-program "gls"
@@ -61,59 +78,93 @@
(defun hgh/project-ripgrep (regexp) (defun hgh/project-ripgrep (regexp)
(interactive (list (read-from-minibuffer "Search (regexp): " (thing-at-point 'symbol)))) (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) (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 ;; key bindings
(keymap-global-set "M-o" #'other-window) (keymap-global-set "M-o" #'other-window)
(keymap-global-set "M-i" #'imenu) (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 "<f5>" #'compile)
(keymap-global-set "C-c r r" #'revert-buffer) (keymap-global-set "C-c r r" #'revert-buffer)
(keymap-global-set "C-c C-c" #'comment-or-uncomment-region) (keymap-global-set "C-c C-c" #'comment-or-uncomment-region)
(keymap-global-set "M-]" #'forward-paragraph) (keymap-global-set "M-]" #'forward-paragraph)
(keymap-global-set "M-[" #'backward-paragraph) (keymap-global-set "M-[" #'backward-paragraph)
(keymap-global-set "C-h h" #'eldoc) (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 e i" #'hgh/visit-init-file)
(keymap-global-set "C-c c" #'compile) (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) (require 'dired)
(setq dired-dwim-target t)
(keymap-set dired-mode-map "C-c C-c" #'wdired-change-to-wdired-mode) (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 (use-package exec-path-from-shell
:when is-mac :when is-mac
:config :config
(exec-path-from-shell-initialize)) (exec-path-from-shell-initialize))
(use-package man
:when is-mac
:custom
(manual-program "gman"))
(use-package magit (use-package magit
:defer t) :defer t)
(use-package tree-sitter (use-package tree-sitter
:mode (("\\.tsx\\'" . tsx-ts-mode) :mode ((" \\.tsx\\'" . tsx-ts-mode)
("\\.js\\'" . typescript-ts-mode) (" \\.js\\'" . typescript-ts-mode)
("\\.mjs\\'" . typescript-ts-mode) (" \\.mjs\\'" . typescript-ts-mode)
("\\.mts\\'" . typescript-ts-mode) (" \\.mts\\'" . typescript-ts-mode)
("\\.cjs\\'" . typescript-ts-mode) (" \\.cjs\\'" . typescript-ts-mode)
("\\.ts\\'" . typescript-ts-mode) (" \\.ts\\'" . typescript-ts-mode)
("\\.jsx\\'" . tsx-ts-mode) (" \\.jsx\\'" . tsx-ts-mode)
("\\.json\\'" . json-ts-mode)) (" \\.json\\'" . json-ts-mode))
:custom :custom
(treesit-extra-load-path '("~/repos/tree-sitter-module/dist"))) (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) (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 (use-package sly
:defer t
:custom :custom
(inferior-lisp-program "/opt/homebrew/bin/sbcl")) (inferior-lisp-program "/opt/homebrew/bin/sbcl"))
@@ -147,13 +198,13 @@
:config :config
(global-corfu-mode 1)) (global-corfu-mode 1))
(use-package cape
:init
(add-to-list 'completion-at-point-functions #'cape-dabbrev))
(use-package browse-kill-ring (use-package browse-kill-ring
:bind (("C-c y" . 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 () (defun hgh/org-mode-visual-fill ()
(setq visual-fill-column-width 120 (setq visual-fill-column-width 120
visual-fill-column-center-text t) visual-fill-column-center-text t)
@@ -173,7 +224,8 @@
(java-ts-mode . eglot-ensure) (java-ts-mode . eglot-ensure)
(svelte-mode . eglot-ensure) (svelte-mode . eglot-ensure)
(haskell-mode . eglot-ensure) (haskell-mode . eglot-ensure)
(terraform-mode . eglot-ensure)) (terraform-mode . eglot-ensure)
(odin-mode . eglot-ensure))
:bind :bind
(:map eglot-mode-map (:map eglot-mode-map
("C-c r" . eglot-rename) ("C-c r" . eglot-rename)
@@ -188,14 +240,18 @@
(cl-remove-if (lambda (c) (equal (car c) 'rust-mode)) (cl-remove-if (lambda (c) (equal (car c) 'rust-mode))
eglot-server-programs)) eglot-server-programs))
(setf eglot-server-programs (cons (list '(rust-ts-mode rust-mode) "rust-analyzer" :initializationOptions '(:checkOnSave (:command "clippy"))) (setf eglot-server-programs
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") (setenv "DOTNET_ROOT" "~/.local/share/mise/installs/dotnet/9")
eglot-server-programs)) (push '("\\.csproj$" . xml-mode) auto-mode-alist)
(push '("\\.vs$" . c-mode) auto-mode-alist)
(setf eglot-server-programs (cons '(haskell-mode "haskell-language-server-wrapper" "--lsp") (push '("\\.fs$" . c-mode) auto-mode-alist)
eglot-server-programs))) (push '("\\.sbclrc" . lisp-mode) auto-mode-alist)
;; paredit ;; paredit
@@ -209,18 +265,35 @@
(define-key paredit-mode-map (kbd "M-:") #'paredit-backward-barf-sexp) (define-key paredit-mode-map (kbd "M-:") #'paredit-backward-barf-sexp)
(enable-paredit-mode)) (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) (clojure-mode-hook clojure-mode)
(lisp-mode-hook lisp-mode) (lisp-mode-hook lisp-mode)
(sly-mode-hook sly-mode))) (sly-mode-hook sly-mode)))
(add-hook 'lisp-mode-hook (defun hgh/rg (search)
(lambda () (interactive "sSearch: ")
(set (make-local-variable 'lisp-indent-function) (compilation-start
'common-lisp-indent-function) (concat "rg --no-heading '" search "'")
(setup-paredit))) 'compilation-mode
(lambda (s)
(concat
"*"
(file-name-nondirectory (directory-file-name default-directory))
" rg*"))))
(use-package multiple-cursors (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 :config
(global-set-key (kbd "C->") 'mc/mark-next-like-this) (global-set-key (kbd "C->") 'mc/mark-next-like-this)
(global-set-key (kbd "C-<") 'mc/mark-previous-like-this)) (global-set-key (kbd "C-<") 'mc/mark-previous-like-this))
@@ -237,14 +310,6 @@
(use-package markdown-mode (use-package markdown-mode
:ensure t) :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: ;; Run Prettier only in certain major-modes before saving:
(defvar hgh/prettier-modes (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) '(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 terraform-mode)
(use-package cider) (use-package cider
:defer t)
(use-package org (use-package org
:defer t
:custom :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