Create an evennia-mode

And break out the org-blocks into an ob-evennia source file.

Allows us to have :session and C-c C-c evaluation behavior.

Probably doesn't work flawlessly, and will need tweaks on my main system.
This commit is contained in:
Howard Abrams 2025-08-08 19:08:29 -07:00
parent 2731861d46
commit e81a0d8692

148
pud.org
View file

@ -2,7 +2,7 @@
#+author: Howard X. Abrams #+author: Howard X. Abrams
#+date: 2025-01-18 #+date: 2025-01-18
#+filetags: emacs hamacs #+filetags: emacs hamacs
#+lastmod: [2025-06-09 Mon] #+lastmod: [2025-08-05 Tue]
A literate programming file for a Comint-based MUD client. A literate programming file for a Comint-based MUD client.
@ -30,13 +30,13 @@ A literate programming file for a Comint-based MUD client.
This project is a simple MUD client for Emacs, based on COM-INT MUD client I learn about on Mickey Petersens [[https://www.masteringemacs.org/article/comint-writing-command-interpreter][essay on Comint]]. This project is a simple MUD client for Emacs, based on COM-INT MUD client I learn about on Mickey Petersens [[https://www.masteringemacs.org/article/comint-writing-command-interpreter][essay on Comint]].
This uses eithr =ssh= or good ol =telnet= for the connection. Surprised that one can still install in on a Mac, like: This uses either =ssh= or good ol =telnet= for the connection. Surprised that one can still install =telnet= on a Mac, like:
#+BEGIN_SRC sh #+BEGIN_SRC sh
brew install telnet brew install telnet
#+END_SRC #+END_SRC
Use your favorite way to install Emacs packages, for instance, with Emacs 30, once can install it, and customize some settings in one go with =use-package=: Use your favorite way to install Emacs packages, for instance, with Emacs 30, one could install and customize settings in one go with =use-package=:
#+BEGIN_SRC emacs-lisp :tangle no :eval no #+BEGIN_SRC emacs-lisp :tangle no :eval no
(use-package pud (use-package pud
@ -428,9 +428,28 @@ Note that =comint-process-echoes=, depending on the mode and the circumstances,
* Org Babel * Org Babel
Wouldnt it be nice to be able to write commands in an Org file, and send the command to the connected Mud? Wouldnt it be nice to be able to write commands in an Org file, and send the command to the connected Mud?
#+begin_src emacs-lisp :exports none :tangle ~/.emacs.d/elisp/ob-evennia.el
;;; ob-evennia --- Evennia source blocks in Org -*- lexical-binding: t; -*-
;;
;; © 2025 Howard X. Abrams
;; Licensed under a Creative Commons Attribution 4.0 International License.
;; See http://creativecommons.org/licenses/by/4.0/
;;
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
;; Maintainer: Howard X. Abrams
;; Created: January 18, 2025
;;
;; While obvious, GNU Emacs does not include this file or project.
;;
;; *NB:* Do not edit this file. Instead, edit the original literate file at:
;; /Users/howard/src/hamacs/pud.org
;; And tangle the file to recreate this one.
;;
;;; Code:
#+end_src
Since Im connected to more than one MUD, or at least, I often log in with two different characters as two different characters. Lets have a function that can return all PUD buffers: Since Im connected to more than one MUD, or at least, I often log in with two different characters as two different characters. Lets have a function that can return all PUD buffers:
#+BEGIN_SRC emacs-lisp #+BEGIN_SRC emacs-lisp :tangle ~/.emacs.d/elisp/ob-evennia.el
(defun pud-get-all-buffers () (defun pud-get-all-buffers ()
"Return a list of all buffers with a live PUD connection." "Return a list of all buffers with a live PUD connection."
(save-window-excursion (save-window-excursion
@ -444,7 +463,7 @@ Since Im connected to more than one MUD, or at least, I often log in with two
And a wrapper around =completing-read= for choosing one of the buffers: And a wrapper around =completing-read= for choosing one of the buffers:
#+BEGIN_SRC emacs-lisp #+BEGIN_SRC emacs-lisp :tangle ~/.emacs.d/elisp/ob-evennia.el
(defun pud-current-world () (defun pud-current-world ()
"Return buffer based on user choice of current PUD connections." "Return buffer based on user choice of current PUD connections."
(let ((pud-buffers (pud-get-all-buffers))) (let ((pud-buffers (pud-get-all-buffers)))
@ -459,7 +478,7 @@ And a wrapper around =completing-read= for choosing one of the buffers:
Given a buffer and a string, use the =comint-send-string=: Given a buffer and a string, use the =comint-send-string=:
#+BEGIN_SRC emacs-lisp #+BEGIN_SRC emacs-lisp :tangle ~/.emacs.d/elisp/ob-evennia.el
(defun pud-send-string (buf-name text) (defun pud-send-string (buf-name text)
"Send TEXT to a comint buffer, BUF-NAME." "Send TEXT to a comint buffer, BUF-NAME."
(save-window-excursion (save-window-excursion
@ -472,7 +491,7 @@ Given a buffer and a string, use the =comint-send-string=:
Lets send the current line or region. Lets send the current line or region.
#+BEGIN_SRC emacs-lisp :results silent #+BEGIN_SRC emacs-lisp :tangle ~/.emacs.d/elisp/ob-evennia.el
(defun pud-send-line (world) (defun pud-send-line (world)
"Send the current line or region to WORLD." "Send the current line or region to WORLD."
(interactive (list (pud-current-world))) (interactive (list (pud-current-world)))
@ -491,7 +510,7 @@ Lets send the current line or region.
Lets be able to send the current Org block, where all lines in the block are smooshed together to create a single line: Lets be able to send the current Org block, where all lines in the block are smooshed together to create a single line:
#+BEGIN_SRC emacs-lisp #+BEGIN_SRC emacs-lisp :tangle ~/.emacs.d/elisp/ob-evennia.el
(defun pud-send-block (world) (defun pud-send-block (world)
"Send the current Org block to WORLD." "Send the current Org block to WORLD."
(interactive (list (pud-current-world))) (interactive (list (pud-current-world)))
@ -503,28 +522,109 @@ Lets be able to send the current Org block, where all lines in the block are
(pud-send-string world (pud-send-string world
(replace-regexp-in-string (replace-regexp-in-string
(rx (one-or-more space)) " " text)))) (rx (one-or-more space)) " " text))))
#+END_SRC #+END_SRC
And code so that we can =(require 'ob-evennia)= to get font-locking working in blocks.
#+BEGIN_SRC emacs-lisp :tangle ~/.emacs.d/elisp/ob-evennia.el
(require 'ob)
(defvar org-babel-default-header-args:evennia '())
(defun org-babel-execute:evennia (body params)
"Execute evennia BODY.
PARAMS can contain the following:
:session - The buffer to send the block
Called by `org-babel-execute-src-block'."
(let* ((session (cdr (assq :session params)))
(buffer (or session (pud-current-world))))
(if session
(setq buffer (format "*%s*" session)))
(pud-send-string buffer
(replace-regexp-in-string
(rx (one-or-more space)) " " body))
(message "No connected world.")))
(defun org-babel-prep-session:evennia (_session _params)
"Signal error; Evennia does not (currently) support sessions."
(error "Evennia sessions are nonsensical"))
(provide 'ob-evennia)
#+END_SRC
This should allow this client to simply =require= it:
#+BEGIN_SRC emacs-lisp
(require 'ob-evennia)
#+END_SRC
* Evennia Mode * Evennia Mode
Make a simple mode for basic highlighting of =ev= code. #+begin_src emacs-lisp :exports none :tangle ~/.emacs.d/elisp/evennia-mode.el
;;; evennia-mode --- Syntax coloring for Evennia code -*- lexical-binding: t; -*-
;;
;; © 2025 Howard X. Abrams
;; Licensed under a Creative Commons Attribution 4.0 International License.
;; See http://creativecommons.org/licenses/by/4.0/
;;
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
;; Maintainer: Howard X. Abrams
;; Created: January 18, 2025
;;
;; While obvious, GNU Emacs does not include this file or project.
;;
;; *NB:* Do not edit this file. Instead, edit the original literate file at:
;; /Users/howard/src/hamacs/pud.org
;; And tangle the file to recreate this one.
;;
;;; Code:
#+end_src
Make a simple mode for basic highlighting of =ev= code. Based on =ruby= (which seems to be close enough).
#+BEGIN_SRC emacs-lisp :tangle ~/.emacs.d/elisp/evennia-mode.el
(define-derived-mode evennia-mode ruby-mode "Evennia"
"Major mode for editing evennia batch command files.
\\{evennia-mode-map}
Turning on Evennia mode runs the normal hook `evennia-mode-hook'."
(setq-local require-final-newline mode-require-final-newline)
(setq-local comment-start "# ")
(setq-local comment-start-skip "#+\\s-*"))
#+END_SRC
And add it to org blocks:
#+BEGIN_SRC emacs-lisp :tangle no #+BEGIN_SRC emacs-lisp :tangle no
(define-derived-mode evennia-mode nil "Evennia" (add-to-list 'org-babel-load-languages '(evennia . t))
"Major mode for editing evennia batch command files.
\\{evennia-mode-map}
Turning on Evennia mode runs the normal hook `evennia-mode-hook'."
(setq-local comment-start "# ")
(setq-local comment-start-skip "#+\\s-*")
(setq-local require-final-newline mode-require-final-newline)
(add-hook 'conevennia-menu-functions 'evennia-mode-conevennia-menu 10 t))
(defvar evennia-mode-font-lock-keywords
`(,(rx line-start "@" (one-or-more alnum))
)
"Additional things to highlight in evennia output.")
#+END_SRC #+END_SRC
Final stuff to require to include this major-mode:
#+BEGIN_SRC emacs-lisp :tangle ~/.emacs.d/elisp/evennia-mode.el
;; Add the mode to the auto-mode-alist for specific file extensions
(add-to-list 'auto-mode-alist '("\\.ev\\'" . evennia-mode))
;; Provide the mode for use
(provide 'evennia-mode)
#+END_SRC
How does this look?
#+BEGIN_SRC evennia :tangle /tmp/testing.ev
# Comments, while not used much are comments.
@one two = "three" :four
#+END_SRC
This client can =require= to depend on this mode.
#+BEGIN_SRC emacs-lisp export none
(require 'evennia-mode)
#+END_SRC
* Technical Artifacts :noexport: * Technical Artifacts :noexport:
Let's =provide= a name so we can =require= this file: Let's =provide= a name so we can =require= this file: