add retroforth.el emacs mode

FossilOrigin-Name: ab48fb1417a31f11dac8a7ad174c1f317c916e7e114f0f6e4db9417d175f72e3
This commit is contained in:
philippebrochard 2021-03-30 20:41:40 +00:00
parent 6a4aaf8eac
commit 8aeb775ff8

285
retroforth.el Normal file
View file

@ -0,0 +1,285 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; retroforth-mode for emacs
;; version: 0.01
;; RETRO 12 syntax
;;
;; ----------------------------------------------------------
;; Copyright (c) 2021 Philippe Brochard <hocwp@free.fr>
;;
;; Permission to use, copy, modify, and/or distribute this software
;; for any purpose with or without fee is hereby granted, provided
;; that the above copyright notice and this permission notice appear
;; in all copies.
;;
;; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
;; WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
;; WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
;; AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
;; CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
;; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
;; NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
;; CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
;; ----------------------------------------------------------
;; ( http://en.wikipedia.org/wiki/ISC_license )
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; usage : add this to your .emacs file:
;;
;; (add-to-list 'load-path <path/to/retroforth.el>)
;; (require 'retroforth)
;;
;; files in *.retro will be open in retroforth mode
;;
;; interactions:
;;
;; C-M-x retroforth-eval-block-region
;; C-c C-k forth-kill
;; C-c C-f forth-restart
;; C-c : forth-eval
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; changelog
;;
;; 2021-03-30 v. 0.01 hocwp
;; retroforth-mode for emacs
;; limited to basic syntax highlighting
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; implementation
;;
;----------------------------------------------------------
; forth-mode require for basic usage already defined in this mode:
;
(require 'forth-mode)
;----------------------------------------------------------
; retroforth groups definitions
;
(defgroup retroforth nil
"Major mode for editing and running RETRO Forth."
:prefix "retrofoth-"
:link '(url-link "http://www.retroforth.org/"))
(defgroup retroforth-lock-faces nil
"Major mode for editing and running RETRO Forth."
:prefix "retrofoth-"
:group 'retroforth
:link '(url-link "http://www.retroforth.org/"))
;----------------------------------------------------------
; tables
; start with empty syntax and abbrev tables
;
(defvar retroforth-mode-syntax-table (make-syntax-table) "")
(defvar retroforth-mode-abbrev-table (make-abbrev-table) "")
(defvar retroforth-block-regex "~~~\\|```")
;----------------------------------------------------------
; face definitions for syntax highlighting
; ( instead of editing the colors here, use M-x customize-face )
;
;;; Markdown faces
(defface retroforth-markdown-title-face
'((t (:foreground "blue")))
"Face for retroforth mode."
:group 'retroforth-lock-faces)
(defface retroforth-markdown-italic-face
'((t (:inherit italic)))
"Face for italic text."
:group 'retroforth-lock-faces)
(defface retroforth-markdown-bold-face
'((t (:inherit bold)))
"Face for retroforth mode."
:group 'retroforth-lock-faces)
(defface retroforth-markdown-inline-code-face
'((t (:foreground "dark cyan")))
"Face for retroforth mode."
:group 'retroforth-lock-faces)
;;; Code faces
(defface retroforth-block-highlight
'((t (:background "seashell" :extend t)))
"Face for retroforth mode."
:group 'retroforth-lock-faces)
(defface retroforth-define-face
'((t (:foreground "red" :inherit retroforth-block-highlight)))
"Face for retroforth mode."
:group 'retroforth-lock-faces)
(defface retroforth-compile-face
'((t (:foreground "green4" :inherit retroforth-block-highlight)))
"Face for retroforth mode."
:group 'retroforth-lock-faces)
(defface retroforth-execute-face
'((t (:foreground "yellow4" :inherit retroforth-block-highlight)))
"Face for retroforth mode."
:group 'retroforth-lock-faces)
(defface retroforth-number-face
'((t (:foreground "dark blue" :inherit retroforth-block-highlight)))
"Face for retroforth mode."
:group 'retroforth-lock-faces)
(defface retroforth-string-face
'((t (:foreground "VioletRed4" :inherit retroforth-block-highlight)))
"Face for retroforth mode."
:group 'retroforth-lock-faces)
(defface retroforth-comment-face
'((t (:foreground "grey40" :inherit retroforth-block-highlight)))
"Face for retroforth mode."
:group 'retroforth-lock-faces)
(defface retroforth-bracket-face
'((t (:foreground "darkorange3" :inherit retroforth-block-highlight)))
"Face for retroforth mode."
:group 'retroforth-lock-faces)
(defface retroforth-code-face
'((t (:foreground "grey40" :inherit retroforth-block-highlight)))
"Face for retroforth mode."
:group 'retroforth-lock-faces)
(defface retroforth-var-face
'((t (:foreground "dark magenta" :inherit retroforth-block-highlight)))
"Face for retroforth mode."
:group 'retroforth-lock-faces)
(defface retroforth-keyword-face
'((t (:foreground "dark blue" :inherit retroforth-block-highlight)))
"Face for retroforth mode."
:group 'retroforth-lock-faces)
(defface retroforth-highlight-face
'((t (:background "azure2" :extend t)))
"Face for retroforth mode."
:group 'retroforth-lock-faces)
(defun defprefixhighlight (prefix face)
(cons (format "\\(^\\|[ \n\t]\\)%s[^ \n\t]+" prefix) `(0 ',face t)))
(setq retroforth-highlights
(let* ((keywords '("bye" "TIB" "abort" "include" "FREE" "dump-stack" "reset"
"tab" "sp" "nl" "unhook" "set-hook" "hook" "indexed-times"
"K" "J" "I" "does" "curry" "reorder" "STRINGS" "TempStringMax"
"TempStrings" "---reveal---" "ScopeList" "copy" "allot" "mod"
"rot" "-if;" "if;" "gteq?" "lteq?" "not" "case" "FALSE" "TRUE"
"times" "until" "while" "tri@" "tri*" "tri" "bi@" "bi*" "bi" "sip"
"dip" "dup-pair" "?dup" "drop-pair" "nip" "over" "tuck" "const"
"var" "var-n" "here" "compiling?" "primitive" "data" "immediate"
"reclass" "depth" "EOM" "Version" "interpret" "again" "repeat" "Dictionary"
"Heap" "Compiler" "-if" "if" "choose" "store-next" "fetch-next" "pop"
"push" "shift" "xor" "or" "and" "/mod" "store" "fetch"
"gt?" "lt?" "-eq?" "eq?" "call" "swap" "drop" "dup"))
(keywords-regexp (regexp-opt keywords 'words)))
`(("\\(~~~\\|```\\)\\(.\\|\n\\)*?\\(~~~\\|```\\)" . (0 'retroforth-block-highlight t))
("[]{}\\[]" . (0 'retroforth-bracket-face t))
("^#.*$" . (0 'retroforth-markdown-title-face t))
(,keywords-regexp . (0 'retroforth-keyword-face t))
(" \\*.*\\*" . (0 'retroforth-markdown-bold-face t))
(" _.*_" . (0 'retroforth-markdown-italic-face t))
(" `.*`" . (0 'retroforth-markdown-inline-code-face t))
,(defprefixhighlight "\\w+:" 'retroforth-compile-face)
,(defprefixhighlight "#[0-9]+" 'retroforth-number-face)
,(defprefixhighlight "\\." 'retroforth-number-face)
("\\$." (0 'retroforth-number-face t))
,(defprefixhighlight "'" 'retroforth-string-face)
,(defprefixhighlight ":" 'retroforth-define-face)
(" ;" . (0 'retroforth-define-face t))
,(defprefixhighlight "(" 'retroforth-comment-face)
,(defprefixhighlight "&" 'retroforth-var-face)
,(defprefixhighlight "@" 'retroforth-var-face)
,(defprefixhighlight "!" 'retroforth-var-face))))
;----------------------------------------------------------
; forth mode interactions
;
(defun retroforth-interaction-send (&rest strings)
(forth-scrub (or (apply #'forth-interaction-send-raw-result strings)
"OK: No output")))
(defun retroforth-eval (string)
(interactive "sForth expression: ")
(message "%s" (retroforth-interaction-send string)))
(defun retroforth-eval-region (start end)
(interactive "r")
(retroforth-eval (buffer-substring start end)))
(defun retroforth-eval-block-region ()
(interactive)
(save-excursion
(re-search-backward retroforth-block-regex) (next-line)
(beginning-of-line)
(let ((beg (point)))
(re-search-forward retroforth-block-regex)
(beginning-of-line)
(pulse-momentary-highlight-region beg (point) 'retroforth-highlight-face)
(retroforth-eval-region beg (point)))))
(defvar retroforth-mode-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "C-M-x") 'retroforth-eval-block-region)
(define-key map (kbd "C-c C-k") 'forth-kill)
(define-key map (kbd "C-c C-f") 'forth-restart)
(define-key map (kbd "C-c :") 'forth-eval)
map))
;----------------------------------------------------------
; blocks highlight function
;
(defun retroforth-font-lock-extend-region ()
"Extend the search region to include an entire block of text."
;; Avoid compiler warnings about these global variables from font-lock.el.
;; See the documentation for variable `font-lock-extend-region-functions'.
(eval-when-compile (defvar font-lock-beg) (defvar font-lock-end))
(save-excursion
(goto-char font-lock-beg)
(let ((found (or (re-search-backward "\n\n" nil t) (point-min))))
(goto-char font-lock-end)
(when (re-search-forward "\n\n" nil t)
(beginning-of-line)
(setq font-lock-end (point)))
(setq font-lock-beg found))))
;----------------------------------------------------------
; retroforth mode
;
(define-derived-mode retroforth-mode text-mode "retroforth"
"major mode for editing RETRO Forth language code."
(setq font-lock-defaults '(retroforth-highlights))
(set (make-local-variable 'font-lock-multiline) t)
(add-hook 'font-lock-extend-region-functions
'retroforth-font-lock-extend-region)
(use-local-map retroforth-mode-map))
(setq auto-mode-alist (cons '("\\.retro\\'" . retroforth-mode)
auto-mode-alist))
(provide 'retroforth)
;; end.