#+TITLE: ed iting text files #+AUTHOR: screwtape Someone asked me what exactly it is that I do, especially since I asked for donations...! I will show you something I wrote that I use day to day. * Ed iting text :not_mine:context: If you are completely naked, cover yourself using ed(1). If you don't have access to ed, you have a problem. ** Ed is like this #+begin_src ksh ed test-ed #+end_src #+RESULTS: : test-ed: No such file or directory #+begin_src ed 0 a I thought what I'd do was . #+end_src This is the basic mechanism of ed. #+begin_src ed 1,$ p #+end_src #+RESULTS: : I thought what I'd do was Print from 1 to $ (end of file) could also be line numbers from 1 or simple regexes. (Appending to 0 will insert a line before 1; or you could i I guess.) #+begin_src ed 0 a Salinger quote: . #+end_src #+begin_src ed $ a I'd pretend I was one of those deaf-mutes. That was people wouldn't bother me. . #+end_src #+begin_src ed /Salinger/,/bother/ p #+end_src #+RESULTS: : Salinger quote: : I thought what I'd do was : I'd pretend I was one of those deaf-mutes. : That way people wouldn't bother me. #+begin_src ed /bother/ c That way I wouldn't have to have any goddam stupid useless conversations with anybody. . 1,$ p #+end_src #+RESULTS: : Salinger quote: : I thought what I'd do was : I'd pretend I was one of those deaf-mutes. : That way I wouldn't have to have any goddam stupid useless conversations : with anybody. ed is Ken Thompson's line editor. d, t and k are also very important letters. *** From man ed(1) HISTORY An ed command appeared in Version 1 AT&T UNIX. * How could something so beautiful possibly be improved upon? :not_mine:context: At Bell labs, Rob Pike wrote the editor sam, with input from Ken. Pike was also very interested in squeezing blood from turnips - er, I mean making a computer mouse useful to typing code. sam's default is a screen editor - an editor that fills your terminal with text, and pretends you are no longer writing into a terminal by playing with what's on the screen with lots of add-ins like CTAGS functionality and so forth. BUT sam -d provides a line editor like ed but with more sophisticated structural regexes and a few other improvements. sam -d is different enough to ed that you do need to read the sam -d (initial) section of Pike's tutorial. I won't repeat that tutorial here: http://doc.cat-v.org/bell_labs/sam_lang_tutorial/sam_tut.pdf [web though ..]. I'll mirror that on gopher later. * How could sam -d be better instead of being a windowing mouse bonanza like sam or acme? Alright, we got to something I wrote. ** Prereqs You've got to have plan9port. Fortunately, plan9port has probably been ported to your OS. That's kind of the point. (If you are actually on 9front figure it out yourself). On openbsd: #+begin_src ksh pkg_add plan9port #+end_src It builds basically anywhere, for example to port it to aarch64 simply add aarch64 to the openbsd makefile as a supported distribution (maybe there was one two line patch). ** THIS IS IT, MY PROGRAM #+begin_src lisp ;;;; sam-d.lisp (defpackage sam-d (:use cl cl-user)) (in-package sam-d) (defclass ext-proc () ((2way :accessor 2way) (proc :accessor proc))) (defclass sam-d (ext-proc) ((2sam :initform (list '|:-(|) :accessor 2sam) (fsam :initform (list '|:-)|) :accessor fsam) (dirty :initform nil :accessor dirty))) (defmethod shared-initialize :after ((obj sam-d) names &rest args) (declare (ignore unused names args)) (multiple-value-bind (2way unused proc) (ext:run-program "9" '("sam" "-d") :wait nil) (setf (slot-value obj '2way) 2way (slot-value obj 'proc) proc))) (defmethod wstrm ((obj sam-d)) (two-way-stream-output-stream (2way obj))) (defmethod rstrm ((obj sam-d)) (two-way-stream-input-stream (2way obj))) (defvar *sam-d* (make-instance 'sam-d)) (defun fin () (format (wstrm *sam-d*) "=~%") (force-output (wstrm *sam-d*)) (loop for line = (read-line (rstrm *sam-d*)) do (format t "~a~%" line) while (not (search "; #" line))) (when (listen (rstrm *sam-d*)) (loop for ch = (read-char-no-hang (rstrm *sam-d*)) while ch do (princ ch)))) (define-symbol-macro % (fin)) (defun sam (say) (format (wstrm *sam-d*) "~a~%" say) (force-output (wstrm *sam-d*))) (defun sam-reader (s c n) (declare (ignore c n)) '(progn (sam (coerce ',(loop for ch = (read-char s) while (not (and (char= ch #\#) (char= (peek-char nil s) #\]))) collecting ch finally (read-char-no-hang s)) 'string)) (fin))) (set-dispatch-macro-character #\# #\[ #'sam-reader) (defmacro 2s (&body body) '(with-input-from-string (s (format nil "#[~@{~a~^ ~}#]" ,@body)) (eval (read s)))) (defun rs (start end) (with-output-to-string (*standard-output*) (sam (format nil "~a,~a" start end)))) #+end_src *** To build #+begin_src lisp (compile-file "sam-d.lisp" :system-p t) (ext:install-c-compiler) (c:build-program "sam-d" :lisp-files '("sam-d.o")) (si:quiT) #+end_src #+begin_src ksh ecl --load make.lisp #+end_src * How is this so incredibly good? :explanation: sam -d is an incredibly powerful regex based line editor that was lacking a home. Being an alternative to Bill Joy's vi for C is not a home. Being stapled to ansi common lisp gives sam -d a purpose. Now what you are editing can be (compile-file "wrote-using-sam-d.lisp" :load t)'d from your REPL / program live. For ANSI common lisp, Guy Steele's dream of an ANSI common lisp editor was never really realized. But - stapling sam -d onto the standard as a reader macro domain specific language for line editing files... Now common lisp can really fly. * REPL Usage #+begin_src ksh rlwrap ./sam-d (print "we are in common lisp") #[!touch counter.lisp#] #[e counter.lisp#] #[a (defpackage cntr (:use cl cl-user)) (in-package cntr) (defvar *counter*) (setq *counter* (let ((count 0)) (lambda () (incf count)))) (setf (symbol-function 'my-count) *counter*) .#] (compile-file #p"counter.lisp" :load t) (loop for x from 1 to 10 do (print (cntr::my-count))) #[,#] #+end_src * Ironic aside I'm trying out adhering to emacs' org-mode's org file format so as to get its multiple exports like #+begin_src ksh emacsclient -a "" --eval '(progn (visit-file "post.org") (org-html-export-to-html) (kill-emacs))' #+end_src I see some people have fancy space-justified lines too. What do you think? That's probably another post topic. Concentrate on sam-d.lisp.