Download
76 lines 3 KiBEmacsLispModified 2025-04-21 raw
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
(defvar tomo-mode-hook nil)

(defvar tomo-keywords
  '("if" "else" "for" "in" "while" "return" "skip" "stop" "break" "continue" "repeat"
    "struct" "enum" "lang" "when" "is" "func" "pass" "assert"))

(defvar tomo-types
  '("Int" "Int64" "Int32" "Int16" "Int8" "Byte" "Num" "Num32" "Bool" "Text" "Void" "Abort"))

(defvar tomo-constants
  '("yes" "no" "none"))

(defvar tomo-operators
  '("+" "-" "*" "/" "%" "==" "!=" "<" ">" "<=" ">=" "!" ":=" ":" "=" "+=" "-=" "*=" "/="))

(defvar tomo-font-lock
  `((,(regexp-opt tomo-keywords 'words) . font-lock-keyword-face)
    (,(regexp-opt tomo-types 'words) . font-lock-type-face)
    (,(regexp-opt tomo-constants 'words) . font-lock-constant-face)
    (,(regexp-opt '("and" "or" "xor" "_min_" "_max_" "mod" "mod1") 'words) . font-lock-builtin-face)
    (,(regexp-opt tomo-operators 'words) . font-lock-builtin-face)
    ("\\<[0-9]+\\(\\.[0-9]+\\)?\\([eE][+-]?[0-9]+\\)?\\>" . font-lock-constant-face) ; numbers
    ("\\<0x[0-9A-Fa-f]+\\>" . font-lock-constant-face) ; hex
    ("\\<0b[01]+\\>" . font-lock-constant-face) ; binary
    ("\\<0o[0-7]+\\>" . font-lock-constant-face) ; octal
    ("\\<[a-zA-Z_][a-zA-Z0-9_]*\\s-*(" . font-lock-function-name-face) ; function calls
    ("\"" ; text with interpolation
     (0 font-lock-string-face)
     ("\\(\\$[a-zA-Z_][a-zA-Z0-9_]*\\)" ; Simple var interpolation
      (string-match-p "[^\\]\"" (match-string 0)) nil  ; Only within strings
      (1 font-lock-variable-name-face t))
     ("\\(\\$([^)]*)\\)" ; Expression interpolation
      (string-match-p "[^\\]\"" (match-string 0)) nil  ; Only within strings
      (1 font-lock-preprocessor-face t)))
    )) ; function calls

(defun should-indent-tomo ()
  (let ((tomo-indent-keywords '("if" "else" "repeat" "when" "is" "convert" "lang" "struct" "enum" "while" "for" "func")))
    (seq-some (lambda (kw) (looking-at (concat "^[ \t]*" kw))) tomo-indent-keywords)))

(defun tomo-newline-and-indent ()
  "Insert a newline and indent the next line if it's a block-starting line."
  (interactive)
  (let ((cur-indent (current-indentation)))
    (let ((next-line-indent
            (save-excursion
              (beginning-of-line)
              (if (should-indent-tomo) (+ cur-indent 4) cur-indent))))
      (newline)
      (indent-line-to next-line-indent))))

(defvar tomo-mode-syntax-table
  (let ((st (make-syntax-table)))
    ;; Define '#' as comment start character
    (modify-syntax-entry ?# "<" st)
    ;; Define newline as comment end character
    (modify-syntax-entry ?\n ">" st)
    ;; Other syntax entries...
    st)
  "Syntax table for tomo-mode.")

;;;###autoload
(define-derived-mode tomo-mode prog-mode "Tomo"
  "Major mode for editing Tomo source files."
  :syntax-table tomo-mode-syntax-table
  (setq font-lock-defaults '((tomo-font-lock)))
  (setq comment-start "#")
  (setq comment-end "")
  (local-set-key (kbd "RET") 'tomo-newline-and-indent)
  (setq-local indent-tabs-mode nil)
  (setq-local tab-width 4))

;;;###autoload
(add-to-list 'auto-mode-alist '("\\.tm\\'" . tomo-mode))

(provide 'tomo-mode)