Skip to content

17. The Waiting Widget

In this lesson, we implement a waiting widget that appears in the mode line while awaiting a response from OpenAI.

To achieve this, we define the chatgpt-mode-line-waiting function. This function either starts a timer that updates the mode line with the string "| ChatGPT" followed by a variable number of dots or stops this timer and remove the waiting widget from the mode line. This is done by updating the global-mode-string variable every 0.66 seconds. The timer is stored in the chatgpt-timer variable.

(defvar chatgpt-timer nil "Timer for waiting widget in mode line")

(defun chatgpt-mode-line-waiting (action)
  "Start or stop a waiting widget in mode line.

Accepted values for ACTION includes `start' and `stop'."
  (pcase action
    ('start
     (setq chatgpt-timer
           (run-with-timer
            0 0.66
            (let ((idx 0))
              (lambda ()
                (progn
                  (setq global-mode-string
                        `(:eval
                          ,(concat "| ChatGPT."
                                   (make-string (mod idx 3) ?.))))
                  (force-mode-line-update 'all)
                  (cl-incf idx)))))))
    ('stop
     (cancel-timer chatgpt-timer)
     (setq chatgpt-timer nil)
     (setq global-mode-string nil)
     (force-mode-line-update 'all))))

Next, we modify the chatgpt-send-request function to incorporate calls to chatgpt-mode-line-waiting. Before sending the request, we invoke this function to initiate the chatgpt-timer. Upon receiving a response from OpenAI, we also call this function to stop the timer in the sentinel function, ensuring it is the first action executed:

(defun chatgpt-send-request (prompt)
  "Send the request with PROMPT to OpenAI."
  (let* (...)
    ...
    (chatgpt-mode-line-waiting 'start)
    (make-process
     :name "chatgpt"
     :buffer (generate-new-buffer-name "chatgpt")
     :command (list "sh" "-c" command)
     :sentinel
     (lambda (process event)
       (chatgpt-mode-line-waiting 'stop)
       (if (not (string= event "finished\n"))
           ...
         ...)))))

This implementation effectively manages the waiting widget within the mode line, providing us with clear visual feedback while awaiting a response from OpenAI.