Blob


1 ;;; 9ps-mode.el --- major mode for editing ninepscripts -*- lexical-binding: t; -*-
3 ;; Copyright (C) 2021 Omar Polo
5 ;; Author: Omar Polo <op@omarpolo.com>
6 ;; Keywords: languages
8 ;; Permission to use, copy, modify, and distribute this software for any
9 ;; purpose with or without fee is hereby granted, provided that the above
10 ;; copyright notice and this permission notice appear in all copies.
12 ;; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 ;; WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 ;; MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 ;; ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 ;; WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ;; ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 ;; OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 ;;; Commentary:
22 ;; Major mode for editing ninepscripts, the kamid regression tests.
24 ;;; Code:
25 (eval-when-compile
26 (require 'rx))
28 (defconst 9ps--font-lock-defaults
29 (let ((keywords '("assert" "const" "dir" "include" "proc" "should-fail"
30 "testing" "vargs"))
31 (types '("str" "u8" "u16" "u32")))
32 `(((,(rx-to-string `(: (or ,@keywords))) 0 font-lock-keyword-face)
33 ("\\([[:word:]]+\\)\s*(" 1 font-lock-function-name-face)
34 (,(rx-to-string `(: (or ,@types))) 0 font-lock-type-face)))))
36 (defvar 9ps-mode-syntax-table
37 (let ((st (make-syntax-table)))
38 (modify-syntax-entry ?\{ "(}" st)
39 (modify-syntax-entry ?\} "){" st)
40 (modify-syntax-entry ?\( "()" st)
42 ;; - and _ are word constituent
43 (modify-syntax-entry ?_ "w" st)
44 (modify-syntax-entry ?- "w" st)
46 ;; both single and double quotes makes strings
47 (modify-syntax-entry ?\" "\"" st)
48 (modify-syntax-entry ?' "'" st)
50 ;; one day we'll have escaping (maybe)
51 (modify-syntax-entry ?\\ "\\" st)
53 ;; add comments. lua-mode does something similar, so it shouldn't
54 ;; bee *too* wrong.
55 (modify-syntax-entry ?# "<" st)
56 (modify-syntax-entry ?\n ">" st)
58 ;; '==' as punctuation
59 (modify-syntax-entry ?= ".")
60 st))
62 (defun 9ps-indent-line ()
63 "Indent current line."
64 (let (indent
65 boi-p ;begin of indent
66 move-eol-p
67 (point (point)))
68 (save-excursion
69 (back-to-indentation)
70 (setq indent (car (syntax-ppss))
71 boi-p (= point (point)))
72 ;; don't indent empty lines if they don't have the in it
73 (when (and (eq (char-after) ?\n)
74 (not boi-p))
75 (setq indent 0))
76 ;; check whether we want to move to the end of line
77 (when boi-p
78 (setq move-eol-p t))
79 ;; decrement the indent if the first character on the line is a
80 ;; closer.
81 (when (or (eq (char-after) ?\))
82 (eq (char-after) ?\}))
83 (setq indent (1- indent)))
84 ;; indent the line
85 (delete-region (line-beginning-position)
86 (point))
87 (indent-to (* tab-width indent)))
88 (when move-eol-p
89 (move-end-of-line nil))))
91 (defvar 9ps-mode-abbrev-table nil
92 "Abbreviation table used in `9ps-mode' buffers.")
94 (define-abbrev-table '9ps-mode-abbrev-table
95 '())
97 ;;;###autoload
98 (define-derived-mode 9ps-mode prog-mode "9ps"
99 "Major mode for ninepscript files."
100 :abbrev-table 9ps-mode-abbrev-table
101 (setq font-lock-defaults 9ps--font-lock-defaults)
102 (setq-local comment-start "#")
103 (setq-local comment-start-skip "#+[\t ]*")
104 (setq-local indent-line-function #'9ps-indent-line)
105 (setq-local indent-tabs-mode t))
107 ;;;###autoload
108 (add-to-list 'auto-mode-alist '("\\.9ps" . 9ps-mode))
110 (provide '9ps-mode)
111 ;;; 9ps-mode.el ends here