[net.sources] Emacs string completion

majka@ubc-vision.UUCP (Marc Majka) (08/02/85)

<Take and eat, these are my bits>

Here is an Mlisp string completion function for Unipress #264 Emacs.  It
behaves like get-tty-command except that it looks up permissible strings in
a buffer.  Lots of in-line comments to describe the algorithm.

It is supplied with a demo program called "animal".  Try it out!  Just save
the part below the CUT line, and execute-mlisp-buffer it.

Bug reports and suggestions to Marc Majka <majka@ubc-vision.UUCP>
or ...decvax!tektronix!uw-beaver!ubc-vision!majka

---
Marc Majka  - UBC Laboratory for Computational Vision

---   CUT   ---   CUT   ---   CUT   ---   CUT   ---   CUT   ---   CUT   ---
;
;************************************************************
;  Copyright (c) 1985                                       *
;  Marc S. Majka - UBC Laboratory for Computational Vision  *
;                                                           *
;  Permission is hereby granted to copy all or any part of  *
;  this program for non-commercial use.  The author's name  *
;  and this copyright notice must be included in any copy.  *
;************************************************************
;
; 
; NAME: get-word-in-buffer - get a line from a buffer, 
;       providing help and string completion.
; 
; SYNOPSIS: (get-word-in-buffer buffer-name prompt-string)
; 
; DESCRIPTION: get-word-in-buffer is designed to give MLISP
;              functions a mechanism for providing the user
;              with command completion for arbitrary sets of
;              strings.  The buffer argument should contain a
;              sorted list of strings.  get-word-in-buffer
;              prompts the user with the prompt argument, and
;              reads characters from the keyboard.  A <space>
;              character causes completion (or extension) to 
;              be invoked.  A "?" character causes a menu of
;              possible strings to be displayed.  The user input
;              sections are designed to mimic the EMACS built-in
;              completion commands, such as get-tty-file, 
;              get-tty-buffer, and get-tty-command.
; 
;              The completion (extension) algorithm proceeds by
;              moving two pointers, p1 and p2, from the beginning
;              and end of the buffer in order to "bracket" a 
;              region.  The top pointer, p1, is moved forward to
;              the first line in the buffer which has the current
;              user string as a prefix.  If no such line exists,
;              the last character in the user string is dropped
;              and the search is attempted again.  Similarly, p2
;              is moved to the last line containing the user 
;              string as a prefix.
; 
;              If the pointers meet, then there is a single line
;              in the buffer which matches the user's input, so
;              the string is completed.
;
;              If the pointers do not meet, then the string is
;              extended to be the longest possible prefix in the
;              bracketed region.
; 
; SYSTEM: This software runs on a UNIPRESS #264.  It should be easy
;         to convert to Gosling (change "error-occurred" to 
;         "error-occured").  GNU? forget it.  Note that it calls
;         /bin/pr to format the help window.
; 
(defun
    (get-word-in-buffer buf prompt str c found b s shelp
	(setq buf (arg 1 ": get-word-in-buffer buffer: "))
	(setq prompt (arg 2 (concat ": get-word-in-buffer buffer: "
				    buf " prompt: ")))
	(setq str "")
	(setq found 0)
	(setq c (getchar (concat prompt str)))
	(while (! found)
	       (setq str (concat str c))
; 
; space: push the pointers together, dropping unacceptable characters.
; 
	       (if (= c " ") 
		   (save-window-excursion p1 p2 str1 str2 c1 c2 len tstr
		       (setq str (substr str 1 (- (length str) 1)))
		       (setq tstr str)
		       (pop-to-buffer buf)
; top pointer (p1)
		       (beginning-of-file)
		       (while (error-occurred 
				  (re-search-forward (concat "^" str)))
			      (setq str (substr str 1 (- (length str) 1))))
		       (beginning-of-line)
		       (setq p1 (dot))
; bottom pointer (p2)
		       (end-of-file)
		       (while (error-occurred 
				  (re-search-reverse (concat "^" str)))
			      (setq str (substr str 1 (- (length str) 1))))
		       (beginning-of-line)
		       (setq p2 (dot))
; 
; test if any characters were dropped. if so, do nothing.
; 
		       (if (!= str tstr) (setq found 0)
			   (if (= p1 p2)
; 
; pointers met. found a unique string
; 
			       (progn
				     (set-mark)
				     (end-of-line)
				     (setq str (region-to-string))
				     (setq found 1))
; 
; pointers did not meet.  extend string
; 
			       (progn 
				      (setq len (+ 1 (length str)))
				      (goto-character p1)
				      (set-mark)
				      (end-of-line)
				      (setq str1 (region-to-string))
				      (goto-character p2)
				      (set-mark)
				      (end-of-line)
				      (setq str2 (region-to-string))
				      (setq c1 (substr str1 len 1))
				      (setq c2 (substr str2 len 1))
				      (while (= c1 c2)
					     (setq str (concat str c1))
					     (setq len (+ len 1))
					     (setq c1 (substr str1 len 1))
					     (setq c2 (substr str2 len 1)))
				      (setq found 0))))))
; 
; backspace: delete last string character
; 
	       (if (= c "") 
		   (setq str (substr str 1 (- (length str) 2))))
; 
; del: erase string
; 
	       (if (= c "") 
		   (setq str ""))
; 
; ^G: abort
; 
	       (if (= c "") 
		   (error-message "Aborted."))
; 
; return: force the current string to be returned
; 
	       (if (= c "
") 
		   (progn
			 (setq str (substr str 1 (- (length str) 1)))
			 (setq found 1)))
; 
; question: construct a list of possible extensions
; 
	       (if (= c "?") 
		   (progn cw
; 
; pull the bracketed section out of the buffer
; 
			 (save-window-excursion p1 p2 
			     (setq str (substr str 1 (- (length str) 1)))
			     (pop-to-buffer buf)
			     (beginning-of-file)
			     (while (error-occurred 
					(re-search-forward (concat "^" str)))
				    (setq str 
					  (substr str 1 (- (length str) 1))))
			     (beginning-of-line)
			     (set-mark)
			     (end-of-file)
			     (while (error-occurred 
					(re-search-reverse (concat "^" str)))
				    (setq str
					  (substr str 1 (- (length str) 1))))
			     (next-line)
			     (beginning-of-line)
			     (setq shelp (region-to-string)))
; 
; make the help window
; 
			 (setq cw (current-buffer-name))
			 (pop-to-buffer "Help")
			 (setq needs-checkpointing 0)
			 (erase-buffer)
			 (insert-string shelp)
			 (beginning-of-file)
			 (set-mark)
			 (end-of-file)
			 (fast-filter-region "/bin/pr -3 -l1 -t")
			 (beginning-of-file)
			 (insert-string "Choose one of the following:\n")
			 (pop-to-buffer cw)))
; 
; get another character from the user
; 
	       (if (! found)
		   (setq c (getchar (concat prompt str)))))
	str))

; 
; getchar - prompt the user for a single character
; 
(defun
    (getchar c
	(save-window-excursion
	    (pop-to-buffer "  Minibuf")
	    (erase-buffer)
	    (message (arg 1))
	    (sit-for 0)
	    (end-of-file)
	    (setq c (char-to-string (get-tty-character)))
	    (erase-buffer)
	    c)))

; 
; test/demo function
; 
(defun 
    (animal str
	 (setq str (get-word-in-buffer "XanimX" ": animal "))
	 (message "You chose " str)))

; 
; my favorite animals
; 
(save-window-excursion
    (pop-to-buffer "XanimX")
    (setq needs-checkpointing 0)
    (erase-buffer)
    (insert-string "aardvark\n")
    (insert-string "ant\n")
    (insert-string "bat\n")
    (insert-string "bear\n")
    (insert-string "bumblebee\n")
    (insert-string "cat\n")
    (insert-string "catfish\n")
    (insert-string "cow\n")
    (insert-string "dog\n")
    (insert-string "duck\n")
    (insert-string "elephant\n")
    (insert-string "emu\n")
    (insert-string "ferret\n")
    (insert-string "frog\n")
    (insert-string "gnu\n")
    (insert-string "goat\n")
    (insert-string "horse\n")
    (insert-string "hound\n")
    (insert-string "indigo bunting\n")
    (insert-string "jackrabbit\n")
    (insert-string "koala\n")
    (insert-string "llama\n")
    (insert-string "moose\n")
    (insert-string "mouse\n")
    (insert-string "newt\n")
    (insert-string "ostrich\n")
    (insert-string "pig\n")
    (insert-string "porqupine\n")
    (insert-string "quahaug\n")
    (insert-string "rat\n")
    (insert-string "spider\n")
    (insert-string "teal\n")
    (insert-string "unicorn\n")
    (insert-string "vampire\n")
    (insert-string "wolf\n")
    (insert-string "wombat\n")
    (insert-string "yeti\n")
    (insert-string "zebra\n"))