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:
		
							parent
							
								
									2731861d46
								
							
						
					
					
						commit
						e81a0d8692
					
				
					 1 changed files with 124 additions and 24 deletions
				
			
		
							
								
								
									
										142
									
								
								pud.org
									
									
									
									
									
								
							
							
						
						
									
										142
									
								
								pud.org
									
									
									
									
									
								
							| 
						 | 
					@ -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 Petersen’s [[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 Petersen’s [[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
 | 
				
			||||||
Wouldn’t it be nice to be able to write commands in an Org file, and send the command to the connected Mud?
 | 
					Wouldn’t 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 I’m connected to more than one MUD, or at least, I often log in with two different characters as two different characters. Let’s have a function that can return all PUD buffers:
 | 
					Since I’m connected to more than one MUD, or at least, I often log in with two different characters as two different characters. Let’s 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 I’m 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=:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Let’s send the current line or region.
 | 
					Let’s 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 @@ Let’s send the current line or region.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Let’s be able to send the current Org block, where all lines in the block are smooshed together to create a single line:
 | 
					Let’s 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)))
 | 
				
			||||||
| 
						 | 
					@ -505,26 +524,107 @@ Let’s be able to send the current Org block, where all lines in the block are
 | 
				
			||||||
                        (rx (one-or-more space)) " " text))))
 | 
					                        (rx (one-or-more space)) " " text))))
 | 
				
			||||||
#+END_SRC
 | 
					#+END_SRC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* Evennia Mode
 | 
					And code so that we can =(require 'ob-evennia)= to get font-locking working in blocks.
 | 
				
			||||||
Make a simple mode for basic highlighting of =ev= code.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#+BEGIN_SRC emacs-lisp :tangle no
 | 
					#+BEGIN_SRC emacs-lisp :tangle ~/.emacs.d/elisp/ob-evennia.el
 | 
				
			||||||
  (define-derived-mode evennia-mode nil "Evennia"
 | 
					  (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
 | 
				
			||||||
 | 
					#+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.
 | 
					    "Major mode for editing evennia batch command files.
 | 
				
			||||||
      \\{evennia-mode-map}
 | 
					      \\{evennia-mode-map}
 | 
				
			||||||
      Turning on Evennia mode runs the normal hook `evennia-mode-hook'."
 | 
					      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)
 | 
					    (setq-local require-final-newline mode-require-final-newline)
 | 
				
			||||||
    (add-hook 'conevennia-menu-functions 'evennia-mode-conevennia-menu 10 t))
 | 
					    (setq-local comment-start "# ")
 | 
				
			||||||
 | 
					    (setq-local comment-start-skip "#+\\s-*"))
 | 
				
			||||||
  (defvar evennia-mode-font-lock-keywords
 | 
					 | 
				
			||||||
    `(,(rx line-start "@" (one-or-more alnum))
 | 
					 | 
				
			||||||
      )
 | 
					 | 
				
			||||||
    "Additional things to highlight in evennia output.")
 | 
					 | 
				
			||||||
#+END_SRC
 | 
					#+END_SRC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					And add it to org blocks:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#+BEGIN_SRC emacs-lisp :tangle no
 | 
				
			||||||
 | 
					  (add-to-list 'org-babel-load-languages '(evennia . t))
 | 
				
			||||||
 | 
					#+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:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue