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, but only when they don't have the
72 ;; cursor 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 (and (eq (char-after) ?\n)
78 boi-p)
79 (setq move-eol-p t))
80 ;; decrement the indent if the first character on the line is a
81 ;; closer.
82 (when (or (eq (char-after) ?\))
83 (eq (char-after) ?\}))
84 (setq indent (1- indent)))
85 ;; indent the line
86 (delete-region (line-beginning-position)
87 (point))
88 (indent-to (* tab-width indent)))
89 (when move-eol-p
90 (move-end-of-line nil))))
92 (defvar 9ps-mode-abbrev-table nil
93 "Abbreviation table used in `9ps-mode' buffers.")
95 (define-abbrev-table '9ps-mode-abbrev-table
96 '())
98 ;;;###autoload
99 (define-derived-mode 9ps-mode prog-mode "9ps"
100 "Major mode for ninepscript files."
101 :abbrev-table 9ps-mode-abbrev-table
102 (setq font-lock-defaults 9ps--font-lock-defaults)
103 (setq-local comment-start "#")
104 (setq-local comment-start-skip "#+[\t ]*")
105 (setq-local indent-line-function #'9ps-indent-line)
106 (setq-local indent-tabs-mode t))
108 ;;;###autoload
109 (add-to-list 'auto-mode-alist '("\\.9ps" . 9ps-mode))
111 (provide '9ps-mode)
112 ;;; 9ps-mode.el ends here