[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/minibar c995aec574 01/17: Add render and modules for time,
From: |
ELPA Syncer |
Subject: |
[nongnu] elpa/minibar c995aec574 01/17: Add render and modules for time, CPU, temperature... |
Date: |
Sun, 27 Nov 2022 16:01:35 -0500 (EST) |
branch: elpa/minibar
commit c995aec574f3118541b00cb8a4875963b67813d8
Author: Akib Azmain Turja <akib@disroot.org>
Commit: Akib Azmain Turja <akib@disroot.org>
Add render and modules for time, CPU, temperature...
---
README.org | 39 ++++++
miniline.el | 446 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 485 insertions(+)
diff --git a/README.org b/README.org
new file mode 100644
index 0000000000..228928a3f1
--- /dev/null
+++ b/README.org
@@ -0,0 +1,39 @@
+#+title: Miniline - Modular status bar in echo area
+
+The echo area is unused most of the time. Sometimes this empty area so
+annoying that some people want to get rid of it. This package makes it
+useful by showing a status bar in it when it's unused. This is especially
+helpful when you use Emacs as your X window manager using EXWM.
+
+* Installation
+
+** Quelpa
+
+#+begin_src emacs-lisp
+(quelpa '(miniline :fetcher git
+ :url "https://codeberg.org/akib/emacs-miniline.git"))
+#+end_src
+
+** Straight.el
+
+#+begin_src emacs-lisp
+(straight-use-package
+ '(miniline :type git
+ :repo "https://codeberg.org/akib/emacs-miniline.git"))
+#+end_src
+
+** Manual
+
+First install =minibuffer-line= package from ELPA. Then download
+=miniline.el= and put it in your ~load-path~.
+
+* Usage
+
+Enable ~miniline-mode~ to display miniline. You may want to put
+~(miniline-mode +1)~ in your init file. There are several user options you
+can customize, use ~customize-group~ to see and possibly customize them.
+
+Miniline renders the status bar and it uses =minibuffer-line= package to
+show the line in echo area. To change the refresh rate, customize the
+~minibuffer-line-refresh-interval~ variable. To change the face, customize
+the ~minibuffer-line~ face.
diff --git a/miniline.el b/miniline.el
new file mode 100644
index 0000000000..c1c80ef46f
--- /dev/null
+++ b/miniline.el
@@ -0,0 +1,446 @@
+;;; miniline.el --- Modular status bar in echo area -*- lexical-binding: t -*-
+
+;; Copyright (C) 2022 Akib Azmain Turja.
+
+;; Author: Akib Azmain Turja <akib@disroot.org>
+;; Version: 0.1
+;; Package-Requires: ((emacs "27.2") minibuffer-line)
+;; Keywords: calendar, hardware
+;; URL: https://codeberg.org/akib/emacs-miniline
+
+;; This file is not part of GNU Emacs.
+
+;; This file is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; For a full copy of the GNU General Public License
+;; see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; The echo area is unused most of the time. Sometimes this empty area so
+;; annoying that some people want to get rid of it. This package makes it
+;; useful by showing a status bar in it when it's unused. This is
+;; especially helpful when you use Emacs as your X window manager using
+;; EXWM.
+;;
+;; Usage:
+;;
+;; Enable `miniline-mode' to display miniline. You may want to put
+;; (miniline-mode +1) in your init file. There are several user options
+;; you can customize, use `customize-group' to see and possibly customize
+;; them.
+;;
+;; Miniline renders the status bar and it uses `minibuffer-line' package
+;; to show the line in echo area. To change the refresh rate, customize
+;; the `minibuffer-line-refresh-interval' variable. To change the face,
+;; customize the `minibuffer-line' face.
+
+;;; Code:
+
+(require 'minibuffer-line)
+
+(defgroup miniline nil
+ "Modular status bar in echo bar."
+ :group 'tools
+ :link '(url-link "https://codeberg.org/akib/emacs-miniline")
+ :prefix "miniline-")
+
+(defcustom miniline-module-separator " "
+ "Separator to separate modules."
+ :type 'string)
+
+(defcustom miniline-group-separator " "
+ "Separator to separate groups."
+ :type 'string)
+
+(defcustom miniline-group-left nil
+ "Modules to be placed on the left of `miniline'.
+
+The value should be a list of functions. Each function should return a
+string to display, or nil in case there is to show."
+ :type '(repeat function))
+
+(defcustom miniline-group-middle '(miniline-module-time)
+ "Modules to be placed on the middle of `miniline'.
+
+The value should be a list of functions. Each function should return a
+string to display, or nil in case there is to show."
+ :type '(repeat function))
+
+(defcustom miniline-group-right nil
+ "Modules to be placed on the right of `miniline'.
+
+The value should be a list of functions. Each function should return a
+string to display, or nil in case there is to show."
+ :type '(repeat function))
+
+(defun miniline--render-group (modules)
+ "Render MODULES."
+ (mapconcat #'identity (delete nil (mapcar #'funcall modules))
+ miniline-module-separator))
+
+;;;###autoload
+(defun miniline-render ()
+ "Render Miniline."
+ (with-temp-buffer
+ (let ((bar "")
+ (width (frame-width (window-frame (minibuffer-window))))
+ (left (miniline--render-group
+ miniline-group-left))
+ (middle (miniline--render-group
+ miniline-group-middle))
+ (right (miniline--render-group
+ miniline-group-right)))
+
+ ;; HACK: Emacs doesn't show the last character on terminal, so
+ ;; decrease the width by one in that case.
+ (unless (display-graphic-p)
+ (setq width (1- width)))
+ (unless (zerop (length left))
+ (setq bar (concat left miniline-group-separator)))
+ (unless (zerop (length middle))
+ (setq bar (concat bar (make-list
+ (max 0 (- (/ (- width (length middle)) 2)
+ (length bar)))
+ ? )
+ middle miniline-group-separator)))
+ (unless (zerop (length right))
+ (setq bar (concat bar (make-list
+ (max 0 (- width (length right)
+ (length bar)))
+ ? )
+ right)))
+ (replace-regexp-in-string
+ "%" "%%" (format (format "%%-%i.%is" width width) bar)))))
+
+;;;###autoload
+(define-minor-mode miniline-mode
+ "Toggle Miniline display."
+ :init-value nil
+ :lighter " Miniline"
+ :keymap nil
+ :global t
+ (if miniline-mode
+ (progn
+ (setq minibuffer-line-format '(:eval (miniline-render)))
+ (minibuffer-line-mode +1))
+ (setq minibuffer-line-format
+ (ignore-errors
+ (eval (car (get 'minibuffer-line-format 'standard-value)))))
+ (minibuffer-line-mode -1)))
+
+(defcustom miniline-module-time-format "%a %b %d %H:%M"
+ "Time format for time module."
+ :type 'string)
+
+(defun miniline-module-time ()
+ "Module for showing time."
+ (format-time-string miniline-module-time-format))
+
+(defcustom miniline-module-battery-cache-for 60
+ "Cache battery status for this many seconds. Set to zero disable."
+ :type 'number)
+
+(defcustom miniline-module-battery-low-threshold 30
+ "When battery is less than this many percent, treat it as low."
+ :type 'number)
+
+(defface miniline-module-battery-low-face
+ '((t :inherit warning))
+ "Face to use when battery is low.")
+
+(defvar miniline--module-battery-cache nil
+ "Cached battery status.
+
+The value is a cons cell whose car is the status and cdr is the time when
+it was recorded.")
+
+(defun miniline-module-battery ()
+ "Module for showing battery status."
+ (when (or (not miniline--module-battery-cache)
+ (>= (float-time
+ (time-since (cdr miniline--module-battery-cache)))
+ miniline-module-battery-cache-for))
+ (require 'battery nil t)
+ (setq
+ miniline--module-battery-cache
+ (cons
+ (let ((status (when (boundp 'battery-status-function)
+ (funcall battery-status-function))))
+ (when (and (listp status)
+ (assq ?p status)
+ (assq ?L status)
+ (assq ?h status)
+ (assq ?m status))
+ (let ((load (floor (string-to-number (alist-get ?p status))))
+ (charging (string= (alist-get ?L status) "AC"))
+ (remaining-hours (string-to-number (alist-get ?h status)))
+ (remaining-minutes (mod (string-to-number
+ (alist-get ?m status))
+ 60)))
+ (concat
+ (if (and (< load 30)
+ (not charging))
+ (propertize (format "%i%%" load) 'face
+ 'miniline-module-battery-low-face)
+ (format "%s%%" load))
+ (if charging "+" " ")
+ (if (eq load 100)
+ "(full)"
+ (format "(%02i:%02i)" remaining-hours
+ remaining-minutes))))))
+ (current-time))))
+ (car miniline--module-battery-cache))
+
+(defcustom miniline-module-temperature-cache-for 5
+ "Cache CPU temperature for this many seconds. Set to zero disable."
+ :type 'number)
+
+(defcustom miniline-module-temperature-high-threshold 70
+ "When temperature is more than this many percent, treat it as high.
+
+The value should be less than
+`miniline-module-temperature-very-high-threshold'."
+ :type 'number)
+
+(defcustom miniline-module-temperature-very-high-threshold 90
+ "When temperature is more than this many percent, treat it as very high.
+
+The value should be more than
+`miniline-module-temperature-high-threshold'."
+ :type 'number)
+
+(defface miniline-module-temperature-high-face
+ '((t :inherit warning))
+ "Face to use when temperature is high.")
+
+(defface miniline-module-temperature-very-high-face
+ '((t :inherit error))
+ "Face to use when temperature is very high.")
+
+(defvar miniline--module-temperature-cache nil
+ "Cached CPU temperature.
+
+The value is a cons cell whose car is the temperature and cdr is the time
+when it was recorded.")
+
+(defun miniline-module-temperature ()
+ "Module for showing CPU temperature"
+ (when (or (not miniline--module-temperature-cache)
+ (>= (float-time
+ (time-since (cdr miniline--module-temperature-cache)))
+ miniline-module-temperature-cache-for))
+ (setq
+ miniline--module-temperature-cache
+ (cons
+ (let ((zone 0))
+ (with-temp-buffer
+ (insert-file-contents
+ (format "/sys/class/thermal/thermal_zone%i/temp" zone))
+ (let* ((temp (/ (string-to-number (buffer-string)) 1000))
+ (str (concat (int-to-string temp)
+ (if (char-displayable-p ?°) "°" " ")
+ "C")))
+ (if (>= temp miniline-module-temperature-high-threshold)
+ (if (>= temp
+ miniline-module-temperature-very-high-threshold)
+ (propertize str 'face
+ 'miniline-module-temperature-high-face)
+ (propertize str 'face
+ 'miniline-module-temperature-very-high-face))
+ str))))
+ (current-time))))
+ (car miniline--module-temperature-cache))
+
+(defcustom miniline-module-network-speeds-cache-for 1
+ "Cache network speed values for this many seconds. Set to zero disable."
+ :type 'number)
+
+(defvar miniline--module-network-speeds-last-byte-counts nil
+ "Total sent bytes and received bytes previously calculated.")
+
+(defvar miniline--module-network-speeds-cache nil
+ "Cached network speeds.
+
+The value is a cons cell whose car is the speeds and cdr is the time when
+it was recorded.")
+
+(defun miniline-module-network-speeds ()
+ "Module for showing network speeds."
+ (when (or (not miniline--module-network-speeds-cache)
+ (>= (float-time
+ (time-since (cdr miniline--module-network-speeds-cache)))
+ miniline-module-network-speeds-cache-for))
+ (setq
+ miniline--module-network-speeds-cache
+ (cons
+ (let ((previous miniline--module-network-speeds-last-byte-counts)
+ (current
+ (cons (current-time)
+ (with-temp-buffer
+ (insert-file-contents "/proc/net/dev")
+ (let ((regexp "^[\s\t]*\\(.*\\):")
+ (sent 0)
+ (received 0))
+ (goto-char (point-min))
+ (while (search-forward-regexp regexp nil t)
+ (setq received (+ received
+ (read (current-buffer)))))
+ (goto-char (point-min))
+ (while (search-forward-regexp regexp nil t)
+ (forward-word 8)
+ (setq sent (+ sent (read (current-buffer)))))
+ (cons sent received))))))
+ (let* ((speeds
+ (if previous
+ (let ((delta (float-time
+ (time-subtract (car current)
+ (car previous)))))
+ (cons (/ (float (- (car (cdr current))
+ (car (cdr previous))))
+ delta)
+ (/ (float (- (cdr (cdr current))
+ (cdr (cdr previous))))
+ delta)))
+ '(0.0 . 0.0)))
+ (formatter
+ (lambda (rate)
+ (let ((unit "B"))
+ (cond
+ ((>= rate (* 1024 1024 1000))
+ (setq unit "GB")
+ (setq rate (/ rate (* 1024 1024 1000))))
+ ((>= rate (* 1024 1000))
+ (setq unit "MB")
+ (setq rate (/ rate (* 1024 1000))))
+ ((>= rate 1000)
+ (setq unit "KB")
+ (setq rate (/ rate 1000))))
+ (if (string= unit "B")
+ (when (>= rate 100)
+ (setq rate (floor rate)))
+ (when (>= rate 10)
+ (setq rate (floor rate))))
+ (format (if (floatp rate)
+ (format "%%%i.%if %%s/s"
+ (if (string= unit "B") 4 3)
+ (if (string= unit "B")
+ (if (>= rate 10) 1 2)
+ 1))
+ (format "%%%ii %%s/s"
+ (if (string= unit "B") 4 3)))
+ rate unit)))))
+ (setq miniline--module-network-speeds-last-byte-counts current)
+ (format "↑ %s ↓ %s"
+ (funcall formatter (car speeds))
+ (funcall formatter (cdr speeds)))))
+ (current-time))))
+ (car miniline--module-network-speeds-cache))
+
+(defcustom miniline-module-cpu-cache-for 1
+ "Cache CPU load values for this many seconds. Set to zero disable."
+ :type 'number)
+
+(defvar miniline--module-cpu-cache nil
+ "Cached CPU load.
+
+The value is a cons cell whose car is the CPU load and cdr is the time when
+it was recorded.")
+
+(defvar miniline--module-cpu-last-times nil
+ "Last CPU idle and total calculated.")
+
+(defvar miniline--module-cpu-count nil
+ "Count of processor or CPU.")
+
+(defun miniline--module-cpu-calculate-load (cpu)
+ "Calculate CPU load."
+ (let* ((last-cell
+ (let ((cell (assoc-string cpu miniline--module-cpu-last-times)))
+ (unless cell
+ (setq miniline--module-cpu-last-times
+ (cons (cons cpu nil) miniline--module-cpu-last-times))
+ (setq cell (assoc-string cpu
+ miniline--module-cpu-last-times)))
+ cell))
+ (last (cdr last-cell))
+ (now
+ (let ((total 0)
+ (active 0)
+ (data nil))
+ (goto-char (point-min))
+ (search-forward cpu)
+ (setq data (mapcar (lambda (_) (read (current-buffer)))
+ (number-sequence 0 7)))
+ (setq total (apply #'+ data))
+ (setq active (- total (+ (nth 3 data)
+ (nth 4 data))))
+ (cons total active))))
+ (setcdr last-cell now)
+ (* 100
+ (if last
+ (let ((diff-total (- (car now) (car last)))
+ (diff-active (- (cdr now) (cdr last))))
+ (if (zerop diff-total)
+ 0.0
+ (/ (float diff-active) diff-total)))
+ 0.0))))
+
+(defun miniline-module-cpu ()
+ "Module for showing CPU loads."
+ (when (or (not miniline--module-cpu-cache)
+ (>= (float-time
+ (time-since (cdr miniline--module-cpu-cache)))
+ miniline-module-cpu-cache-for))
+ (setq
+ miniline--module-cpu-cache
+ (cons
+ (with-temp-buffer
+ (insert-file-contents "/proc/stat")
+ (unless miniline--module-cpu-count
+ (setq miniline--module-cpu-count
+ (string-to-number (shell-command-to-string "nproc"))))
+ (format
+ "%3i%%%s"
+ (miniline--module-cpu-calculate-load "cpu")
+ (if (display-graphic-p)
+ (concat
+ " "
+ (mapconcat
+ (lambda (i)
+ (let ((load (miniline--module-cpu-calculate-load
+ (format "cpu%i" i))))
+ (cond
+ ((>= load 87.5)
+ (propertize (string #x2588) 'face 'bold))
+ ((>= load 75)
+ (propertize (string #x2587) 'face 'bold))
+ ((>= load 62.5)
+ (propertize (string #x2586) 'face 'bold))
+ ((>= load 50)
+ (propertize (string #x2585) 'face 'bold))
+ ((>= load 37.5)
+ (propertize (string #x2584) 'face 'bold))
+ ((>= load 25)
+ (propertize (string #x2583) 'face 'bold))
+ ((>= load 12.5)
+ (propertize (string #x2582) 'face 'bold))
+ (t
+ (propertize
+ (string #x2581) 'face
+ '(:weight bold :inherit font-lock-comment-face))))))
+ (number-sequence 0 (1- miniline--module-cpu-count)) ""))
+ "")))
+ (current-time))))
+ (car miniline--module-cpu-cache))
+
+(provide 'miniline)
+;;; miniline.el ends here
- [nongnu] branch elpa/minibar created (now 45824cb137), ELPA Syncer, 2022/11/27
- [nongnu] elpa/minibar e6f7411c51 03/17: Rename to Minibar, ELPA Syncer, 2022/11/27
- [nongnu] elpa/minibar 8ecedf6d6c 02/17: Add COPYING, ELPA Syncer, 2022/11/27
- [nongnu] elpa/minibar c995aec574 01/17: Add render and modules for time, CPU, temperature...,
ELPA Syncer <=
- [nongnu] elpa/minibar 2bf88ae60a 05/17: While updating, don't exit on input, that doesn't work on Emacs 28, ELPA Syncer, 2022/11/27
- [nongnu] elpa/minibar 2c50c766dd 07/17: Rename minibar--update to minibar-update, ELPA Syncer, 2022/11/27
- [nongnu] elpa/minibar 5e8afde8f7 13/17: Don't run module functions in temp buffer, ELPA Syncer, 2022/11/27
- [nongnu] elpa/minibar 1da37a9286 12/17: Update install instructions, ELPA Syncer, 2022/11/27
- [nongnu] elpa/minibar 46f3307cc9 10/17: Fix wrong argument order, ELPA Syncer, 2022/11/27
- [nongnu] elpa/minibar 8775f1584c 09/17: Use idle timer, ELPA Syncer, 2022/11/27
- [nongnu] elpa/minibar 9d650e3c71 14/17: Fix group positioning in minibuffer, ELPA Syncer, 2022/11/27
- [nongnu] elpa/minibar 3913de72e0 15/17: Try to make all lines less than 75 characters width, ELPA Syncer, 2022/11/27
- [nongnu] elpa/minibar 9d1a459684 04/17: Don't depend on minibuffer-line, ELPA Syncer, 2022/11/27
- [nongnu] elpa/minibar f228469970 06/17: Use char-displayable-p instead of display-graphic-p, ELPA Syncer, 2022/11/27