@ -2,8 +2,8 @@
;; Author: Lucien Cartier-Tilet <lucien@phundrak.com>
;; Maintainer: Lucien Cartier-Tilet <lucien@phundrak.com>
;; Version: 0.8. 4
;; Package-Requires: ((emacs "25.1") ( f "0.20") ( s "1"))
;; Version: 0.8. 8
;; Package-Requires: ((emacs "25.1") ( s "1"))
;; Homepage: https://github.com/Phundrak/eshell-info-banner.el
;; This file is not part of GNU Emacs
@ -38,7 +38,7 @@
;;; Code:
( require 'cl-lib )
( require ' f )
( require ' s )
( require 'em-banner )
( require 'json )
( require 'seq )
@ -60,38 +60,34 @@
; Constants ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
( defconst eshell-info-banner-path-separator
( substring-no-properties ( file-relative-name ( expand-file-name " x " " y " ) ) 1 2 )
" File separator used by the current operating system. " )
( defconst eshell-info-banner--min-length-left 8
" Minimum length of text on the left hand side of the banner. " )
( eval-when-compile
( defconst eshell-info-banner--macos-versions
' ( ( " 10.0 " . " Mac OS X Cheetah " )
( " 10.1 " . " Mac OS X Puma " )
( " 10.2 " . " Mac OS X Jaguar " )
( " 10.3 " . " Mac OS X Panther " )
( " 10.4 " . " Mac OS X Tiger " )
( " 10.5 " . " Mac OS X Leopard " )
( " 10.6 " . " Mac OS X Snow Leopard " )
( " 10.7 " . " Mac OS X Lion " )
( " 10.8 " . " OS X Mountain Lion " )
( " 10.9 " . " OS X Mavericks " )
( " 10.10 " . " OS X Yosemite " )
( " 10.11 " . " OS X El Capitan " )
( " 10.12 " . " macOS Sierra " )
( " 10.13 " . " macOS High Sierra " )
( " 10.14 " . " macOS Mojave " )
( " 10.15 " . " macOS Catalina " )
( " 10.16 " . " macOS Big Sur " )
( " 11.0 " . " macOS Big Sur " )
( " 11.1 " . " macOS Big Sur " )
( " 11.2 " . " macOS Big Sur " )
( " 11.3 " . " macOS Big Sur " )
( " 11.4 " . " macOS Big Sur " )
( " 11.5 " . " macOS Big Sur " )
( " 11.6 " . " macOS Big Sur " )
( " 12.0 " . " macOS Monterey " )
( " 12.1 " . " macOS Monterey " )
( " 12.2 " . " macOS Monterey " ) )
' ( ( " ^10 \\ .0 \\ . " . " Mac OS X Cheetah " )
( " ^10 \\ .1 \\ . " . " Mac OS X Puma " )
( " ^10 \\ .2 \\ . " . " Mac OS X Jaguar " )
( " ^10 \\ .3 \\ . " . " Mac OS X Panther " )
( " ^10 \\ .4 \\ . " . " Mac OS X Tiger " )
( " ^10 \\ .5 \\ . " . " Mac OS X Leopard " )
( " ^10 \\ .6 \\ . " . " Mac OS X Snow Leopard " )
( " ^10 \\ .7 \\ . " . " Mac OS X Lion " )
( " ^10 \\ .8 \\ . " . " OS X Mountain Lion " )
( " ^10 \\ .9 \\ . " . " OS X Mavericks " )
( " ^10 \\ .10 \\ . " . " OS X Yosemite " )
( " ^10 \\ .11 \\ . " . " OS X El Capitan " )
( " ^10 \\ .12 \\ . " . " macOS Sierra " )
( " ^10 \\ .13 \\ . " . " macOS High Sierra " )
( " ^10 \\ .14 \\ . " . " macOS Mojave " )
( " ^10 \\ .15 \\ . " . " macOS Catalina " )
( " ^10 \\ .16 \\ . " . " macOS Big Sur " )
( " ^11 \\ . " . " macOS Big Sur " )
( " ^12 \\ . " . " macOS Monterey " ) )
" Versions of OSX and macOS and their name. " ) )
( defconst eshell-info-banner--posix-shells ' ( " bash " " zsh " " sh " )
@ -106,69 +102,77 @@
" Make `eshell-info-banner' TRAMP aware. "
:group 'eshell-info-banner
:type 'boolean
:safe #' booleanp
:version " 0.3.0 " )
:safe #' booleanp )
( defcustom eshell-info-banner-shorten-path-from 7
" From which length should a path be shortened? "
:group 'eshell-info-banner
:type 'integer
:safe #' integer-or-marker-p
:version " 0.1.0 " )
:safe #' integer-or-marker-p )
( defcustom eshell-info-banner-width 80
" Width of the info banner to be shown in Eshell. "
:group 'eshell-info-banner
:type 'integer
:safe #' integer-or-marker-p
:version " 0.1.0 " )
:safe #' integer-or-marker-p )
( defcustom eshell-info-banner-progress-bar-char " = "
" Character to fill the progress bars with. "
:group 'eshell-info-banner
:type 'string
:safe #' stringp
:version " 0.1.0 " )
:safe #' stringp )
( defcustom eshell-info-banner-warning-percentage 75
" When to warn about a percentage. "
:group 'eshell-info-banner
:type 'float
:safe #' floatp
:version " 0.1.0 " )
:safe #' floatp )
( defcustom eshell-info-banner-critical-percentage 90
" When a percentage becomes critical. "
:group 'eshell-info-banner
:type 'float
:safe #' floatp
:version " 0.1.0 " )
:safe #' floatp )
( defcustom eshell-info-banner-partition-prefixes ' ( " /dev " )
" List of prefixes for detecting which partitions to display. "
:group 'eshell-info-banner
:type 'list
:version " 0.3.0 " )
:type 'list )
( defun eshell-info-banner--executable-find ( program )
( defcustom eshell-info-banner-filter-duplicate-partitions nil
" Whether to filter duplicate partitions.
Two partitions are considered duplicate if they have the same
size and amount of space used. "
:group 'eshell-info-banner
:type 'boolean )
( defcustom eshell-info-banner-exclude-partitions nil
" List of patterns to exclude from the partition list.
Patterns are matched against the partition name with
` string-match-p '. "
:group 'eshell-info-banner
:type ' ( repeat string ) )
( defmacro eshell-info-banner--executable-find ( program )
" Find PROGRAM executable, possibly on a remote machine.
This is a wrapper around ` executable-find ' in order to avoid
issues with older versions of the functions only accepting one
argument. ` executable-find ' ’ s remote argument has the value of
` eshell-info-banner-tramp-aware '. "
( if ( version< emacs-version " 27.1 " )
( let ( ( default-directory ( if eshell-info-banner-tramp-aware
default-directory
" ~ " ) ) )
( executable-find program ) )
( executable-find program eshell-info-banner-tramp-aware ) ) )
` ( let ( ( default-directory ( if eshell-info-banner-tramp-aware
default-directory
" ~ " ) ) )
( executable-find , program ) )
` ( executable-find , program eshell-info-banner-tramp-aware ) ) )
( defcustom eshell-info-banner-duf-executable " duf "
" Path to the `duf' executable. "
:group 'eshell-info-banner
:type 'string
:safe #' stringp
:version " 0.5.0 " )
:safe #' stringp )
( defcustom eshell-info-banner-use-duf
( if ( eshell-info-banner--executable-find eshell-info-banner-duf-executable )
@ -177,16 +181,14 @@ argument. `executable-find'’ s remote argument has the value of
" If non-nil, use `duf' instead of `df' . "
:group 'eshell-info-banner
:type 'boolean
:safe #' booleanp
:version " 0.5.0 " )
:safe #' booleanp )
( defcustom eshell-info-banner-file-size-flavor nil
" Display sizes with IEC prefixes. "
:group 'eshell-info-banner
:type ' ( radio ( const :tag " Default " nil )
( const :tag " SI " si )
( const :tag " IEC " iec ) )
:version " 0.8.0 " )
( const :tag " IEC " iec ) ) )
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -219,7 +221,7 @@ argument. `executable-find'’ s remote argument has the value of
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
( defmacro eshell-info-banner--with-face ( str &rest properties )
" Helper macro for applying face ` PROPERTIES' to ` STR' ."
" Helper macro for applying face PROPERTIES to STR."
` ( propertize , str 'face ( list ,@ properties ) ) )
( defun eshell-info-banner--shell-command-to-string ( command )
@ -230,8 +232,9 @@ Ensures the command is ran with LANG=C."
eshell-info-banner--posix-shells )
" sh " ) ) )
( with-temp-buffer
( call-process shell nil t nil " -c " ( concat " LANG=C " command ) )
( buffer-string ) ) ) )
( let ( ( default-directory ( if eshell-info-banner-tramp-aware default-directory " ~ " ) ) )
( process-file shell nil t nil " -c " ( concat " LANG=C " command ) )
( buffer-string ) ) ) ) )
( defun eshell-info-banner--progress-bar-without-prefix ( bar-length used total &optional newline )
" Display a progress bar without its prefix.
@ -254,6 +257,14 @@ of the progress bar."
:inherit ( eshell-info-banner--get-color-percentage percentage ) )
( if newline " \n " " " ) ) ) ) )
( defun eshell-info-banner--string-repeat ( str times )
" Repeat STR for TIMES times. "
( declare ( pure t ) ( side-effect-free t ) )
( let ( result )
( cl-dotimes ( _ times )
( setq result ( cons str result ) ) )
( apply #' concat result ) ) )
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Internal functions ;
@ -285,7 +296,7 @@ If the executable `uptime' is not found, return nil."
path size used percent )
( defun eshell-info-banner--get-longest-path ( partitions )
" Return the length of the longest partition path in ` PARTITIONS' .
" Return the length of the longest partition path in PARTITIONS.
The returned value is in any case greater than
` eshell-info-banner--min-length-left '. "
@ -295,34 +306,43 @@ The returned value is in any case greater than
( length ( eshell-info-banner--mounted-partitions-path partition ) ) ) ) ) ) )
( defun eshell-info-banner--abbr-path ( path &optional abbr )
" Remove `$HOME' from ` PATH' , abbreviate parent dirs if ` ABBR' non nil.
" Remove `$HOME' from PATH, abbreviate parent dirs if ABBR non nil.
Abbreviate ` PATH ' by removing the value of ` HOME ' if it is
present in the former, and if ` ABBR ' is t then all parent
directories of the current ` PATH ' are abbreviated to only one
character. If an abbreviated directory starts with a dot, then
include it before the abbreviated name of the directory,
e.g. \".config\" -> \".c\".
Abbreviate PATH by removing the value of HOME if it is present in
the former, and if ABBR is t then all parent directories of the
current PATH are abbreviated to only one character. If an
abbreviated directory starts with a dot, then include it before
the abbreviated name of the directory, e.g. \".config\" ->
\".c\".
For public use, ` PATH ' should be a string representing a UNIX
path. For internal use, ` PATH ' can also be a list. If ` PATH ' is
neither of these, an error will be thrown by the function. "
For public use, PATH should be a string representing a UNIX path.
For internal use, PATH can also be a list. If PATH is neither of
these, an error will be thrown by the function. "
( cond
( ( stringp path ) ( abbreviate-file-name
( if abbr
( eshell-info-banner--abbr-path
( f-split ( eshell-info-banner--abbr-path path ) ) )
path ) ) )
( ( stringp path )
( let ( ( abbr-path ( abbreviate-file-name path ) ) )
( if abbr
( abbreviate-file-name
( eshell-info-banner--abbr-path
( split-string abbr-path eshell-info-banner-path-separator t ) ) )
abbr-path ) ) )
( ( null path ) " " )
( ( listp path )
( f-join ( if ( = ( length path ) 1 )
( car path )
( let* ( ( dir ( car path ) )
( first-char ( substring dir 0 1 ) ) )
( if ( string= " . " first-char )
( substring dir 0 2 )
first-char ) ) )
( eshell-info-banner--abbr-path ( cdr path ) ) ) )
( let ( ( file ( eshell-info-banner--abbr-path ( cdr path ) ) )
( directory ( if ( = ( length path ) 1 )
( car path )
( let* ( ( dir ( car path ) )
( first-char ( substring dir 0 1 ) ) )
( if ( string= " . " first-char )
( substring dir 0 2 )
first-char ) ) ) ) )
( if ( string= " " file )
directory
( let ( ( relative-p ( not ( file-name-absolute-p directory ) ) )
( new-dir ( expand-file-name file directory ) ) )
( if relative-p
( file-relative-name new-dir )
new-dir ) ) ) ) )
( t ( error " Invalid argument %s, neither stringp or listp " path ) ) ) )
( defun eshell-info-banner--get-mounted-partitions-duf ( )
@ -362,15 +382,15 @@ Common function between
otherwise differ solely on the position of the mount point in the
partition list. Its position is given by the argument
MOUNT-POSITION. "
( let ( ( partitions ( cdr ( split-string ( eshell-info-banner--shell-command-to-string " df -l " )
( let ( ( partitions ( cdr ( split-string ( eshell-info-banner--shell-command-to-string " df -l -k " )
( regexp-quote " \n " )
t ) ) ) )
( cl-remove-if #' null
( mapcar ( lambda ( partition )
( let* ( ( partition ( split-string partition " " t ) )
( filesystem ( nth 0 partition ) )
( size ( string-to-number ( nth 1 partition ) ) )
( used ( string-to-number ( nth 2 partition ) ) )
( size ( * ( string-to-number ( nth 1 partition ) ) 1024 ) )
( used ( * ( string-to-number ( nth 2 partition ) ) 1024 ) )
( percent ( nth 4 partition ) )
( mount ( nth mount-position partition ) ) )
( when ( seq-some ( lambda ( prefix )
@ -383,7 +403,7 @@ MOUNT-POSITION."
:size size
:used used
:percent ( string-to-number
( s tring-trim-left percent ( regexp-quote " % " ) ) ) ) ) ) )
( s -chop-suffix " % " percent ) ) ) ) ) )
partitions ) ) ) )
( defun eshell-info-banner--get-mounted-partitions-gnu ( )
@ -412,26 +432,54 @@ Return detected partitions as a list of structs. See
chosen. Relies on the ` df ' command. "
( eshell-info-banner--get-mounted-partitions-df 8 ) )
( defun eshell-info-banner--get-mounted-partitions ( )
( defun eshell-info-banner--get-mounted-partitions -1 ( )
" Detect mounted partitions on the system.
Return detected partitions as a list of structs. "
( if eshell-info-banner-use-duf
( eshell-info-banner--get-mounted-partitions-duf )
( pcase system-type
( ( or 'gnu 'gnu/linux 'gnu/kfreebsd 'berkeley-unix )
( eshell-info-banner--get-mounted-partitions-gnu ) )
( ( or 'ms-dos 'windows-nt 'cygwin )
( eshell-info-banner--get-mounted-partitions-windows ) )
( 'darwin
( eshell-info-banner--get-mounted-partitions-darwin ) )
( other
( progn
( ( or 'gnu 'gnu/linux 'gnu/kfreebsd 'berkeley-unix )
( eshell-info-banner--get-mounted-partitions-gnu ) )
( ( or 'ms-dos 'windows-nt 'cygwin )
( eshell-info-banner--get-mounted-partitions-windows ) )
( 'darwin
( eshell-info-banner--get-mounted-partitions-darwin ) )
( other
( progn
( warn " Partition detection for %s not yet supported. " other )
nil ) ) ) ) )
( defun eshell-info-banner--get-mounted-partitions ( )
" Detect mounted partitions on the system.
Take ` eshell-info-banner-filter-duplicate-partitions ' and
` eshell-info-banner-exclude-partitions ' into account. "
( let ( ( partitions ( eshell-info-banner--get-mounted-partitions-1 ) ) )
( when eshell-info-banner-filter-duplicate-partitions
( setq partitions
( cl-loop for partition in partitions
with used = nil
for signature =
( format " %d-%d "
( eshell-info-banner--mounted-partitions-size partition )
( eshell-info-banner--mounted-partitions-used partition ) )
unless ( member signature used )
collect partition and do ( push signature used ) ) ) )
( when eshell-info-banner-exclude-partitions
( setq partitions
( seq-filter ( lambda ( partition )
( let ( ( path ( eshell-info-banner--mounted-partitions-path
partition ) ) )
( not ( seq-some
( lambda ( pattern )
( string-match-p pattern path ) )
eshell-info-banner-exclude-partitions ) ) ) )
partitions ) ) )
partitions ) )
( defun eshell-info-banner--partition-to-string ( partition text-padding bar-length )
" Display a progress bar showing how full a `PARTITION' is.
" Display a progress bar showing how full a PARTITION is.
For TEXT-PADDING and BAR-LENGTH, see the documentation of
` eshell-info-banner--display-memory '. "
@ -570,16 +618,16 @@ in bytes."
( defun eshell-info-banner--memory-to-string ( type total used text-padding bar-length )
" Display a memory’ s usage with a progress bar.
The ` TYPE ' of memory will be the text on the far left, while
` USED ' and ` TOTAL ' will be displayed on the right of the progress
bar. From them, a percentage will be computed which will be used
to display a colored percentage of the progress bar and it will
be displayed on the far right.
The TYPE of memory will be the text on the far left, while USED
and TOTAL will be displayed on the right of the progress bar.
From them, a percentage will be computed which will be used to
display a colored percentage of the progress bar and it will be
displayed on the far right.
` TEXT-PADDING ' will determine how many dots are necessary between
` TYPE ' and the colon.
TEXT-PADDING will determine how many dots are necessary between
TYPE and the colon.
` BAR-LENGTH ' determines the length of the progress bar to be
BAR-LENGTH determines the length of the progress bar to be
displayed. "
( concat ( s-pad-right text-padding " . " type )
" : "
@ -595,10 +643,10 @@ bars will have this appearance:
TYPE......: [ ========= ] XXG / XXG ( XX% )
` TEXT-PADDING ' : the space allocated to the text at the left of the
TEXT-PADDING : the space allocated to the text at the left of the
progress bar.
` BAR-LENGTH ' : the length of the progress bar. "
BAR-LENGTH : the length of the progress bar. "
( mapconcat ( lambda ( mem )
( eshell-info-banner--memory-to-string ( nth 0 mem ) ( nth 1 mem )
( nth 2 mem ) text-padding
@ -610,7 +658,7 @@ progress bar.
; Display information ;;;;;;;;;;;;;;;;;
( defun eshell-info-banner--get-color-percentage ( percentage )
" Display a ` PERCENTAGE' with its according face."
" Display a PERCENTAGE with its according face."
( let ( ( percentage ( if ( stringp percentage )
( string-to-number percentage )
percentage ) ) )
@ -622,12 +670,12 @@ progress bar.
( t 'eshell-info-banner-normal-face ) ) ) )
( defun eshell-info-banner--progress-bar ( length percentage &optional invert )
" Display a progress bar ` LENGTH' long and ` PERCENTAGE' full.
" Display a progress bar LENGTH long and PERCENTAGE full.
The full path will be displayed filled with the character
specified by ` eshell-info-banner-progress-bar-char ' up to
` PERCENTAGE ' percents. The rest will be empty.
PERCENTAGE percents. The rest will be empty.
If ` INVERT ' is t , then consider the percentage to approach
If INVERT is t , then consider the percentage to approach
critical levels close to 0 rather than 100. "
( let* ( ( length-filled ( if ( = 0 percentage )
0
@ -638,10 +686,12 @@ critical levels close to 0 rather than 100."
percentage ) ) )
( concat
( eshell-info-banner--with-face " [ " :weight 'bold )
( eshell-info-banner--with-face ( s-repeat length-filled eshell-info-banner-progress-bar-char )
( eshell-info-banner--with-face ( eshell-info-banner--string-repeat eshell-info-banner-progress-bar-char
length-filled )
:weight 'bold
:inherit ( eshell-info-banner--get-color-percentage percentage-level ) )
( eshell-info-banner--with-face ( s-repeat length-empty eshell-info-banner-progress-bar-char )
( eshell-info-banner--with-face ( eshell-info-banner--string-repeat eshell-info-banner-progress-bar-char
length-empty )
:weight 'bold
:inherit 'eshell-info-banner-background-face )
( eshell-info-banner--with-face " ] " :weight 'bold ) ) ) )
@ -649,9 +699,9 @@ critical levels close to 0 rather than 100."
( defun eshell-info-banner--display-battery ( text-padding bar-length )
" If the computer has a battery, display its level.
Pad the left text with dots by ` TEXT-PADDING ' characters.
Pad the left text with dots by TEXT-PADDING characters.
` BAR-LENGTH ' indicates the length in characters of the progress
BAR-LENGTH indicates the length in characters of the progress
bar.
The usage of ` eshell-info-banner-warning-percentage ' and
@ -676,7 +726,9 @@ the warning face with a battery level of 25% or less."
( eshell-info-banner--progress-bar bar-length
percentage
t )
( s-repeat ( if ( equal eshell-info-banner-file-size-flavor 'iec ) 21 17 ) " " )
( eshell-info-banner--string-repeat
" "
( if ( equal eshell-info-banner-file-size-flavor 'iec ) 21 17 ) )
( format " (%3s%%) \n "
( eshell-info-banner--with-face
( number-to-string percentage )
@ -782,15 +834,17 @@ If RELEASE-FILE is nil, use '/etc/os-release'."
" Get the name of the current macOS or OSX system based on its VERSION. "
` ( cond
,@ ( mapcar ( lambda ( major )
` ( ( string-match-p ( regexp-quote , ( car major ) )
, version )
, ( cdr major ) ) )
` ( ( string-match-p , ( car major )
, version )
, ( cdr major ) ) )
eshell-info-banner--macos-versions )
( t " unknown version " ) ) )
( defun eshell-info-banner--get-os-information-darwin ( )
" See `eshell-info-banner--get-os-information' . "
` ( , ( eshell-info-banner--get-macos-name ( s-trim ( eshell-info-banner--shell-command-to-string " sw_vers -productVersion " ) ) )
` ( , ( eshell-info-banner--get-macos-name
( s-trim
( eshell-info-banner--shell-command-to-string " sw_vers -productVersion " ) ) )
.
, ( s-trim ( eshell-info-banner--shell-command-to-string " uname -rs " ) ) ) )
@ -841,7 +895,8 @@ build number)."
( bar-length ( if ( equal eshell-info-banner-file-size-flavor 'iec )
( - bar-length 4 )
bar-length ) ) )
( concat ( format " %s \n " ( s-repeat tot-width eshell-info-banner-progress-bar-char ) )
( concat ( format " %s \n " ( eshell-info-banner--string-repeat eshell-info-banner-progress-bar-char
tot-width ) )
( format " %s: %s Kernel.: %s \n "
( s-pad-right left-padding
" . "
@ -855,7 +910,8 @@ build number)."
( eshell-info-banner--display-battery left-padding bar-length )
( eshell-info-banner--display-memory left-padding bar-length )
( eshell-info-banner--display-partitions left-padding bar-length )
( format " \n %s \n " ( s-repeat tot-width eshell-info-banner-progress-bar-char ) ) ) ) )
( format " \n %s \n " ( eshell-info-banner--string-repeat eshell-info-banner-progress-bar-char
tot-width ) ) ) ) )
;;;###autoload
( defun eshell-info-banner-update-banner ( )