;;; -*- Mode:LISP; Package:Zwei; Fonts:(CPTFONT); Base:10 -*- ;;; Copyright (C) Lisp Machine, Inc. 1984, 1985, 1986 ;;; See filename "Copyright" for ;;; licensing and release information. ;;; The routines responsible for retrieving and setting up nodes, and ;;; managing Gateway's internal data structures, including history ;;; lists and automatically generated scripts. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; ;;; ;;; ;;; DATA MANAGEMENT ROUTINES ;;; ;;; ;;; ;;; ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; SEEK-DATA-NODE ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Takes a script frame, which can be obtained in a variety of ways, and ;;; displays the data node named in the frame in the context of the script ;;; node named in the frame. (defun SEEK-DATA-NODE (script-frame &key backtrack &aux data-node-name data-node script-node-name script-node script-frame-to-display-from) ;;; If we've been handed something demonstrabably bogus ;;; (which of course could never happen) don't try to use it. (when (or (not script-frame) (not (typep script-frame 'array))) (barf "~% **** ERROR. CANNOT DISPLAY REQUESTED NODE. ****")) ;;; Perform the tests needed to validate the script frame. ;;; Note that if SCRIPT-NODE has been rebuilt by GET-NODE, ;;; we will automatically be transferred to the new version ;;; because SCRIPT-FRAME-TO-DISPLAY will have been drawn ;;; from it rather than from the old version. (setq data-node-name (script-frame-node-name script-frame) script-node-name (script-frame-script-name script-frame) data-node (get-node data-node-name 'complain 'throw) script-node (get-node script-node-name 'complain 'throw) script-frame-to-display-from (get-script-frame-for-node data-node-name script-node-name)) (unless script-frame-to-display-from (barf "~% **** ERROR. NODE: ~A ****~% **** NOT IN SCRIPT: ~A ****" (btrim (string-upcase (caddr data-node-name))) (btrim (string-upcase (caddr script-node-name))))) (gateway-display-node data-node script-frame-to-display-from :backtrack backtrack)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; GET-NODE ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Takes a nodename, and finds, sets up, and returns the node. ;;; The arguments tell what to do if the node cannot be found: ;;; complain-or-quiet: 'complain print an error message ;;; 'quiet don't print an error message ;;; throw-or-continue: 'throw throw to the Zmacs command loop ;;; 'continue return normally to point of call (defun GET-NODE (nodename complain-or-quiet throw-or-continue &aux pathname node-id node buffer name-string node-sections) (setq nodename (standardize-nodename nodename)) ;;; First check whether the node is already known (due to a prior call to get-node). ;;; If it is, return it immediately. (if (setq node (gethash nodename *node-hash-table*)) node ;;;Otherwise, try to find the node. If it can't be found, take the actions specified ;;;in the arguments. If it can, set it up and put it in the hash table. (setq pathname (make-absolute-pathname (car nodename))) (setq node-id (string-upcase (btrim (cadr nodename)))) ;;; Look for the file/buffer. (if (not (setq buffer (find-a-file-that-does-exist pathname))) (get-node-exception (format nil "~% **** FILE NOT FOUND: ~A ****" (send pathname :string-for-printing)) complain-or-quiet throw-or-continue) ;;; If the buffer needs resectionizing (due to editing) resectionize it. (when (gethash pathname *resectionize-p-hash-table*) (normalize-gateway-buffer buffer) (sectionize-file-buffer buffer) (puthash pathname nil *resectionize-p-hash-table*)) ;;; Look for the node in the buffer. (dolist (sect (send buffer :inferiors)) (setq name-string (send sect :name)) (if (string-equal (substring name-string 0 (- (length name-string) 4)) node-id) (setq node-sections (nconc node-sections (list sect))) (when node-sections (return)))) (if (not node-sections) (get-node-exception (format nil "~% **** NODE NOT FOUND: ~A ****" (btrim (string-upcase (caddr nodename)))) complain-or-quiet throw-or-continue) ;;;Set up the node and put it in the hash table, then return it. (setq node (make-node-from-node-sections nodename node-sections)) (puthash nodename node *node-hash-table*) node)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; CHECK-NODE-NONEXISTENT ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; The inverse of get-node, for use when the need is to be sure that ;;; a node does NOT exist. (defun CHECK-NODE-NONEXISTENT (nodename complain-or-quiet throw-or-continue) (when (get-node nodename 'quiet 'continue) (get-node-exception (format nil "~% ***** NODE ALREADY EXISTS *****") complain-or-quiet throw-or-continue))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; MAKE-NODE-FROM-NODE-SECTIONS ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Takes (from GET-NODE) a nodename and a list of the Zmacs sections that constitute the ;;; node. Creates a GNODE flavor instance and fills in all instance variables to reflect ;;; the node name and node sections. ;;; Script, Index, and Related Information data are converted into property lists, then ;;; into the form they will have when actually used. The original purpose of this ;;; indirection was to allow for the processing of nodes in various formats: conversion ;;; to a property list is done first, via whatever is the appropriate transform, after ;;; which Gateway can operate the same way irrespective of the original node syntax. ;;; Experience has shown that it would have been simpler to design a consistant ;;; Gateway-internal format for each section type, and convert directly to that in the ;;; first place. Hence the property-list method is a historical artifact. Only converters ;;; for Gateway syntax currently exist. (defun MAKE-NODE-FROM-NODE-SECTIONS (nodename node-sections &aux buffer scr ind rel fun node) (pkg-bind 'zwei (setq buffer (send (car node-sections) :superior)) ;;; Walk the sections (dolist (section node-sections) ;;; Get each section's name and value. (let* ((section-title (send section :name)) (type-string (substring section-title (- (string-length section-title) 4))) (contents (string-remove-fonts (string-interval (send section :first-bp) (send section :last-bp) t t)))) (cond ;;; Convert a script section to a property list. ((string-equal type-string ".scr") (setq scr "(") (do ((idx1 (string-search-char #/@ contents) (string-search-char #/@ contents (1+ idx1))) (idx2)) ((equal idx1 nil) (setq scr (read-from-string (string-append scr ")")))) (setq idx2 (string-search-char #/return contents idx1)) (multiple-value-bind (script-pathname script-name) (parse-script-reference (substring contents idx1 idx2) buffer) (setq scr (string-append scr (make-nodename script-pathname script-name)))))) ;;; Convert an index section to a property list. ((string-equal type-string ".ind") (setq ind "(") (do ((idx1 (string-search-char #/@ contents) (string-search-char #/@ contents (1+ idx1))) (idx2)) ((equal idx1 nil) (setq ind (read-from-string (string-append ind ")")))) (setq idx2 (string-search-char #/return contents idx1)) (multiple-value-bind (ignore index-element) (parse-script-reference (substring contents idx1 idx2) buffer) (setq ind (string-append ind (string-append "(/"" (btrim index-element) "/")")))))) ;;;Convert a related-information section to a property list. ((string-equal type-string ".see") (setq rel "(") (do ((idx1 (string-search-char #/@ contents) (string-search-char #/@ contents (1+ idx1))) (idx2)) ((equal idx1 nil) (setq rel (read-from-string (string-append rel ")")))) (setq idx2 (string-search-char #/return contents idx1)) (multiple-value-bind (related-information-pathname related-information-nodename) (parse-script-reference (substring contents idx1 idx2) buffer) (setq rel (string-append rel (make-nodename related-information-pathname related-information-nodename)))))) ;;;Fill out the instance variable for a function section ((string-equal type-string ".fun") (setq fun (read-from-string (nth-value 1 (function-start (send section :defun-line))))))))) ;;; Create and fill in the gnode flavor instance. (setq node (make-gnode :nodename nodename :related-information rel :script scr :index ind :function fun :sections node-sections)) ;;; Build a displayable/selectable script item list from a script property list. (when (gnode-script node) (script-item-list-setup node)) ;;; Build a displayable/selectable related-information ;;; item list from a related-information property list. (when (gnode-related-information node) (related-information-item-list-setup node)) ;;; Index item-lists are set up on demand; the above should be too. node)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; GET-NODE-EXCEPTION ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Called by GET-NODE when its argument is a nonexistent node, or ;;; check-node-nonexistent when its argument is an existing node, to take ;;; the exception-action specified in the call that produced the exception. (defun GET-NODE-EXCEPTION (message complain-or-quiet throw-or-continue) (cond ((and (eq complain-or-quiet 'complain) (eq throw-or-continue 'throw)) (barf message)) ((and (eq complain-or-quiet 'quiet) (eq throw-or-continue 'continue)) nil) ((and (eq complain-or-quiet 'complain) (eq throw-or-continue 'continue)) (tv:beep) (format *query-io* message) nil) ((and (eq complain-or-quiet 'quiet) (eq throw-or-continue 'throw)) (throw 'zwei-command-loop t)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; RELATED-INFORMATION-ITEM-LIST-SETUP ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Create a displayable/selectable related-information list from a ;;; related-information property list. (defun RELATED-INFORMATION-ITEM-LIST-SETUP (current-node &aux current-reference-frame) (let ((item-list nil)) (do* ((reference (gnode-related-information current-node)(cdr reference)) (end (length reference)(1- end)) (first-time t nil)) ((equal end 0) (alter-gnode current-node :related-information-item-list item-list) t) (if first-time (progn (setq current-reference-frame (make-script-frame :node-name (car reference)) item-list (nconc item-list (list (list "RELATED INFORMATION" :no-select nil :font fonts:bigfnt) (list (caddr (script-frame-node-name current-reference-frame)) :value current-reference-frame :font fonts:cptfont))))) (setf (script-frame-next current-reference-frame) (setq current-reference-frame (make-script-frame :previous current-reference-frame :node-name (car reference)))) (nconc item-list (list (list (caddr (script-frame-node-name current-reference-frame)) :value current-reference-frame :font fonts:cptfont))))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; UPDATE-HISTORY-LISTS ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Update relevant history lists to include the node/script designated ;;; (as a script frame) in the argument. (defun UPDATE-HISTORY-LISTS (script-frame &aux history-frame) (setq history-frame (create-history-frame-from-script-frame script-frame)) (cond ((gnode-script (get-node (history-frame-node-name history-frame) 'complain 'throw)) (setq *top-script-history-list* (update-a-history-list *top-script-history-list* history-frame)) (setq *top-full-history-list* (update-a-history-list *top-full-history-list* history-frame)) (when (edit-mode-p) (setq *top-editing-history-list* (update-a-history-list *top-editing-history-list* history-frame)))) (t (setq *top-data-node-history-list* (update-a-history-list *top-data-node-history-list* history-frame)) (setq *top-full-history-list* (update-a-history-list *top-full-history-list* history-frame)) (when (edit-mode-p) (setq *top-editing-history-list* (update-a-history-list *top-editing-history-list* history-frame)))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; UPDATE-A-HISTORY-LIST ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Update a particular history list (first argument) to include a ;;; history frame (second argument. (defun UPDATE-A-HISTORY-LIST (history-list history-frame &aux top-frame) (if (and (>= (length history-list) 2) (setq top-frame (caddr (cadr history-list))) (equal (history-frame-node-name history-frame) (history-frame-node-name top-frame)) (equal (history-frame-script-name history-frame) (history-frame-script-name top-frame))) history-list (let ((item-list-header (car history-list)) (item-list (cdr history-list))) (setq item-list (nconc (list item-list-header (list (cadr (history-frame-node-name history-frame)) :value history-frame :font fonts:hl12)) item-list))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; UPDATE-BACKTRACK-LIST ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Update the backtrack list to include a history frame. (defun UPDATE-BACKTRACK-LIST (script-frame &aux history-frame top-frame) (setq history-frame (create-history-frame-from-script-frame script-frame)) (unless (and (>= (length *backtrack-list*) 1) (setq top-frame (caddar *backtrack-list*)) (equal (history-frame-node-name history-frame) (history-frame-node-name top-frame)) (equal (history-frame-script-name history-frame) (history-frame-script-name top-frame))) (let ((new-item (list (cadr (history-frame-node-name history-frame)) :value history-frame :font fonts:hl12))) (push new-item *backtrack-list*)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; REDISPLAY-FULL-HISTORY-PANE ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Redisplay the current script pane so as to reflect the previous node and script. (defun REDISPLAY-FULL-HISTORY-PANE (&aux (frame-item-list (list nil))) (let ((first-entry (third (second *top-full-history-list*))) (second-entry (third (third *top-full-history-list*))) (third-entry (third (fourth *top-full-history-list*))) (fourth-entry (third (fifth *top-full-history-list*)))) (setq frame-item-list (nconc frame-item-list (list (list "FULL HISTORY" :value (ncons #/hyper-super-f) :font fonts:hl12b :documentation " DISPLAY A LIST OF ALL PREVIOUSLY SELECTED DATA AND SCRIPT NODES." )))) (if first-entry (setq frame-item-list (nconc frame-item-list (list (list (btrim (caddr (history-frame-node-name first-entry))) :value (ncons #/roman-i) :font fonts:hl12 :documentation "SELECT THIS ITEM FROM THE FULL HISTORY")))) (setq frame-item-list (nconc frame-item-list (list (list "" :no-select nil))))) (if second-entry (setq frame-item-list (nconc frame-item-list (list (list (btrim (caddr (history-frame-node-name second-entry))) :value (ncons #/roman-ii) :font fonts:hl12 :documentation "SELECT THIS ITEM FROM THE FULL HISTORY")))) (setq frame-item-list (nconc frame-item-list (list (list "" :no-select nil))))) (if third-entry (setq frame-item-list (nconc frame-item-list (list (list (btrim (caddr (history-frame-node-name third-entry))) :value (ncons #/roman-iii) :font fonts:hl12 :documentation "SELECT THIS ITEM FROM THE FULL HISTORY")))) (setq frame-item-list (nconc frame-item-list (list (list "" :no-select nil))))) (if fourth-entry (setq frame-item-list (nconc frame-item-list (list (list (btrim (caddr (history-frame-node-name fourth-entry))) :value (ncons #/roman-iv) :font fonts:hl12 :documentation "SELECT THIS ITEM FROM THE FULL HISTORY")))) (setq frame-item-list (nconc frame-item-list (list (list "" :no-select nil)))))) (send *full-history-pane* :set-item-list frame-item-list)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; REDISPLAY-CURRENT-SCRIPT-PANE ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Redisplay the current script pane so as to reflect the current node and script. (defun REDISPLAY-CURRENT-SCRIPT-PANE (&aux frame-item-list) (setq frame-item-list (list nil)) (setq frame-item-list (nconc frame-item-list (list (list "CURRENT SCRIPT" :value (ncons #/super-s) :font fonts:hl12b :documentation " DISPLAY THE CURRENT SCRIPT." )))) (if (script-frame-previous *current-script-frame*) (setq frame-item-list (nconc frame-item-list (list (list (btrim (caddr (script-frame-node-name (script-frame-previous *current-script-frame*)))) :value (ncons #/super-p) :font fonts:hl12 :documentation "SELECT THIS ITEM FROM THE CURRENT SCRIPT")))) (setq frame-item-list (nconc frame-item-list (list (list "" :no-select nil))))) (setq frame-item-list (nconc frame-item-list (list (list (btrim (caddr (script-frame-node-name *current-script-frame*))) :value (ncons #/super-=) :font fonts:hl12b :documentation "SELECT THIS ITEM FROM THE CURRENT SCRIPT")))) (when (script-frame-next *current-script-frame*) (setq frame-item-list (nconc frame-item-list (list (list (btrim (caddr (script-frame-node-name (script-frame-next *current-script-frame*)))) :value (ncons #/super-n) :font fonts:hl12 :documentation "SELECT THIS ITEM FROM THE CURRENT SCRIPT"))))) (when (and (script-frame-next *current-script-frame*) (script-frame-next (script-frame-next *current-script-frame*))) (setq frame-item-list (nconc frame-item-list (list (list (btrim (caddr (script-frame-node-name (script-frame-next (script-frame-next *current-script-frame*))))) :value (ncons #/hyper-super-hand-down) :font fonts:hl12 :documentation "SELECT THIS ITEM FROM THE CURRENT SCRIPT"))))) (send *current-script-pane* :set-item-list frame-item-list)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; HIGHLIGHT-CURRENT-SCRIPT ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Put into boldface the name of the current node in the item-list that is ;;; displayed when the current-script command is selected. (defun HIGHLIGHT-CURRENT-SCRIPT (&aux item-list) (setq item-list (cdr (gnode-script-item-list (get-node (script-frame-script-name *current-script-frame*) 'complain 'throw)))) (dolist (item item-list) (if (equal (third item) *current-script-frame*) (setf (fifth item) fonts:cptfontb) (setf (fifth item) fonts:cptfont)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; SCRIPT-ITEM-LIST-SETUP ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Create a displayable/selectable script item list from a script property list. ;;; Create the list of script frames that will embody the script. (defun SCRIPT-ITEM-LIST-SETUP (script &aux script-name current-script-frame) (setq script-name (gnode-nodename script)) (let ((item-list nil)) (do* ((new-script (gnode-script script)(cdr new-script)) (end (length new-script)(1- end)) (first-time t nil)) ((equal end 0) (alter-gnode script :script-item-list item-list) t) (if first-time (progn (setq current-script-frame (make-script-frame :script-name script-name :node-name (car new-script)) item-list (nconc item-list (list (list (caddr script-name) :no-select nil :font fonts:bigfnt) (list (caddr (script-frame-node-name current-script-frame)) :value current-script-frame :font fonts:cptfont)))) (alter-gnode script :first-script-frame current-script-frame)) (setf (script-frame-next current-script-frame) (setq current-script-frame (make-script-frame :script-name script-name :previous current-script-frame :node-name (car new-script)))) (nconc item-list (list (list (caddr (script-frame-node-name current-script-frame)) :value current-script-frame :font fonts:cptfont))))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; GET-SCRIPT-FRAME-FOR-HISTORY-FRAME ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Map a history frame back to the script frame (if any) that currently ;;; corresponds to it. The "currently" is significant because arbitrary ;;; changes to the data may have been made via editing since the history frame ;;; was created. (defun GET-SCRIPT-FRAME-FOR-HISTORY-FRAME (history-frame) (get-script-frame-for-node (history-frame-node-name history-frame) (history-frame-script-name history-frame))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; GET-SCRIPT-FRAME-FOR-NODE ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Search the script frames associated with a script looking for one that ;;; references a particular node. Return the frame if it is found, or nil. (defun GET-SCRIPT-FRAME-FOR-NODE (sought-nodename script-to-search &aux car-sought-nodename cadr-sought-nodename caddr-sought-nodename candidate-nodename candidate-script-frame) (setq car-sought-nodename (make-absolute-pathname (car sought-nodename))) (setq cadr-sought-nodename (btrim (cadr sought-nodename))) (setq caddr-sought-nodename (btrim (caddr sought-nodename))) (dolist (script-frame-item (gnode-script-item-list (get-node script-to-search 'complain 'throw))) (if (and (setq candidate-script-frame (caddr script-frame-item)) (setq candidate-nodename (script-frame-node-name candidate-script-frame)) (eq car-sought-nodename (make-absolute-pathname (car candidate-nodename))) (string-equal cadr-sought-nodename (btrim (cadr candidate-nodename))) (string-equal caddr-sought-nodename (btrim (caddr candidate-nodename)))) (return candidate-script-frame)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; SELECT-FROM-SCRIPT ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Display a node whose name was selected by mousing from a script (internal command). (defun SELECT-FROM-SCRIPT (&aux selected-line nodename script-frame) (tv:with-mouse-grabbed (turn-gateway-mouse-handling-off) (setq selected-line (get-source-script-line (nth-value 3 (mouse-char *window*)))) (if (or (not selected-line) (string-equal selected-line "")) (set-gateway-mouse-handling) (multiple-value-bind (script-pathname script-name) (parse-script-reference selected-line) (setq nodename (read-from-string (make-nodename script-pathname script-name)))) (if (string-equal (car nodename) "NIL") (set-gateway-mouse-handling) (if (not (get-node nodename 'complain 'continue)) (set-gateway-mouse-handling) (setq script-frame (get-script-frame-for-node nodename (script-frame-node-name *current-script-frame*))) (if (not script-frame) (set-gateway-mouse-handling) (seek-data-node script-frame))))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; GET-SOURCE-SCRIPT-LINE ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Maps a formatted line in the *SCRIPT-DISPLAY-BUFFER* to the unformatted line ;;; in the source script from which it was derived, and returns that line. ;;; The method is to count lines from the tops of the two buffers: the nth line ;;; in the unformatted buffer corresponds to the nth line in the formatted ;;; buffer. (defun GET-SOURCE-SCRIPT-LINE (line) (do ((display-line (bp-line (send *script-display-buffer* :first-bp)) (line-next display-line)) (real-line (line-next (send *script-source-section* :defun-line)) (line-next real-line)) (last-line (bp-line (send *script-display-buffer* :last-bp))) (success-flag) (done-flag)) (done-flag (return (and success-flag (line-previous real-line)))) (cond-every ((eq display-line line) (setq success-flag t) (setq done-flag t)) ((eq display-line last-line) (setq done-flag t))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; SELECT-VIA-REFERENCE ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Display a node whose name was selected by mousing a symbol or cross reference. (defun SELECT-VIA-REFERENCE (&aux ref type) (tv:with-mouse-grabbed (turn-gateway-mouse-handling-off) (multiple-value (ref type) (ref-under-mouse *window*)) (when (stringp ref) (setq ref (btrim ref))) (cond ((null ref) (set-gateway-mouse-handling)) ((eq type :node) (select-via-cross-reference ref)) ((eq type :symbol) (select-via-symbol ref)) (t (set-gateway-mouse-handling))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; SELECT-VIA-CROSS-REFERENCE ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Display a node whose name was selected by mousing a cross-reference. (defun SELECT-VIA-CROSS-REFERENCE (ref &aux node-from-ref script-from-ref) ;Evade the inconsistant processing of slashes by zapping them. (do ((i 0 (1+ i))) ((equal i (1- (string-length ref)))) (when (char-equal (aref ref i) #//) (setq ref (string-append (substring ref 0 i) (substring ref (1+ i)))))) (setq node-from-ref (if (string-equal (substring ref 0 1) "(") ref (string-append "(" (send (send *current-gateway-buffer* :pathname) :name) ")" ref))) (setq script-from-ref (gethash node-from-ref *node-script-hash-table*)) (unless script-from-ref (set-gateway-mouse-handling) (barf (format nil "~% **** NODE NOT FOUND: ~A ****" (string-upcase ref)))) (finish-selection-via-reference node-from-ref script-from-ref)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; SELECT-VIA-SYMBOL ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Display a node whose name was selected by mousing a symbol. (defun SELECT-VIA-SYMBOL (ref &aux translated-ref node-from-ref script-from-ref) (setq translated-ref (get (doc-symbol ref) :odm-node)) (unless translated-ref (set-gateway-mouse-handling) (barf (format nil "~% **** SYMBOL NOT FOUND: ~A ****" (string-upcase ref)))) (setq node-from-ref (car translated-ref)) (setq script-from-ref (cdr translated-ref)) (finish-selection-via-reference node-from-ref script-from-ref) (put-reference-at-top ref)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; FINISH-SELECTION-VIA-REFERENCE ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Finish displaying a node whose name was selected by mousing a symbol ;;; or cross reference. (defun FINISH-SELECTION-VIA-REFERENCE (node-from-ref script-from-ref &aux nodename scriptname script-frame) (multiple-value-bind (node-file node-id) (parse-script-reference node-from-ref) (setq nodename (read-from-string (make-nodename node-file node-id)))) (multiple-value-bind (script-file script-id) (parse-script-reference script-from-ref) (setq scriptname (read-from-string (make-nodename script-file script-id)))) (if (or (string-equal (car nodename) "NIL") (string-equal (car scriptname) "NIL") (not (get-node nodename 'complain 'continue)) (not (get-node scriptname 'complain 'continue))) (set-gateway-mouse-handling) (setq script-frame (get-script-frame-for-node nodename scriptname)) (if (not script-frame) (set-gateway-mouse-handling) (seek-data-node script-frame)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; PUT-REFERENCE-AT-TOP ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; When a node was selected by mousing a symbol, put the documentation of the ;;; symbol at the top of the screen. (defun put-reference-at-top (ref &aux (point (point)) car-point (ref-length (string-length ref)) last-line) (block nil (com-goto-beginning) (setq last-line (car (send *interval* :last-bp))) (tagbody search-for-reference (setq car-point (car point)) (when (and ( (string-length car-point) ref-length) (not (and (> (string-length car-point) ref-length) (not (char-equal (aref car-point ref-length) #/ )))) (= (ldb %%ch-font (aref car-point 0)) 3) (string-equal ref (substring car-point 0 ref-length))) (recenter-window *window* :start (point)) (return nil)) (when (eq car-point last-line) (com-goto-beginning) (barf (format nil "~% **** SYMBOL NOT FOUND: ~A ****" (string-upcase ref)))) (com-down-real-line) (com-beginning-of-line) (go search-for-reference)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; DOC-SYMBOL ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Convert a string to a symbol. (defun DOC-SYMBOL (token &key (start 0) (end (string-length token)) &aux colon-position) (ignore-errors (if (not (setq colon-position (string-search-char #\: token start end))) (intern-soft (string-upcase (string-remove-fonts (substring token start end)))) (let ((package (string-remove-fonts (substring token start colon-position))) (name (string-remove-fonts (substring token (1+ colon-position) end)))) (intern-soft (string-upcase name) (pkg-find-package (nstring-upcase package)))))))