fordon_greeman / voidfiles

Branch: main
Switch branches/tags
main
theidioticdev add emacs 2079ec5 19h ago
124 lines · 5.1 KB Raw Blame History
1 ;; simp-hare-mode, a simple hare major mode based on simpc, License: GPL -*- lexical-binding: t; -*-
2 (require 'subr-x)
3
4 (defvar simp-hare-mode-syntax-table
5 (let ((table (make-syntax-table)))
6 ;; C/C++ style comments
7 (modify-syntax-entry ?/ ". 124b" table)
8 (modify-syntax-entry ?* ". 23" table)
9 (modify-syntax-entry ?\n "> b" table)
10 ;; Preprocessor stuff?
11 (modify-syntax-entry ?# "." table)
12 ;; Chars are the same as strings
13 (modify-syntax-entry ?' "\"" table)
14 ;; Treat <> as punctuation (needed to highlight C++ keywords
15 ;; properly in template syntax)
16 (modify-syntax-entry ?< "." table)
17 (modify-syntax-entry ?> "." table)
18 (modify-syntax-entry ?& "." table)
19 (modify-syntax-entry ?% "." table)
20 table))
21
22 (defun simp-hare-types ()
23 '("abort" "align" "alloc" "append" "as" "assert" "bool" "break"
24 "case" "const" "continue" "def" "defer" "delete"
25 "done" "else" "export" "false" "fn" "for" "free" "if" "insert"
26 "is" "len" "let" "match" "never" "nullable"
27 "offset" "return" "size" "uintptr" "switch" "use" "vaarg" "vaend"
28 "valist" "vastart" "yield" "_"))
29
30 (defun simp-hare-keywords ()
31 '("f32" "f64" "enum" "i16" "i32" "i64" "i8" "int" "null" "nomem" "opaque" "static" "rune"
32 "str" "struct" "true" "type" "u16" "u32" "u64" "u8" "uint" "void" "union"))
33
34 (defun simp-hare-font-lock-keywords ()
35 (list
36 `("# *\\(warn\\|error\\)" . font-lock-warning-face)
37 `("# *[#a-zA-Z0-9_]+" . font-lock-preprocessor-face)
38 `("# *include\\(?:_next\\)?\\s-+\\(\\(<\\|\"\\).*\\(>\\|\"\\)\\)" . (1 font-lock-string-face))
39 `("\\(?:enum\\|struct\\)\\s-+\\([a-zA-Z0-9_]+\\)" . (1 font-lock-type-face))
40 `(,(regexp-opt (simp-hare-keywords) 'symbols) . font-lock-keyword-face)
41 `(,(regexp-opt (simp-hare-types) 'symbols) . font-lock-type-face)))
42
43 (defun simp-hare--previous-non-empty-line ()
44 "Returns either NIL when there is no such line or a pair (line . indentation)"
45 (save-excursion
46 ;; If you are on the first line, but not at the beginning of buffer (BOB) the `(bobp)`
47 ;; function does not return `t`. So we have to move to the beginning of the line first.
48 ;; TODO: feel free to suggest a better approach for checking BOB here.
49 (move-beginning-of-line nil)
50 (if (bobp)
51 ;; If you are standing at the BOB, you by definition don't have a previous non-empty line.
52 nil
53 ;; Moving one line backwards because the current line is by definition is not
54 ;; the previous non-empty line.
55 (forward-line -1)
56 ;; Keep moving backwards until we hit BOB or a non-empty line.
57 (while (and (not (bobp))
58 (string-empty-p
59 (string-trim-right
60 (thing-at-point 'line t))))
61 (forward-line -1))
62
63 (if (string-empty-p
64 (string-trim-right
65 (thing-at-point 'line t)))
66 ;; If after moving backwards for this long we still look at an empty
67 ;; line we by definition didn't find the previous non-empty line.
68 nil
69 ;; We found the previous non-empty line!
70 (cons (thing-at-point 'line t)
71 (current-indentation))))))
72
73 (defun simp-hare--desired-indentation ()
74 (let ((prev (simp-hare--previous-non-empty-line)))
75 (if (not prev)
76 (current-indentation)
77 (let ((indent-len 8)
78 (cur-line (string-trim-right (thing-at-point 'line t)))
79 (prev-line (string-trim-right (car prev)))
80 (prev-indent (cdr prev)))
81 (cond
82 ((string-match-p "^\\s-*switch\\s-*(.+)" prev-line)
83 prev-indent)
84 ((string-match-p "^\\s-*match\\s-*(.+)" prev-line)
85 prev-indent)
86 ((and (string-suffix-p "{" prev-line)
87 (string-prefix-p "}" (string-trim-left cur-line)))
88 prev-indent)
89 ((string-suffix-p "{" prev-line)
90 (+ prev-indent indent-len))
91 ((string-prefix-p "}" (string-trim-left cur-line))
92 (max (- prev-indent indent-len) 0))
93 ((string-suffix-p ":" prev-line)
94 (if (string-suffix-p ":" cur-line)
95 prev-indent
96 (+ prev-indent indent-len)))
97 ((string-suffix-p ":" cur-line)
98 (max (- prev-indent indent-len) 0))
99 ((string-suffix-p "=>" prev-line)
100 (if (string-suffix-p "=>" cur-line)
101 prev-indent
102 (+ prev-indent indent-len)))
103 ((string-suffix-p "=>" cur-line)
104 (max (- prev-indent indent-len) 0))
105 (t prev-indent))))))
106
107 ;;; TODO: customizable indentation (amount of spaces, tabs, etc)
108 (defun simp-hare-indent-line ()
109 (interactive)
110 (when (not (bobp))
111 (let* ((desired-indentation
112 (simp-hare--desired-indentation))
113 (n (max (- (current-column) (current-indentation)) 0)))
114 (indent-line-to desired-indentation)
115 (forward-char n))))
116
117 (define-derived-mode simp-hare-mode prog-mode "Simple Hare"
118 "Simple major mode for editing Hare files based on simpc."
119 :syntax-table simp-hare-mode-syntax-table
120 (setq-local font-lock-defaults '(simp-hare-font-lock-keywords))
121 (setq-local indent-line-function 'simp-hare-indent-line)
122 (setq-local comment-start "// "))
123
124 (provide 'simp-hare-mode)