Insert output from asynchronous process into buffer without scrolling to the end

StackOverflow https://stackoverflow.com/questions/23078678

  •  03-07-2023
  •  | 
  •  

Вопрос

I'm writing a simple function that runs a shell command using async-shell-command and displays the output of that command in a separate buffer. However, it is mostly the first lines of the output that is interesting, so I would like to stop the buffer from scrolling down when the result is inserted. Since the process is asynchrounous, I can't simply scroll up when the command is done.

Это было полезно?

Решение 2

In the end, I used the async-shell-command-to-string by Johan Lindström, which I found on the emacs mailing list:

(require 'cl)

(defun async-shell-command-to-string (command callback)
  "Execute shell command COMMAND asynchronously in the
  background.

Return the temporary output buffer which command is writing to
during execution.

When the command is finished, call CALLBACK with the resulting
output as a string."
  (lexical-let
      ((output-buffer (generate-new-buffer " *temp*"))
       (callback-fun callback))
    (set-process-sentinel
(start-process "Shell" output-buffer shell-file-name shell-command-switch command)
     (lambda (process signal)
       (when (memq (process-status process) '(exit signal))
         (with-current-buffer output-buffer
           (let ((output-string
                  (buffer-substring-no-properties
                   (point-min)
                   (point-max))))
             (funcall callback-fun output-string)))
         (kill-buffer output-buffer))))
    output-buffer))

(provide 'async-shell-command-to-string)

my code then becomes:

(defun fr-wordreference-word-at-point ()
  "Looks up word in point using Wordreference."
  (interactive)
  (let* ((word (asciify-string (downcase (current-word t)))))
    (async-shell-command-to-string
     (concat "wr.sh " word)
     (lambda (s)
       (save-excursion
         (set-buffer (get-buffer-create "*wr*"))
         (erase-buffer)
         (insert s)
         (display-buffer "*wr*" t))))))

which seems to work just fine.

Другие советы

I found this question late, but for other people trying to accomplish the same thing you can use a process filter in order to avoid adding a dependency. The following filter will print process output to a buffer without scrolling the window down:

(defun no-scroll-filter (proc string)
  "Process filter that outputs to buffer without moving point."
  (when (buffer-live-p (process-buffer proc))
    (with-current-buffer (process-buffer proc)
      (save-excursion
        (let ((moving (= (point) (process-mark proc))))
          (goto-char (process-mark proc))
          (insert string)
          (set-marker (process-mark proc) (point))
          (if moving (goto-char (process-mark proc))))))))

This can then be activated using set-process-filter.

More info can be found in the Elisp info pages under "Filter Functions".

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top