I'm using a python script to get my monthly bandwith usage shown as string on the terminal stdout. How can I display & update it periodically in the modeline?

  • Check the doc for the variables mode-line-format and perhaps global-mode-string and mode-line-misc-info.
    – NickD
    Feb 25, 2020 at 14:35
  • It's likely this question is a duplicate. Could someone please check for that? Seems like questions about how to put something into the mode-line have been asked many times.
    – Drew
    Feb 25, 2020 at 16:15
  • 2
    Does this answer your question? How to append string that get's updated to mode line?
    – NickD
    Feb 25, 2020 at 22:06

2 Answers 2


There are many ways to add stuff to the mode line.
One way is to define a global minor-mode and a global string variable, register the variable in mode-line-format when the minor mode is active.
Run your Python code with a timer and write the result to the string variable and call force-mode-line-update for all windows afterwards.

The following Elisp code demonstrates that. The Python code is replaced by a (format-time-string " Seconds: %S") from Elisp. Put in whatever you like there.

  • Don't use the (:eval ...) construct of mode-line-format to run your heavy Python task. That eval may be run much more often than you want!
  • Instead of a simple string you can also use a (:propertize ...) construct to add fancy text properties. Since you can change these properties by my-mode-line-update-handler you can vary the text color from green to red depending on the network load.
;; mode-line-format
(defvar my-mode-line-update-interval 1
  "Mode line update in seconds.")

(defvar my-mode-line-entry ""
  "String holding my actual modeline add-on.
See `mode-line-format'.")
;; We need the following if we want to propertize the string:
(put 'my-mode-line-entry 'risky-local-variable t)

(defun my-mode-line-update-handler ()
  "Mode line update running for `my-mode-line-mode'."
  (setq my-mode-line-entry (format-time-string " Seconds: %S")) ;; here you run your Python code.
  (force-mode-line-update t))

(defvar my-mode-line-timer nil
  "Timer running my function and updating the modeline.")

(define-minor-mode my-mode-line-mode
  "Demonstration of an updating modeline entry."
  :global t
  (when (timerp my-mode-line-timer)
    (cancel-timer my-mode-line-timer))
  (if my-mode-line-mode
    (unless (memq 'my-mode-line-entry mode-line-format)
      (setq mode-line-format (nconc mode-line-format (list 'my-mode-line-entry))))
    (setq my-mode-line-timer (run-with-timer 0 my-mode-line-update-interval #'my-mode-line-update-handler)))
    (setq mode-line-format (delq 'my-mode-line-entry mode-line-format))))

You want to append data to global-mode-string 1.

(add-to-list 'global-mode-string '(:eval (myfunc)))

The function:

(defun myfunc ()
   (setq mystring (shell-command-to-string "myshellcommand")))

where myshellcommand is your python script invocation returning your data string.

Now this might stress the system, so instead

 (run-at-time 0 60 'myfunc)
 (defun myfunc2() mystring)
 (add-to-list 'global-mode-string '(:eval myfunc2))

So here myfunc is called every minute to update mystring. myfunc2 returns mystring. We called myfunc2 rather than myfunc in the mode string update thus not calling your script too often.


You might want the call to myfunc2 to do some other work but if not, you can add the symbol directly:-

(add-to-list 'global-mode-string 'mystring)
  • 1
    Instead of (defun myfunc2() mystring) and '(:eval myfunc2)) you can just use the mode line construct 'mystring directly.
    – phils
    Feb 25, 2020 at 22:54
  • thanks, I added that.
    – RichieHH
    Feb 25, 2020 at 23:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.