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" "testing"))
30 (types '("str" "u8" "u16" "u32")))
31 `(((,(rx-to-string `(: (or ,@keywords))) 0 font-lock-keyword-face)
32 ("\\([[:word:]]+\\)\s*(" 1 font-lock-function-name-face)
33 (,(rx-to-string `(: (or ,@types))) 0 font-lock-type-face)))))
35 (defvar 9ps-mode-syntax-table
36 (let ((st (make-syntax-table)))
37 (modify-syntax-entry ?\{ "(}" st)
38 (modify-syntax-entry ?\} "){" st)
39 (modify-syntax-entry ?\( "()" st)
41 ;; - and _ are word constituent
42 (modify-syntax-entry ?_ "w" st)
43 (modify-syntax-entry ?- "w" st)
45 ;; both single and double quotes makes strings
46 (modify-syntax-entry ?\" "\"" st)
47 (modify-syntax-entry ?' "'" st)
49 ;; one day we'll have escaping (maybe)
50 (modify-syntax-entry ?\\ "\\" st)
52 ;; add comments. lua-mode does something similar, so it shouldn't
53 ;; bee *too* wrong.
54 (modify-syntax-entry ?# "<" st)
55 (modify-syntax-entry ?\n ">" st)
57 ;; '==' as punctuation
58 (modify-syntax-entry ?= ".")
59 st))
61 (defun 9ps-indent-line ()
62 "Indent current line."
63 (let (indent
64 boi-p ;begin of indent
65 move-eol-p
66 (point (point)))
67 (save-excursion
68 (back-to-indentation)
69 (setq indent (car (syntax-ppss))
70 boi-p (= point (point)))
71 ;; don't indent empty lines if they don't have the in it
72 (when (and (eq (char-after) ?\n)
73 (not boi-p))
74 (setq indent 0))
75 ;; check whether we want to move to the end of line
76 (when boi-p
77 (setq move-eol-p t))
78 ;; decrement the indent if the first character on the line is a
79 ;; closer.
80 (when (or (eq (char-after) ?\))
81 (eq (char-after) ?\}))
82 (setq indent (1- indent)))
83 ;; indent the line
84 (delete-region (line-beginning-position)
85 (point))
86 (indent-to (* tab-width indent)))
87 (when move-eol-p
88 (move-end-of-line nil))))
90 (defvar 9ps-mode-abbrev-table nil
91 "Abbreviation table used in `9ps-mode' buffers.")
93 (define-abbrev-table '9ps-mode-abbrev-table
94 '())
96 ;;;###autoload
97 (define-derived-mode 9ps-mode prog-mode "9ps"
98 "Major mode for ninepscript files."
99 :abbrev-table 9ps-mode-abbrev-table
100 (setq font-lock-defaults 9ps--font-lock-defaults)
101 (setq-local comment-start "#")
102 (setq-local comment-start-skip "#+[\t ]*")
103 (setq-local indent-line-function #'9ps-indent-line)
104 (setq-local indent-tabs-mode t))
106 ;;;###autoload
107 (add-to-list 'auto-mode-alist '("\\.9ps" . 9ps-mode))
109 (provide '9ps-mode)
110 ;;; 9ps-mode.el ends here