branch: externals/idlwave commit 7aa230823c095731764b9b74abe9910eb9a983b8 Author: JD Smith <jdtsm...@gmail.com> Commit: JD Smith <jdtsm...@gmail.com>
Overhaul command sending. Commands are now placed on 'current-command' as a list, which is consulted for post-command-hook, hid status, show-if-error, and redisplay. This is reset when the command completes (next prompt is received), but saved in 'completed-command', for example to trim input from the command output. Post-command-hooks are not forced onto the command queue now; they can for example 'wait for a command to finish. Redisplay is new, and sets when to display the line. If it is 'disable, prevents displaying line except for major errors. --- idlw-shell.el | 313 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 159 insertions(+), 154 deletions(-) diff --git a/idlw-shell.el b/idlw-shell.el index cfc129c02a..2bfb7e95fb 100644 --- a/idlw-shell.el +++ b/idlw-shell.el @@ -736,21 +736,9 @@ the directory stack.") (defvar idlwave-shell-command-output nil "String for accumulating current command output.") -(defvar idlwave-shell-post-command-hook nil - "Lisp list expression or function to run when an IDL command is finished. -The current command is finished when the IDL prompt is displayed. -This is evaluated if it is a list or called with funcall.") - (defvar idlwave-shell-sentinel-hook nil "Hook run when the IDL process exits.") -(defvar idlwave-shell-hide-output nil - "If non-nil the process output is not inserted into the output buffer.") - -(defvar idlwave-shell-show-if-error nil - "If non-nil the process output is inserted into the output buffer if -it contains an error message, even if hide-output is non-nil.") - (defvar idlwave-shell-accumulation nil "Accumulate last line of output.") @@ -760,13 +748,25 @@ it contains an error message, even if hide-output is non-nil.") (defvar idlwave-shell-pending-commands nil "List of commands to be sent to IDL. -Each element of the list is list of \(CMD PCMD HIDE\), where CMD is a -string to be sent to IDL and PCMD is a post-command to be placed on -`idlwave-shell-post-command-hook'. If HIDE is non-nil, hide the output -from command CMD. PCMD and HIDE are optional.") +Each element of the list is list of \(CMD PCMD HIDE SHOW-IF-ERROR +REDISPLAY\), where CMD is a string to be sent to IDL and PCMD is +a post-command to be called after CMD completes. If HIDE is +non-nil, hide the output from command CMD. If SHOW-IF-ERROR is +non-nil, show the full output if it contains an error. If +REDISPLAY is non-nil, clear the current stopped line position if +no position is recognized (unless it is 'disable, in which case +don't update line position unless an error is found). PCMD, +HIDE, and SHOW-IF-ERROR are optional.") (defvar idlwave-shell-current-command nil - "Current command being executed.") + "Current command being executed. +A list consisting of a single element from the list of pending +commands, `idlwave-shell-pending-commands'.") + +(defvar idlwave-shell-completed-command nil + "The most recently completed command. +Same format as current-command. Corresponds to command-output.") + (defun idlwave-shell-buffer () "Name of buffer associated with IDL process. @@ -1026,8 +1026,7 @@ IDL has currently stepped.") (setq idlwave-shell-ready nil) (setq idlwave-shell-bp-alist nil) (idlwave-shell-update-bp-overlays) ; Throw away old overlays - (setq idlwave-shell-post-command-hook nil ;clean up any old stuff - idlwave-shell-sources-alist nil) + (setq idlwave-shell-sources-alist nil) (setq idlwave-shell-default-directory default-directory) (setq idlwave-shell-hide-output nil) @@ -1277,21 +1276,22 @@ Return either nil or 'hide." (defun idlwave-shell-send-command (&optional cmd pcmd hide preempt - show-if-error) - "Send a command to IDL process. + show-if-error redisplay) + "Send a command to the IDL process. -\(CMD PCMD HIDE\) are placed at the end of `idlwave-shell-pending-commands'. -If IDL is ready the first command in `idlwave-shell-pending-commands', -CMD, is sent to the IDL process. +\(CMD PCMD HIDE SHOW-IF-ERROR REDISPLAY\) are placed at the +end of `idlwave-shell-pending-commands'. If IDL is ready the +first command in `idlwave-shell-pending-commands', CMD, is sent +to the IDL process. If optional second argument PCMD is non-nil it will be placed on `idlwave-shell-post-command-hook' when CMD is executed. -If the optional third argument HIDE is non-nil, then hide output from -CMD, unless it is the symbol 'mostly, in which case only output -beginning with \"%\" is hidden, and all other output (i.e., the -results of a PRINT command), is shown. This helps with, e.g., -stepping through code with output. +If the optional third argument HIDE is non-nil, then hide output +from CMD, unless it is the symbol 'mostly, in which case only +output beginning with \"%\" is hidden, and all other +output (i.e., the results of a PRINT command), is shown. This +helps with, e.g., stepping through code with output. If optional fourth argument PREEMPT is non-nil CMD is put at front of `idlwave-shell-pending-commands'. If PREEMPT is 'wait, wait for all @@ -1299,15 +1299,13 @@ output to complete and the next prompt to arrive before returning \(useful if you need an answer now\). IDL is considered ready if the prompt is present and if `idlwave-shell-ready' is non-nil. -If SHOW-IF-ERROR is non-nil, show the output if it contains an error -message, independent of what HIDE is set to." +If SHOW-IF-ERROR is non-nil, show the output if it contains an +error message, independent of what HIDE is set to. -; (setq hide nil) ; FIXME: turn this on for debugging only -; (if (null cmd) -; (progn -; (message "SENDING Pending commands: %s" -; (prin1-to-string idlwave-shell-pending-commands))) -; (message "SENDING %s|||%s" cmd pcmd)) +If REDISPLAY is 'disable, disable line redisplay for all but +errors. If REDISPLAY is otherwise non-nil, clear the current +line position as state is scanned if no stop line message is +recognized." (if (and (symbolp idlwave-shell-show-commands) (eq idlwave-shell-show-commands 'everything)) (setq hide nil)) @@ -1333,38 +1331,30 @@ message, independent of what HIDE is set to." (setq idlwave-shell-pending-commands (if preempt ;; Put at front. - (append (list (list cmd pcmd hide show-if-error)) + (append (list (list cmd pcmd hide show-if-error redisplay)) idlwave-shell-pending-commands) ;; Put at end. (append idlwave-shell-pending-commands - (list (list cmd pcmd hide show-if-error)))))) + (list (list cmd pcmd hide show-if-error redisplay)))))) ;; Check if IDL ready (let ((save-point (point-marker))) (goto-char (process-mark proc)) (if (and idlwave-shell-ready ;; Check for IDL prompt (prog2 - (forward-line 0) - ;; (beginning-of-line) ; Changed for Emacs 21 - (looking-at idlwave-shell-prompt-pattern) + (forward-line 0) + (looking-at idlwave-shell-prompt-pattern) (goto-char (process-mark proc)))) ;; IDL ready for command, execute it (let* ((lcmd (car idlwave-shell-pending-commands)) (cmd (car lcmd)) (pcmd (nth 1 lcmd)) - (hide (nth 2 lcmd)) - (show-if-error (nth 3 lcmd))) + (hide (nth 2 lcmd))) ;; If this is an executive command, reset the stack pointer (if (eq (string-to-char cmd) ?.) (setq idlwave-shell-calling-stack-index 0)) - (setq idlwave-shell-current-command cmd) - ;; Set post-command - (setq idlwave-shell-post-command-hook pcmd) - ;; Output hiding - (setq idlwave-shell-hide-output hide) - ;;Showing errors - (setq idlwave-shell-show-if-error show-if-error) - ;; Pop command + (setq idlwave-shell-current-command lcmd) + ;; Pop command off pending stack (setq idlwave-shell-pending-commands (cdr idlwave-shell-pending-commands)) ;; Send command for execution @@ -1372,7 +1362,9 @@ message, independent of what HIDE is set to." (set-marker comint-last-input-end (point)) (comint-simple-send proc cmd) (setq idlwave-shell-ready nil) - (if (equal preempt 'wait) ; Get all the output at once + + ;; If waiting, accept all output now + (when (equal preempt 'wait) (while (not idlwave-shell-ready) (when (not (accept-process-output proc 6)) ; long wait (setq idlwave-shell-pending-commands nil) @@ -1555,9 +1547,11 @@ error messages, etc." (defun idlwave-shell-filter (proc string) "Watch for IDL prompt and filter incoming text. -When the IDL prompt is received executes `idlwave-shell-post-command-hook' -and then calls `idlwave-shell-send-command' for any pending commands." - ;; We no longer do the cleanup here - this is done by the process sentinel +When the IDL prompt is received executes the post command hook +from `idlwave-shell-current-command' and then calls +`idlwave-shell-send-command' for any pending commands on the +command queue." + (put 'idlwave-shell-filter 'call-cnt (1+ (or (get 'idlwave-shell-filter 'call-cnt) 0))) (if (eq (process-status idlwave-shell-process-name) 'run) ;; OK, process is still running, so we can use it. (let ((data (match-data)) p full-output) @@ -1567,7 +1561,8 @@ and then calls `idlwave-shell-send-command' for any pending commands." (while (setq p (string-match "\C-G" string)) (ding) (aset string p ?\C-j )) - (if idlwave-shell-hide-output + (if (and idlwave-shell-current-command + (nth 2 idlwave-shell-current-command)) ; we're hiding (save-excursion (while (setq p (string-match "\C-M" string)) (aset string p ?\ )) @@ -1575,9 +1570,12 @@ and then calls `idlwave-shell-send-command' for any pending commands." (get-buffer-create idlwave-shell-hidden-output-buffer)) (goto-char (point-max)) (insert string)) + ;; Not hiding, just put in the shell buffer (idlwave-shell-comint-filter proc string)) - ;; Watch for magic - need to accumulate the current line - ;; since it may not be sent all at once. + + ;; Watch for magic prompt after a newline - need to + ;; accumulate the current line since it may not be sent + ;; all at once. (if (string-match "\n" string) (progn (if idlwave-shell-use-input-mode-magic @@ -1591,7 +1589,6 @@ and then calls `idlwave-shell-send-command' for any pending commands." (setq idlwave-shell-accumulation (concat idlwave-shell-accumulation string))) - ;; Test/Debug code ;;(with-current-buffer ;; (get-buffer-create "*idlwave-shell-output*") @@ -1599,78 +1596,76 @@ and then calls `idlwave-shell-send-command' for any pending commands." ;; (insert "\nReceived STRING\n===>\n" string "\n<====\n")) ;; Check for prompt in current accumulating output - (when (setq idlwave-shell-ready + (if (setq idlwave-shell-ready (string-match idlwave-shell-prompt-pattern idlwave-shell-accumulation)) - ;; Gather the command output, and the input as well. - (if idlwave-shell-hide-output - ;; Hidden output - (with-current-buffer idlwave-shell-hidden-output-buffer - (setq full-output (buffer-string)) - (goto-char (point-max)) - (re-search-backward idlwave-shell-prompt-pattern nil t) - ;;(goto-char (match-end 0)) + (let ((pcmd (nth 1 idlwave-shell-current-command)) + (hide (nth 2 idlwave-shell-current-command)) + (show-if-error (nth 3 idlwave-shell-current-command)) + (redisplay (nth 4 idlwave-shell-current-command))) + + ;; Gather the command output + (if hide + ;; Hidden output + (with-current-buffer idlwave-shell-hidden-output-buffer + (setq full-output (buffer-string)) + (goto-char (point-max)) + (re-search-backward idlwave-shell-prompt-pattern + nil t) + ;;(goto-char (match-end 0)) + (setq idlwave-shell-command-output + (buffer-substring-no-properties + (point-min) (point))) + (erase-buffer)) + ;; In-shell output (setq idlwave-shell-command-output - (buffer-substring-no-properties - (point-min) (point))) - (erase-buffer)) - ;(delete-region (point-min) (point))) - ;; In-shell output - (setq idlwave-shell-command-output - (with-current-buffer (process-buffer proc) - (buffer-substring-no-properties - (save-excursion - (goto-char (process-mark proc)) - (forward-line 0) ; Emacs 21 (beginning-of-line nil) - (point)) - comint-last-input-end)))) - - ;; (with-current-buffer - ;; (get-buffer-create "*idlwave-shell-output*") - ;; (insert "\nFull output registered:\n===>\n" - ;; idlwave-shell-command-output "\n<====\n")) - - ;; Scan for state and do post commands - bracket - ;; them with idlwave-shell-ready=nil since they may - ;; call idlwave-shell-send-command themselves. - (let ((idlwave-shell-ready nil)) - (idlwave-shell-scan-for-state) - ;; Show the output in the shell if it contains an error - (if idlwave-shell-hide-output - (if (and idlwave-shell-show-if-error + (with-current-buffer (process-buffer proc) + (buffer-substring-no-properties + (save-excursion + (goto-char (process-mark proc)) + (forward-line 0) + (point)) + comint-last-input-end)))) + + ;; Scan for state (any errors?) + (idlwave-shell-scan-for-state redisplay) + + ;; Conditionally show some (or all) hidden output + (when hide + (if (and show-if-error (eq idlwave-shell-current-state 'error)) + ;; Show full output if it contains an error (idlwave-shell-comint-filter proc full-output) - ;; If it's only *mostly* hidden, filter % lines, - ;; and show anything that remains - (if (eq idlwave-shell-hide-output 'mostly) + (if (eq hide 'mostly) + ;; Filter % lines, and show anything that remains (let ((filtered - (idlwave-shell-filter-hidden-output + (idlwave-shell-filter-hidden-output full-output))) (if filtered - (idlwave-shell-comint-filter - proc filtered)))))) - - ;; Call the post-command hook - (if (listp idlwave-shell-post-command-hook) - (progn - ;;(message "Calling list") - ;;(prin1 idlwave-shell-post-command-hook) - (eval idlwave-shell-post-command-hook)) - ;;(message "Calling command function") - (funcall idlwave-shell-post-command-hook)) - - ;; Reset to default state for next command. - ;; Also we do not want to find this prompt again. - (setq idlwave-shell-current-command nil - idlwave-shell-accumulation nil - idlwave-shell-command-output nil - idlwave-shell-post-command-hook nil - idlwave-shell-hide-output nil - idlwave-shell-show-if-error nil)) - ;; Done with post command. Do pending command if - ;; any. - (idlwave-shell-send-command))) - (store-match-data data))))) + (idlwave-shell-comint-filter proc + filtered)))))) + + ;; We've fully processed all output of this + ;; command now: reset accumulation to clear the + ;; way for next command (which may be in the + ;; post-command hook!) Leave command-output, and + ;; set completed-command, which the + ;; post-command-hook may need to analyze. + (setq idlwave-shell-accumulation nil + idlwave-shell-completed-command + idlwave-shell-current-command + idlwave-shell-current-command nil) + + + ;; Call the post-command hook, if any. + (if pcmd + (if (listp pcmd) (eval pcmd) (funcall pcmd))) + + (setq idlwave-shell-command-output nil) + + + ;; Send any pending commands + (idlwave-shell-send-command)) (defun idlwave-shell-sentinel (process event) "The sentinel function for the IDLWAVE shell process." @@ -1752,17 +1747,20 @@ in IDL5 which inserts random linebreaks in long module and file names.") (defvar idlwave-shell-electric-debug-mode) ; defined by easy-mmode -(defun idlwave-shell-scan-for-state () +(defun idlwave-shell-scan-for-state (&optional redisplay) "Scan for state info. -Looks for messages in output from last IDL command indicating where -IDL has stopped. The types of messages we are interested in are -execution halted, stepped, breakpoint, interrupted at and trace -messages. For breakpoint messages process any attached count or -command parameters. Update the stop line if a message is found. -The variable `idlwave-shell-current-state' is set to 'error, 'halt, -or 'breakpoint, which describes the status, or nil for none of -the above." +Looks for messages in output from last IDL command indicating +where IDL has stopped. The types of messages we are interested +in are execution halted, stepped, breakpoint, interrupted at and +trace messages. For breakpoint messages process any attached +count or command parameters. Update the stop line if a message +is found. The variable `idlwave-shell-current-state' is set to +'error, 'halt, or 'breakpoint, which describes the status, or nil +for none of the above. If REDISPLAY is non-nil, clear the line +position if no recognized message is found, unless it is +'disable, in which case no-redisplay occurs except for errors." (let (trace) + (cond ;; Make sure we have output ((not idlwave-shell-command-output)) @@ -1792,7 +1790,8 @@ the above." (substring idlwave-shell-command-output (match-beginning 2))) idlwave-shell-current-state 'error) - (idlwave-shell-display-line (idlwave-shell-pc-frame))) + (unless (eq redisplay 'disable) + (idlwave-shell-display-line (idlwave-shell-pc-frame)))) ;; Third Priority: Various types of innocuous HALT and ;; TRACEBACK messages. @@ -1807,10 +1806,11 @@ the above." (substring idlwave-shell-command-output (match-end 0)))) (setq idlwave-shell-current-state 'halt) ;; Don't debug trace messages - (idlwave-shell-display-line - (idlwave-shell-pc-frame) nil - (if trace 'disable - (if idlwave-shell-electric-debug-mode 'force)))) + (unless (eq redisplay 'disable) + (idlwave-shell-display-line + (idlwave-shell-pc-frame) nil + (if trace 'disable + (if idlwave-shell-electric-debug-mode 'force))))) ;; Fourth Priority: Breakpoints ((string-match idlwave-shell-break-message @@ -1837,17 +1837,21 @@ the above." ;; set by the user... Let's update our list. (idlwave-shell-bp-query))) (setq idlwave-shell-current-state 'breakpoint) - (idlwave-shell-display-line (idlwave-shell-pc-frame))) + (unless (eq redisplay 'disable) + (idlwave-shell-display-line (idlwave-shell-pc-frame)))) - ;; Last Priority: Can't Step errors + ;; Last Priority: can't Step errors ((string-match idlwave-shell-cant-continue-error idlwave-shell-command-output) (setq idlwave-shell-current-state 'breakpoint)) - ;; Otherwise, no particular state, display no line + ;; Otherwise, no particular state: remove line display if requested (t (setq idlwave-shell-current-state nil) - (unless idlwave-shell-post-command-hook - (idlwave-shell-display-line nil)))))) + (if (and redisplay + (not (eq redisplay 'disable)) + (not (and idlwave-shell-current-command + (nth 1 idlwave-shell-current-command)))) ; pcmd hook + (idlwave-shell-display-line nil)))))) (defun idlwave-shell-parse-line (string &optional skip-main) @@ -1981,7 +1985,7 @@ The size is given by `idlwave-shell-graphics-window-size'." (idlwave-shell-send-command (apply 'format "window,%d,xs=%d,ys=%d" n idlwave-shell-graphics-window-size) - nil (idlwave-shell-hide-p 'misc) nil t))) + nil (idlwave-shell-hide-p 'misc 'show-if-error)))) (defun idlwave-shell-resync-dirs () "Resync the buffer's idea of the current directory. @@ -3105,19 +3109,20 @@ from `idlwave-shell-examine-alist' via mini-buffer shortcut key." (defun idlwave-shell-strip-input () "Strip the input from command output." - (when idlwave-shell-current-command - (if (string-match idlwave-shell-prompt-pattern idlwave-shell-command-output) + (when idlwave-shell-completed-command + (let ((cmd (car idlwave-shell-completed-command))) + (if (string-match idlwave-shell-prompt-pattern + idlwave-shell-command-output) + (setq idlwave-shell-command-output + (substring idlwave-shell-command-output (match-end 0)))) + (when (eq t (compare-strings + idlwave-shell-command-output 0 (length cmd) cmd 0 nil)) (setq idlwave-shell-command-output - (substring idlwave-shell-command-output (match-end 0)))) - (when (eq t (compare-strings - idlwave-shell-command-output 0 (length idlwave-shell-current-command) - idlwave-shell-current-command 0 nil)) - (setq idlwave-shell-command-output - (substring idlwave-shell-command-output - (length idlwave-shell-current-command))) + (substring idlwave-shell-command-output + (length cmd))) (if (string-match "[ \t]*[\r\n]*" idlwave-shell-command-output) (setq idlwave-shell-command-output - (substring idlwave-shell-command-output (match-end 0))))))) + (substring idlwave-shell-command-output (match-end 0)))))))) (defun idlwave-shell-examine-display () "View the examine command output in a separate buffer."