1421 lines
57 KiB
EmacsLisp
1421 lines
57 KiB
EmacsLisp
;;; awesome-tray.el --- Modular tray bar
|
|
|
|
;; Filename: awesome-tray.el
|
|
;; Description: Modular tray bar
|
|
;; Author: Andy Stewart <lazycat.manatee@gmail.com>
|
|
;; Maintainer: Andy Stewart <lazycat.manatee@gmail.com>
|
|
;; Copyright (C) 2018, Andy Stewart, all rights reserved.
|
|
;; Created: 2018-10-07 07:30:16
|
|
;; Version: 4.2
|
|
;; Last-Updated: 2022-03-01 11:02:39
|
|
;; By: Andy Stewart
|
|
;; URL: http://www.emacswiki.org/emacs/download/awesome-tray.el
|
|
;; Keywords:
|
|
;; Compatibility: GNU Emacs 28.1
|
|
;;
|
|
;; Features that might be required by this library:
|
|
;;
|
|
;; `cl-lib'
|
|
;; `subr-x'
|
|
;; `battery'
|
|
;;
|
|
|
|
;;; This file is NOT part of GNU Emacs
|
|
|
|
;;; License
|
|
;;
|
|
;; This program 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.
|
|
|
|
;; You should have received a copy of the GNU General Public License
|
|
;; along with this program; see the file COPYING. If not, write to
|
|
;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
|
;; Floor, Boston, MA 02110-1301, USA.
|
|
|
|
;;; Commentary:
|
|
;;
|
|
;; Modular tray bar.
|
|
;;
|
|
;; I don't like mode-line, it's too high, affect me to read the code.
|
|
;; With Emacs, we only need to focus on very little information, such as time, current mode, git branch.
|
|
;; Excessive information can seriously interfere with our attention.
|
|
;;
|
|
|
|
;;; Installation:
|
|
;;
|
|
;; Put awesome-tray.el to your load-path.
|
|
;; The load-path is usually ~/elisp/.
|
|
;; It's set in your ~/.emacs like this:
|
|
;; (add-to-list 'load-path (expand-file-name "~/elisp"))
|
|
;;
|
|
;; And the following to your ~/.emacs startup file.
|
|
;;
|
|
;; (require 'awesome-tray)
|
|
;; (awesome-tray-mode 1)
|
|
;;
|
|
;; No need more.
|
|
|
|
;;; Customize:
|
|
;;
|
|
;; `awesome-tray-mode-line-active-color'
|
|
;; `awesome-tray-mode-line-inactive-color'
|
|
;; `awesome-tray-active-modules'
|
|
;; `awesome-tray-git-update-duration'
|
|
;; `awesome-tray-refresh-idle-delay'
|
|
;; `awesome-tray-buffer-name-buffer-changed'
|
|
;; `awesome-tray-buffer-name-buffer-changed-style'
|
|
;; `awesome-tray-input-method-default-style'
|
|
;; `awesome-tray-input-method-local-style'
|
|
;; `awesome-tray-input-method-local-methods'
|
|
;; `awesome-tray-buffer-read-only-style'
|
|
;;
|
|
;; All of the above can customize by:
|
|
;; M-x customize-group RET awesome-tray RET
|
|
;;
|
|
|
|
;;; Change log:
|
|
;;
|
|
;; 2023/07/06
|
|
;; * Make mode-line color indicate buffer state configurable by `awesome-tray-adjust-mode-line-color-enable'.
|
|
;;
|
|
;; 2023/07/01
|
|
;; * Make mode-line color indicate buffer state.
|
|
;;
|
|
;; 2023/06/30
|
|
;; * `awesome-tray-module-location-or-page-info' support EAF PDF Viewer
|
|
;;
|
|
;; 2023/06/12
|
|
;; * Add `awesome-tray-module-location-or-page-info' to show location or pdf page.
|
|
;;
|
|
;; 2023/06/03
|
|
;; * Add `awesome-tray-module-celestial-info' to show moon phase date and sunrise/sunset time.
|
|
;; * Add `awesome-tray-location-info-all', `awesome-tray-location-info-top',
|
|
;; and `awesome-tray-location-info-bottom' to use custom string for All, Top and Bottom in buffer location info.
|
|
;;
|
|
;; 2022/03/01
|
|
;; * Use overlay re-implement tray information render.
|
|
;;
|
|
;; 2020/06/18
|
|
;; * Shorter date info.
|
|
;;
|
|
;; 2020/05/06
|
|
;; * Just show origin message if got any error, easy to debug.
|
|
;;
|
|
;; 2020/04/01
|
|
;; * Shorter tray info.
|
|
;;
|
|
;; 2020/02/27
|
|
;; * Adapter the latest version of the snails.
|
|
;; * Adjust algorithm of `awesome-tray-get-frame-width'.
|
|
;;
|
|
;; 2020/02/19
|
|
;; * Add week info in date.
|
|
;;
|
|
;; 2020/02/14
|
|
;; * Add `awesome-tray-battery-update-duration' to fix `set-mark-command' failed.
|
|
;;
|
|
;; 2020/02/10
|
|
;; * Add battery remaining time.
|
|
;;
|
|
;; 2020/02/05
|
|
;; * Add battery status.
|
|
;;
|
|
;; 2020/01/05
|
|
;; * Hide awesome-tab info if it is too long.
|
|
;;
|
|
;; 2019/08/20
|
|
;; * Use variable `awesome-tray-mode-line-default-height' fix issue #34.
|
|
;;
|
|
;; 2019/08/14
|
|
;; * Remove notify message when toggle awesome-tray status.
|
|
;;
|
|
;; 2019/08/13
|
|
;; * Keep tray info align right when message is very long, thanks QiangF.
|
|
;;
|
|
;; 2019/07/26
|
|
;; * Support snails framework.
|
|
;;
|
|
;; 2019/07/16
|
|
;; * Use `format-mode-line' improve performance of `awesome-tray-module-location-info'.
|
|
;;
|
|
;; 2019/07/15
|
|
;; * Use current-line save value of `line-number-at-pos', improve the performance of `awesome-tray-module-location-info'.
|
|
;; * Use `ignore-errors' catch error of awesome-tray.
|
|
;;
|
|
;; 2019/07/14
|
|
;; * Don't wrap awesome-tray info if variable `inhibit-message' is non-nil.
|
|
;;
|
|
;; 2019/06/23
|
|
;; * Support `awesome-tab' group indicator.
|
|
;; * Fix crash cause by `awesome-tray-module-awesome-tab-info'
|
|
;;
|
|
;; 2019/05/08
|
|
;; * Disable git modulde default, it have performance when we change buffer too fast.
|
|
;;
|
|
;; 2019/04/29
|
|
;; * Fix position not update when execute command `beginning-of-buffer' or `end-of-buffer'.
|
|
;;
|
|
;; 2019/04/25
|
|
;; * Add 'circe' module displaying circe tracking-buffer modeline info.
|
|
;; * The circe module is not activated by default, it's added to `awesome-tray-all-modules'.
|
|
;;
|
|
;; 2018/11/25
|
|
;; * Add `RVM' support.
|
|
;; * The rvm module is not activated by default, I move it to `awesome-tray-all-modules'.
|
|
;;
|
|
;; 2018/11/18
|
|
;; * Fix the problem of displaying duplicate information when the mouse is in the minibuffer window.
|
|
;;
|
|
;; 2018/11/12
|
|
;; * Remove Mac color, use hex color instead.
|
|
;;
|
|
;; 2018/11/03
|
|
;; * Add percent information in location module.
|
|
;; * Fix error: Not enough arguments for format string.
|
|
;;
|
|
;; 2018/10/29
|
|
;; * Use `unspecified' attribute fix black block of mode-line inactive status.
|
|
;; * Add `awesome-tray-git-update-duration' option.
|
|
;;
|
|
;; 2018/10/21
|
|
;; * Use `advice-add' re-implmenet `awesome-tray-message-advice'
|
|
;; * Add parent-dir module.
|
|
;; * Don't show parent-dir if current mode is `dired-mode'.
|
|
;;
|
|
;; 2018/10/13
|
|
;; * Use `awesome-tray-process-exit-code-and-output' fetch git current branch for better error handling.
|
|
;;
|
|
;; 2018/10/11
|
|
;; * Reimplement `awesome-tray-module-git-info' don't depend on magit.
|
|
;; * Add last-command module, handy for debug emacs.
|
|
;;
|
|
;; 2018/10/09
|
|
;; * Add new option `awesome-tray-active-modules'.
|
|
;;
|
|
;; 2018/10/07
|
|
;; * First released.
|
|
;; * Add row/column information.
|
|
;; * Add `awesome-tray-message-advice' make tray information visible always.
|
|
;; * Use `frame-width' instead `window-width' to handle blank characters fill.
|
|
;; * Don't fill blank if message string is wider than frame width.
|
|
;;
|
|
|
|
;;; Acknowledgements:
|
|
;;
|
|
;;
|
|
;;
|
|
|
|
;;; TODO
|
|
;;
|
|
;;
|
|
;;
|
|
|
|
;;; Require
|
|
(require 'cl-lib)
|
|
(require 'subr-x)
|
|
(require 'battery)
|
|
(require 'timer)
|
|
(require 'minibuffer)
|
|
(require 'overlay)
|
|
(require 'vc-git)
|
|
(require 'format-spec)
|
|
|
|
(require 'awesome-tray-faces)
|
|
|
|
;;; Code:
|
|
(defgroup awesome-tray nil
|
|
"Modular tray bar."
|
|
:group 'awesome-tray)
|
|
|
|
(defcustom awesome-tray-minibuffer t
|
|
"If non-nil, also display the awesome-tray when in the minibuffer."
|
|
:group 'awesome-tray
|
|
:type 'boolean)
|
|
|
|
(defcustom awesome-tray-second-line nil
|
|
"If non-nil, display awesome-tray in a second line.
|
|
|
|
WARNING! This makes a lot of minibuffer interactions look weird,
|
|
disable it if you have any problems with your minibuffer appearence."
|
|
:group 'awesome-tray
|
|
:type 'boolean)
|
|
|
|
(defcustom awesome-tray-hide-mode-line t
|
|
"If non-nil, make the mode-line very thin and highlight it when its active/inactive."
|
|
:group 'awesome-tray
|
|
:type 'boolean)
|
|
|
|
(defcustom awesome-tray-position 'right
|
|
"Position to display awesome-tray.
|
|
|
|
WARNING! Better to be used with `awesome-tray-second-line' enabled,
|
|
This makes a lot of minibuffer interactions look weird,
|
|
disable it if you have any problems with your minibuffer appearence."
|
|
:group 'awesome-tray
|
|
:type 'symbol)
|
|
|
|
(defcustom awesome-tray-git-show-status t
|
|
"If non-nil, display the current file status in the git module."
|
|
:group 'awesome-tray
|
|
:type 'boolean)
|
|
|
|
(defcustom awesome-tray-evil-show-mode t
|
|
"If non-nil, display the current evil mode in the evil module."
|
|
:group 'awesome-tray
|
|
:type 'boolean)
|
|
|
|
(defcustom awesome-tray-evil-show-macro t
|
|
"If non-nil, display the current recording macro in the evil module."
|
|
:group 'awesome-tray
|
|
:type 'boolean)
|
|
|
|
(defcustom awesome-tray-evil-show-cursor-count t
|
|
"If non-nil, display the current multiple cursors count in the evil module."
|
|
:group 'awesome-tray
|
|
:type 'boolean)
|
|
|
|
(defcustom awesome-tray-meow-show-mode t
|
|
"If non-nil, display the current meow mode in the meow module."
|
|
:group 'awesome-tray
|
|
:type 'boolean)
|
|
|
|
(defcustom awesome-tray-update-interval 1
|
|
"Interval in seconds between updating the awesome-tray contents.
|
|
|
|
If nil, don't update the awesome-tray automatically."
|
|
:group 'awesome-tray
|
|
:type 'number)
|
|
|
|
(defcustom awesome-tray-mode-line-active-color "DarkRed"
|
|
"Active color."
|
|
:type 'string
|
|
:group 'awesome-tray)
|
|
|
|
(defcustom awesome-tray-mode-line-inactive-color "Gray10"
|
|
"Inactive color."
|
|
:type 'string
|
|
:group 'awesome-tray)
|
|
|
|
(defcustom awesome-tray-mode-line-modified-readonly-color "Green"
|
|
"Modified + readonly color."
|
|
:type 'string
|
|
:group 'awesome-tray)
|
|
|
|
(defcustom awesome-tray-mode-line-readonly-color "DarkGreen"
|
|
"Readonly color."
|
|
:type 'string
|
|
:group 'awesome-tray)
|
|
|
|
(defcustom awesome-tray-mode-line-modified-color "DarkOrange"
|
|
"Modified color."
|
|
:type 'string
|
|
:group 'awesome-tray)
|
|
|
|
(defcustom awesome-tray-adjust-mode-line-color-enable nil
|
|
"If non-nil, adjust mode-line color when buffer state changes."
|
|
:group 'awesome-tray
|
|
:type 'boolean)
|
|
|
|
(defcustom awesome-tray-mode-line-height 0.1
|
|
"Height of mode line."
|
|
:type 'integer
|
|
:group 'awesome-tray)
|
|
|
|
(defcustom awesome-tray-active-modules
|
|
'("location" "belong" "file-path" "mode-name" "battery" "date")
|
|
"Default active modules."
|
|
:type 'list
|
|
:group 'awesome-tray)
|
|
|
|
(defcustom awesome-tray-essential-modules
|
|
'("location" "belong" "file-path")
|
|
"Default essential modules, show when minibuffer is too long."
|
|
:type 'list
|
|
:group 'awesome-tray)
|
|
|
|
(defcustom awesome-tray-git-update-hooks
|
|
'(after-save-hook
|
|
after-revert-hook
|
|
vc-checkin-hook
|
|
text-scale-mode-hook)
|
|
"Hook points to update the git module."
|
|
:type '(list (hook :tag "HookPoint")
|
|
(repeat :inline t (hook :tag "HookPoint"))))
|
|
|
|
(defcustom awesome-tray-separator " "
|
|
"Default string for the separator between modules."
|
|
:group 'awesome-tray
|
|
:type 'string)
|
|
|
|
(defcustom awesome-tray-location-info-all ""
|
|
"Default string indicating buffer all."
|
|
:group 'awesome-tray
|
|
:type 'string)
|
|
|
|
(defcustom awesome-tray-location-info-top " T"
|
|
"Default string indicating buffer top."
|
|
:group 'awesome-tray
|
|
:type 'string)
|
|
|
|
(defcustom awesome-tray-location-info-bottom " B"
|
|
"Default string indicating buffer bottom."
|
|
:group 'awesome-tray
|
|
:type 'string)
|
|
|
|
(defcustom awesome-tray-ellipsis "…"
|
|
"Default string for the ellipsis when something is truncated."
|
|
:group 'awesome-tray
|
|
:type 'string)
|
|
|
|
(defcustom awesome-tray-date-format "%-m-%-d %-H:%-M %a"
|
|
"Format string of the date module."
|
|
:group 'awesome-tray
|
|
:type 'string)
|
|
|
|
(defcustom awesome-tray-mpd-format "%a - %t"
|
|
"Format string of the mpd module.
|
|
|
|
%t title
|
|
%a artist
|
|
%A album
|
|
%p position on the playlist
|
|
%P playlist-length
|
|
%f filename without the folder and file extension
|
|
%F regular filename"
|
|
:group 'awesome-tray
|
|
:type 'string)
|
|
|
|
(defcustom awesome-tray-git-format "git:%s"
|
|
"Format string of the git module.
|
|
|
|
%s branch and file status if enabled with `awesome-tray-git-show-status'"
|
|
:group 'awesome-tray
|
|
:type 'string)
|
|
|
|
(defcustom awesome-tray-location-format "%l:%c %p"
|
|
"Format string of the location module.
|
|
|
|
See `mode-line-format'"
|
|
:group 'awesome-tray
|
|
:type 'string)
|
|
|
|
(defcustom awesome-tray-buffer-name-max-length 20
|
|
"Max length of buffer name."
|
|
:group 'awesome-tray
|
|
:type 'int)
|
|
|
|
(defcustom awesome-tray-mpd-title-max-length 20
|
|
"Max length of mpd song title and filename."
|
|
:group 'awesome-tray
|
|
:type 'int)
|
|
|
|
(defcustom awesome-tray-file-name-max-length 20
|
|
"Max length of file name."
|
|
:group 'awesome-tray
|
|
:type 'int)
|
|
|
|
(defcustom awesome-tray-volume-update-duration 5
|
|
"Update duration of volume status, in seconds."
|
|
:type 'integer
|
|
:group 'awesome-tray)
|
|
|
|
(defcustom awesome-tray-github-update-duration 120
|
|
"Update duration of github notification, in seconds."
|
|
:type 'integer
|
|
:group 'awesome-tray)
|
|
|
|
(defcustom awesome-tray-github-erase-duration 30
|
|
"Github notification time before it gets removed from the bar, in seconds."
|
|
:type 'integer
|
|
:group 'awesome-tray)
|
|
|
|
(defcustom awesome-tray-belong-update-duration 5
|
|
"Update duration of which class, in seconds."
|
|
:type 'integer
|
|
:group 'awesome-tray)
|
|
|
|
(defcustom awesome-tray-battery-update-duration 5
|
|
"Update duration of battery status, in seconds.
|
|
|
|
It will make command `set-mark-command' failed if not use duration."
|
|
:type 'integer
|
|
:group 'awesome-tray)
|
|
|
|
(defcustom awesome-tray-refresh-idle-delay 0.5
|
|
"Update idle delay of awesome tray, in seconds."
|
|
:type 'double
|
|
:group 'awesome-tray)
|
|
|
|
(defcustom awesome-tray-buffer-name-buffer-changed-style "*"
|
|
"`awesome-tray-buffer-name-buffer-changed' style."
|
|
:type 'string
|
|
:group 'awesome-tray)
|
|
|
|
(defcustom awesome-tray-buffer-name-buffer-changed nil
|
|
"Show the current buffer changes after buffer-name."
|
|
:type 'boolean
|
|
:group 'awesome-tray)
|
|
|
|
(defcustom awesome-tray-input-method-default-style ""
|
|
"Default input method display style for input-method module."
|
|
:type 'string
|
|
:group 'awesome-tray)
|
|
|
|
(defcustom awesome-tray-input-method-local-style "ZH"
|
|
"Local input method display style for input-method module."
|
|
:type 'string
|
|
:group 'awesome-tray)
|
|
|
|
(defcustom awesome-tray-input-method-local-methods
|
|
'("rime")
|
|
"List of local input methods you want to display `awesome-tray-input-method-local-style'"
|
|
:type 'list
|
|
:group 'awesome-tray)
|
|
|
|
(defcustom awesome-tray-buffer-read-only-style "R-O"
|
|
"Display style for buffer-read-only module."
|
|
:type 'string
|
|
:group 'awesome-tray)
|
|
|
|
(defcustom awesome-tray-file-path-show-filename nil
|
|
"Show filename in file-path module or not."
|
|
:type 'boolean
|
|
:group 'awesome-tray)
|
|
|
|
(defcustom awesome-tray-file-path-truncated-name-length 1
|
|
"In file-path module, how many letters to leave when truncate dirname.
|
|
|
|
Beginning dots are not counted."
|
|
:type 'integer
|
|
:group 'awesome-tray)
|
|
|
|
(defcustom awesome-tray-file-path-full-dirname-levels 2
|
|
"In file-path module, how many levels of parent directories should be shown in
|
|
their full name."
|
|
:type 'integer
|
|
:group 'awesome-tray)
|
|
|
|
(defcustom awesome-tray-info-padding-right 0
|
|
"You can customize right padding to avoid awesome-tray wrap sometimes."
|
|
:type 'integer
|
|
:group 'awesome-tray)
|
|
|
|
(defvar awesome-tray-text nil
|
|
"The text currently displayed in the awesome-tray.")
|
|
|
|
(defvar awesome-tray-overlays nil
|
|
"List of overlays displaying the awesome-tray contents.")
|
|
|
|
(defvar awesome-tray-before-github-fetch-notification-hook nil
|
|
"Hooks before fetching GitHub notifications.
|
|
Example:
|
|
(add-hook \\='awesome-tray-before-github-fetch-notification-hook
|
|
#\\='auth-source-pass-enable)")
|
|
|
|
(defvar awesome-tray--github-notification-number 0)
|
|
|
|
(defvar awesome-tray-github-last-time 0)
|
|
|
|
(defvar awesome-tray-mode-line-colors nil)
|
|
|
|
(defvar awesome-tray-mpd-command-cache "")
|
|
|
|
(defvar awesome-tray-git-command-cache "")
|
|
|
|
(defvar awesome-tray-git-buffer-filename "")
|
|
|
|
(defvar awesome-tray-belong-last-time 0)
|
|
|
|
(defvar awesome-tray-belong-last-buffer nil)
|
|
|
|
(defvar awesome-tray-belong-cache "")
|
|
|
|
(defvar awesome-tray-battery-status-last-time 0)
|
|
|
|
(defvar awesome-tray-battery-status-cache "")
|
|
|
|
(defvar awesome-tray-flycheck-status-cache "")
|
|
|
|
(defvar awesome-tray-last-tray-info nil)
|
|
|
|
(defvar awesome-tray-mode-line-default-height 1)
|
|
|
|
(defvar awesome-tray-module-alist
|
|
'(("awesome-tab" . (awesome-tray-module-awesome-tab-info awesome-tray-module-awesome-tab-face))
|
|
("buffer-name" . (awesome-tray-module-buffer-name-info awesome-tray-module-buffer-name-face))
|
|
("circe" . (awesome-tray-module-circe-info awesome-tray-module-circe-face))
|
|
("date" . (awesome-tray-module-date-info awesome-tray-module-date-face))
|
|
("celestial" . (awesome-tray-module-celestial-info awesome-tray-module-celestial-face))
|
|
("date" . (awesome-tray-module-date-info awesome-tray-module-date-face))
|
|
("evil" . (awesome-tray-module-evil-info awesome-tray-module-evil-face))
|
|
("file-path" . (awesome-tray-module-file-path-info awesome-tray-module-file-path-face))
|
|
("git" . (awesome-tray-module-git-info awesome-tray-module-git-face))
|
|
("last-command" . (awesome-tray-module-last-command-info awesome-tray-module-last-command-face))
|
|
("location" . (awesome-tray-module-location-info awesome-tray-module-location-face))
|
|
("location-or-page" . (awesome-tray-module-location-or-page-info awesome-tray-module-location-or-page-face))
|
|
("parent-dir" . (awesome-tray-module-parent-dir-info awesome-tray-module-parent-dir-face))
|
|
("mode-name" . (awesome-tray-module-mode-name-info awesome-tray-module-mode-name-face))
|
|
("rvm" . (awesome-tray-module-rvm-info awesome-tray-module-rvm-face))
|
|
("battery" . (awesome-tray-module-battery-info awesome-tray-module-battery-face))
|
|
("input-method" . (awesome-tray-module-input-method-info awesome-tray-module-input-method-face))
|
|
("buffer-read-only" . (awesome-tray-module-buffer-read-only-info awesome-tray-module-buffer-read-only-face))
|
|
("belong" . (awesome-tray-module-belong-info awesome-tray-module-belong-face))
|
|
("clock" . (awesome-tray-module-clock-info awesome-tray-module-clock-face))
|
|
("org-pomodoro" . (awesome-tray-module-org-pomodoro-info awesome-tray-module-org-pomodoro-face))
|
|
("pdf-view-page" . (awesome-tray-module-pdf-view-page-info awesome-tray-module-pdf-view-page-face))
|
|
("flymake" . (awesome-tray-module-flymake-info nil))
|
|
("flycheck" . (awesome-tray-module-flycheck-info nil))
|
|
("meow" . (awesome-tray-module-meow-info awesome-tray-module-meow-face))
|
|
("mpd" . (awesome-tray-module-mpd-info awesome-tray-module-mpd-face))
|
|
("volume" . (awesome-tray-module-volume-info awesome-tray-module-volume-face))
|
|
("word-count" . (awesome-tray-module-word-count-info awesome-tray-module-word-count-face))
|
|
("anzu" . (awesome-tray-module-anzu-info awesome-tray-module-anzu-face))
|
|
("github" . (awesome-tray-module-github-info awesome-tray-module-github-face))
|
|
("hostname" . (awesome-tray-module-hostname-info awesome-tray-module-hostname-face))))
|
|
|
|
|
|
(with-eval-after-load 'mu4e-alert
|
|
(add-hook 'mu4e-index-updated-hook #'mu4e-alert-update-mail-count-modeline)
|
|
(add-hook 'mu4e-message-changed-hook #'mu4e-alert-update-mail-count-modeline)
|
|
(advice-add #'mu4e-context-switch :around #'mu4e-alert--context-switch)
|
|
(mu4e-alert-update-mail-count-modeline)
|
|
|
|
(defun awesome-tray-module-mail-info ()
|
|
(if (member "all-the-icons" (font-family-list))
|
|
(concat (all-the-icons-material "mail" :v-adjust -0.1) ":" (substring mu4e-alert-mode-line 7 -2))
|
|
mu4e-alert-mode-line))
|
|
|
|
(add-to-list 'awesome-tray-module-alist
|
|
'("mail" . (awesome-tray-module-mail-info awesome-tray-module-belong-face))))
|
|
|
|
(defun awesome-tray-module-clock-info ()
|
|
(if (org-clocking-p)
|
|
(format " [%s] (%s)"
|
|
(org-duration-from-minutes
|
|
(floor (org-time-convert-to-integer
|
|
(org-time-since org-clock-start-time))
|
|
60))
|
|
org-clock-heading)))
|
|
|
|
(defun awesome-tray-module-github-info ()
|
|
(let ((current-seconds (awesome-tray-current-seconds)))
|
|
(if (> (- current-seconds awesome-tray-github-last-time) awesome-tray-github-update-duration)
|
|
(progn (setq awesome-tray-github-last-time current-seconds)
|
|
(awesome-tray--github-fetch-notifications))
|
|
(if (> (- current-seconds awesome-tray-github-last-time) awesome-tray-github-erase-duration)
|
|
(setq awesome-tray--github-notification-number 0))
|
|
(if (and (numberp awesome-tray--github-notification-number)
|
|
(> awesome-tray--github-notification-number 0))
|
|
(format "%s github" awesome-tray--github-notification-number)
|
|
""))))
|
|
|
|
(defun awesome-tray--github-fetch-notifications ()
|
|
"Fetch GitHub notifications."
|
|
(when (require 'async nil t)
|
|
(async-start
|
|
`(lambda ()
|
|
,(async-inject-variables
|
|
"\\`\\(load-path\\|auth-sources\\|awesome-tray-before-github-fetch-notification-hook\\)\\'")
|
|
(run-hooks 'awesome-tray-before-github-fetch-notification-hook)
|
|
(when (require 'ghub nil t)
|
|
(with-timeout (10)
|
|
(ignore-errors
|
|
(when-let* ((username (ghub--username ghub-default-host))
|
|
(token (ghub--token ghub-default-host username 'ghub t)))
|
|
(ghub-get "/notifications" nil
|
|
:query '((notifications . "true"))
|
|
:username username
|
|
:auth token
|
|
:noerror t))))))
|
|
(lambda (result)
|
|
(message "") ; suppress message
|
|
(setq awesome-tray--github-notification-number (length result))))))
|
|
|
|
(defun awesome-tray-module-hostname-info ()
|
|
"Hostname for remote buffers."
|
|
(when default-directory
|
|
(when-let ((host (file-remote-p default-directory 'host)))
|
|
(concat "@" host))))
|
|
|
|
(defun awesome-tray-module-word-count-info ()
|
|
(let ((f-count (count-words (point-min) (point-max))))
|
|
(if (region-active-p)
|
|
(format "%d/%dW" (count-words-region (region-beginning) (region-end)) f-count)
|
|
(format "%dW" f-count))))
|
|
|
|
(with-eval-after-load 'anzu
|
|
(add-hook 'isearch-mode-end-hook #'anzu--reset-status t)
|
|
(add-hook 'iedit-mode-end-hook #'anzu--reset-status)
|
|
(advice-add #'evil-force-normal-state :after #'anzu--reset-status)
|
|
;; Fix matches segment mirroring across all buffers
|
|
(mapc #'make-variable-buffer-local
|
|
'(anzu--total-matched
|
|
anzu--current-position anzu--state anzu--cached-count
|
|
anzu--cached-positions anzu--last-command
|
|
anzu--last-isearch-string anzu--overflow-p)))
|
|
|
|
(defun awesome-tray--fix-anzu-count (positions here)
|
|
"Calulate anzu count via POSITIONS and HERE."
|
|
(cl-loop for (start . end) in positions
|
|
collect t into before
|
|
when (and (>= here start) (<= here end))
|
|
return (length before)
|
|
finally return 0))
|
|
|
|
(defun awesome-tray-module-anzu-info ()
|
|
"Show the match index and total number thereof.
|
|
Requires `anzu', also `evil-anzu' if using `evil-mode' for compatibility with
|
|
`evil-search'."
|
|
(if (featurep 'anzu)
|
|
(when (and (bound-and-true-p anzu--state)
|
|
(not (bound-and-true-p iedit-mode)))
|
|
(let ((here anzu--current-position)
|
|
(total anzu--total-matched))
|
|
(cond ((eq anzu--state 'replace-query)
|
|
(format "%d replace" anzu--cached-count))
|
|
((eq anzu--state 'replace)
|
|
(format "[%d/%d]" here total))
|
|
(anzu--overflow-p
|
|
(format "%s+" total))
|
|
(t
|
|
(format "[%s/%d]" here total)))))
|
|
""))
|
|
|
|
(defun awesome-tray-build-active-info ()
|
|
(condition-case nil
|
|
(mapconcat 'identity (cl-remove-if #'(lambda (n) (equal (length n) 0))
|
|
(mapcar 'awesome-tray-get-module-info awesome-tray-active-modules)) awesome-tray-separator)
|
|
(format "Awesome Tray broken.")))
|
|
|
|
(defun awesome-tray-build-essential-info ()
|
|
(condition-case nil
|
|
(mapconcat 'identity (cl-remove-if #'(lambda (n) (equal (length n) 0))
|
|
(mapcar 'awesome-tray-get-module-info awesome-tray-essential-modules)) awesome-tray-separator)
|
|
(format "Awesome Tray broken.")))
|
|
|
|
(defun awesome-tray-get-module-info (module-name)
|
|
(let* ((func (ignore-errors (cadr (assoc module-name awesome-tray-module-alist))))
|
|
(face-param (ignore-errors (caddr (assoc module-name awesome-tray-module-alist))))
|
|
(face (cond ((functionp face-param) (funcall face-param))
|
|
((facep face-param) face-param)
|
|
(t nil)))
|
|
(raw-info (ignore-errors (funcall func)))
|
|
(info (ignore-errors (if face (propertize raw-info 'face face) raw-info))))
|
|
(if func
|
|
(if info
|
|
info
|
|
(propertize "" 'face face))
|
|
(propertize module-name 'face 'awesome-tray-default-face))))
|
|
|
|
(defun awesome-tray-module-volume-info ()
|
|
(if (ignore-errors (require 'volume))
|
|
(concat (number-to-string (truncate (volume-get))) "%")
|
|
""))
|
|
|
|
(defun awesome-tray-module-git-info ()
|
|
(if (executable-find "git")
|
|
(progn
|
|
(if (not (string= (buffer-file-name) awesome-tray-git-buffer-filename))
|
|
(awesome-tray-git-command-update-cache))
|
|
awesome-tray-git-command-cache)
|
|
""))
|
|
|
|
(defun awesome-tray-git-command-update-cache ()
|
|
(if (file-exists-p (format "%s" (buffer-file-name)))
|
|
(let* ((filename (buffer-file-name))
|
|
(status (vc-git-state filename))
|
|
(branch (car (ignore-errors (vc-git-branches)))))
|
|
|
|
(pcase status
|
|
('up-to-date (setq status ""))
|
|
('edited (setq status "!"))
|
|
('needs-update (setq status "⇣"))
|
|
('needs-merge (setq status "⇡"))
|
|
('unlocked-changes (setq status ""))
|
|
('added (setq status "+"))
|
|
('removed (setq status "-"))
|
|
('conflict (setq status "="))
|
|
('missing (setq status "?"))
|
|
('ignored (setq status ""))
|
|
('unregistered (setq status "?"))
|
|
(_ (setq status "")))
|
|
(if (not branch) (setq branch ""))
|
|
|
|
(setq awesome-tray-git-buffer-filename filename)
|
|
|
|
(setq awesome-tray-git-command-cache (if awesome-tray-git-show-status
|
|
(format awesome-tray-git-format (string-trim (concat branch " " status)))
|
|
(format awesome-tray-git-format branch))))
|
|
(setq awesome-tray-git-buffer-filename nil
|
|
awesome-tray-git-command-cache "")))
|
|
|
|
(defun awesome-tray-module-circe-info ()
|
|
"Display circe tracking buffers"
|
|
(if (listp tracking-mode-line-buffers)
|
|
(apply 'concat (cl-loop for entry in tracking-mode-line-buffers
|
|
collect (or (plist-get entry :propertize) "")))
|
|
""))
|
|
|
|
(defun awesome-tray-module-rvm-info ()
|
|
(if (executable-find "rvm-prompt")
|
|
(format "rvm:%s" (replace-regexp-in-string
|
|
"\n" ""
|
|
(nth 1 (awesome-tray-process-exit-code-and-output "rvm-prompt"))))
|
|
|
|
""))
|
|
|
|
(defun awesome-tray-module-battery-info ()
|
|
(let ((current-seconds (awesome-tray-current-seconds)))
|
|
(if (> (- current-seconds awesome-tray-battery-status-last-time) awesome-tray-battery-update-duration)
|
|
(let* ((battery-info (funcall battery-status-function))
|
|
(battery-type (battery-format "%L" battery-info))
|
|
battery-status)
|
|
(setq awesome-tray-battery-status-last-time current-seconds)
|
|
|
|
;; Short battery type.
|
|
(cond ((member battery-type '("on-line" "AC"))
|
|
(setq battery-type "AC")
|
|
(setq battery-status ""))
|
|
((member battery-type '("off-line" "BAT" "Battery"))
|
|
(setq battery-type "")
|
|
(setq battery-status (battery-format
|
|
(if (eq system-type 'darwin)
|
|
"[%p%%]"
|
|
"[%p%% %t]")
|
|
battery-info))))
|
|
|
|
;; Update battery cache.
|
|
(setq awesome-tray-battery-status-cache (concat battery-type battery-status)))
|
|
awesome-tray-battery-status-cache)))
|
|
|
|
(defun awesome-tray-module-mode-name-info ()
|
|
(car (split-string (format "%s" major-mode) "-mode")))
|
|
|
|
(defun awesome-tray-module-location-info ()
|
|
(if (equal major-mode 'eaf-mode)
|
|
""
|
|
(string-replace
|
|
" All" awesome-tray-location-info-all
|
|
(string-replace
|
|
" Top" awesome-tray-location-info-top
|
|
(string-replace
|
|
" Bottom" awesome-tray-location-info-bottom
|
|
(format-mode-line awesome-tray-location-format))))))
|
|
|
|
(defun awesome-tray-module-location-or-page-info ()
|
|
"Show Location or PDF page depends on current mode."
|
|
(let ((page-info (awesome-tray-module-pdf-view-page-info)))
|
|
(if (string= page-info "")
|
|
(awesome-tray-module-location-info)
|
|
page-info)))
|
|
|
|
(with-eval-after-load 'libmpdel
|
|
(add-hook 'libmpdel-current-playlist-changed-hook 'awesome-tray-mpd-command-update-cache)
|
|
(add-hook 'libmpdel-current-song-changed-hook 'awesome-tray-mpd-command-update-cache))
|
|
|
|
(defun awesome-tray-module-mpd-info ()
|
|
(if (and (ignore-errors (require 'libmpdel)) (executable-find "mpd"))
|
|
(if (libmpdel-connected-p)
|
|
awesome-tray-mpd-command-cache
|
|
"not connected to mpd")
|
|
""))
|
|
|
|
(defun awesome-tray-mpd-command-update-cache ()
|
|
(let* ((mpd-info (libmpdel-current-song))
|
|
(title (or (libmpdel-entity-name mpd-info) ""))
|
|
(artist (or (libmpdel-artist-name mpd-info) ""))
|
|
(album (or (libmpdel-album-name mpd-info) ""))
|
|
(position (or (+ (libmpdel-song-position mpd-info) 1) ""))
|
|
(playlist-length (or (libmpdel-playlist-length) ""))
|
|
(filename (or (libmpdel-song-file mpd-info) "")))
|
|
(setq title (awesome-tray-truncate-string title awesome-tray-mpd-title-max-length))
|
|
(setq cut-filename (awesome-tray-truncate-string
|
|
(file-name-sans-extension
|
|
(replace-regexp-in-string ".*/" "" filename))
|
|
awesome-tray-mpd-title-max-length))
|
|
(setq filename (awesome-tray-truncate-string filename awesome-tray-mpd-title-max-length))
|
|
(setq awesome-tray-mpd-command-cache
|
|
(format-spec awesome-tray-mpd-format
|
|
(format-spec-make ?t title ?a artist ?A album ?p position
|
|
?P playlist-length ?f cut-filename ?F filename)))))
|
|
|
|
(defun awesome-tray-module-date-info ()
|
|
"Displays the date."
|
|
(format-time-string awesome-tray-date-format))
|
|
|
|
(defun awesome-tray-module-celestial-info ()
|
|
"Displays lunar phase and sunrise/sunset time."
|
|
(with-demoted-errors
|
|
""
|
|
(if (featurep 'celestial-mode-line)
|
|
(substring-no-properties celestial-mode-line-string)
|
|
"")))
|
|
|
|
(defun awesome-tray-module-last-command-info ()
|
|
;; Only show last command when user enable `toggle-debug-on-error'.
|
|
(when debug-on-error
|
|
(format "%s" last-command)))
|
|
|
|
(defun awesome-tray-module-buffer-name-info ()
|
|
(let (bufname)
|
|
(setq bufname (if awesome-tray-buffer-name-buffer-changed
|
|
(if (and (buffer-modified-p)
|
|
(not (eq buffer-file-name nil)))
|
|
(concat (buffer-name) awesome-tray-buffer-name-buffer-changed-style)
|
|
(buffer-name))
|
|
(format "%s" (buffer-name))))
|
|
(awesome-tray-truncate-string bufname awesome-tray-buffer-name-max-length t)))
|
|
|
|
(defun awesome-tray-module-buffer-read-only-info ()
|
|
(if (and (eq buffer-read-only t)
|
|
(not (eq buffer-file-name nil)))
|
|
(format "%s" awesome-tray-buffer-read-only-style)))
|
|
|
|
(defun awesome-tray-module-input-method-info ()
|
|
(format "%s"
|
|
(if (eq current-input-method nil)
|
|
awesome-tray-input-method-default-style
|
|
(if (member current-input-method awesome-tray-input-method-local-methods)
|
|
awesome-tray-input-method-local-style
|
|
current-input-method-title))))
|
|
|
|
(defun awesome-tray-module-parent-dir-info ()
|
|
(format "%s" (file-name-nondirectory (directory-file-name default-directory))))
|
|
|
|
(defun awesome-tray-shrink-dir-name (input-string)
|
|
(let* ((words (split-string input-string "-"))
|
|
(abbreviated-words (mapcar (lambda (word) (substring word 0 (min awesome-tray-file-path-truncated-name-length (length word)))) words)))
|
|
(mapconcat 'identity abbreviated-words "-")))
|
|
|
|
(defun awesome-tray-module-file-path-info ()
|
|
(let* ((file-path (split-string (if buffer-file-name buffer-file-name default-directory) "/" t))
|
|
(full-num awesome-tray-file-path-full-dirname-levels)
|
|
(show-name awesome-tray-file-path-show-filename)
|
|
shown-path)
|
|
;; Remove file name if `awesome-tray-file-path-show-filename' is nil.
|
|
(setq show-path
|
|
(if buffer-file-name
|
|
(if show-name file-path (butlast file-path))
|
|
file-path))
|
|
;; Remove redundant directory with `awesome-tray-file-path-full-dirname-levels' value.
|
|
(setq show-path (nthcdr (- (length show-path)
|
|
(if buffer-file-name
|
|
(if show-name (1+ full-num) full-num)
|
|
(1+ full-num)))
|
|
show-path))
|
|
;; Shrink parent directory name to save minibuffer space.
|
|
(setq show-path
|
|
(append (mapcar #'awesome-tray-shrink-dir-name (butlast show-path))
|
|
(last show-path)))
|
|
;; Join paths.
|
|
(setq show-path (mapconcat #'identity show-path "/"))
|
|
show-path))
|
|
|
|
(defun awesome-tray-module-awesome-tab-info ()
|
|
(with-demoted-errors
|
|
""
|
|
(if (featurep 'awesome-tab)
|
|
(let ((tab-info (format "%s" (cdr (awesome-tab-selected-tab (awesome-tab-current-tabset t))))))
|
|
(if (> (string-width tab-info) 30)
|
|
""
|
|
tab-info))
|
|
"")))
|
|
|
|
(defun awesome-tray-module-evil-info ()
|
|
(with-demoted-errors
|
|
""
|
|
(if (featurep 'evil)
|
|
(let ((state
|
|
(cond ((not awesome-tray-evil-show-mode) "")
|
|
((evil-normal-state-p) "<N>")
|
|
((evil-emacs-state-p) "<E>")
|
|
((evil-insert-state-p) "<I>")
|
|
((evil-motion-state-p) "<M>")
|
|
((evil-visual-state-p) "<V>")
|
|
((evil-operator-state-p) "<O>")
|
|
((evil-replace-state-p) "<R>")
|
|
(t ""))))
|
|
(if awesome-tray-evil-show-macro
|
|
(setq state (string-trim (concat (awesome-tray--macro-recording) " " state))))
|
|
(if awesome-tray-evil-show-cursor-count
|
|
(setq state (string-trim (concat (awesome-tray--count-multiple-cursors) " " state))))
|
|
state)
|
|
"")))
|
|
|
|
(defun awesome-tray-module-meow-info ()
|
|
(with-demoted-errors
|
|
""
|
|
(if (and (featurep 'meow) awesome-tray-meow-show-mode)
|
|
meow--indicator
|
|
"")))
|
|
|
|
(defun awesome-tray--macro-recording ()
|
|
"Display current evil macro being recorded."
|
|
(if (featurep 'evil)
|
|
(when (or defining-kbd-macro executing-kbd-macro)
|
|
(if (bound-and-true-p evil-this-macro)
|
|
(format "recording @%s" (char-to-string evil-this-macro))
|
|
"Macro"))
|
|
""))
|
|
|
|
(defun awesome-tray--count-multiple-cursors ()
|
|
"Show the number of multiple cursors."
|
|
(let (count)
|
|
(cond ((featurep 'evil-mc) (if (bound-and-true-p evil-mc-cursor-list)
|
|
(format "mc:%s" (number-to-string (+ (length evil-mc-cursor-list) 1)))))
|
|
((featurep 'multiple-cursors) (if (bound-and-true-p multiple-cursors-mode)
|
|
(format "mc:%s" (number-to-string (mc/num-cursors)))))
|
|
(t ""))))
|
|
|
|
(defun awesome-tray-module-belong-info ()
|
|
(if (featurep 'treesit)
|
|
(let ((current-seconds (awesome-tray-current-seconds)))
|
|
(if (or (not (eq (current-buffer) awesome-tray-belong-last-buffer))
|
|
(> (- current-seconds awesome-tray-belong-last-time) awesome-tray-belong-update-duration))
|
|
(progn
|
|
(setq awesome-tray-belong-last-time current-seconds)
|
|
(setq awesome-tray-belong-last-buffer (current-buffer))
|
|
(awesome-tray-update-belong-cache))
|
|
awesome-tray-belong-cache))
|
|
""))
|
|
|
|
(defun awesome-tray-update-belong-cache ()
|
|
(setq awesome-tray-belong-cache
|
|
(let* ((class-nodes (append (awesome-tray-get-match-nodes '((class_definition name: (symbol) @x)))
|
|
(awesome-tray-get-match-nodes '((class_definition name: (identifier) @x)))
|
|
(awesome-tray-get-match-nodes '((class_declaration name: (identifier) @x)))
|
|
(awesome-tray-get-match-nodes '((class_specifier name: (type_identifier) @x)))))
|
|
|
|
(function-nodes (append (awesome-tray-get-match-nodes '((function_definition name: (symbol) @x)))
|
|
(awesome-tray-get-match-nodes '((function_definition name: (identifier) @x)))
|
|
(awesome-tray-get-match-nodes '((function_declarator declarator: (identifier) @x)))
|
|
(awesome-tray-get-match-nodes '((method_declaration name: (identifier) @x)))
|
|
(awesome-tray-get-match-nodes '((function_declarator declarator: (field_identifier) @x)))))
|
|
|
|
which-belong-info
|
|
which-class-info
|
|
which-func-info)
|
|
;; Set class information if point at between range of parent node.
|
|
(setq which-class-info (catch 'found
|
|
(dolist (class-node class-nodes)
|
|
(let ((node (car class-node)))
|
|
(pcase (format "%s" (cdr class-node))
|
|
("(awesome-tray-get-match-nodes '((class_specifier name: (type_identifier) @x)))"
|
|
(when (and (> (point) (treesit-node-start node))
|
|
(< (point) (treesit-node-end node)))
|
|
(throw 'found (treesit-node-text node))))
|
|
(t
|
|
(when (and (> (point) (treesit-node-start (treesit-node-parent node)))
|
|
(< (point) (treesit-node-end (treesit-node-parent node))))
|
|
(throw 'found (treesit-node-text node)))))))
|
|
(throw 'found "")))
|
|
;; Set function information if point at between range of parent node.
|
|
(setq which-func-info (catch 'found
|
|
(dolist (function-node function-nodes)
|
|
(let ((node (car function-node)))
|
|
(pcase (format "%s" (cdr function-node))
|
|
("((function_declarator declarator: (identifier) @x))"
|
|
(when (and (> (point) (treesit-node-start (treesit-node-parent (treesit-node-parent node))))
|
|
(< (point) (treesit-node-end (treesit-node-parent (treesit-node-parent node)))))
|
|
(throw 'found (treesit-node-text node))))
|
|
("((function_declarator declarator: (field_identifier) @x))"
|
|
(when (and (> (point) (treesit-node-start (treesit-node-parent node)))
|
|
(< (point) (treesit-node-end (treesit-node-parent node))))
|
|
(throw 'found (treesit-node-text node))))
|
|
(t
|
|
(when (and (> (point) (treesit-node-start (treesit-node-parent node)))
|
|
(< (point) (treesit-node-end (treesit-node-parent node))))
|
|
(throw 'found (treesit-node-text node)))))))
|
|
(throw 'found "")))
|
|
(setq which-belong-info (string-trim (concat which-class-info " " which-func-info)))
|
|
(if (string-equal which-belong-info "")
|
|
""
|
|
(format "[%s]" which-belong-info))))
|
|
awesome-tray-belong-cache)
|
|
|
|
(defun awesome-tray-module-org-pomodoro-info ()
|
|
(with-demoted-errors
|
|
""
|
|
(if (featurep 'org-pomodoro)
|
|
(let ((state
|
|
(cond ((eq org-pomodoro-state :pomodoro) (concat "[" (org-pomodoro-format-seconds) "]"))
|
|
((eq org-pomodoro-state :short-break) (concat "(" (org-pomodoro-format-seconds) ")"))
|
|
((eq org-pomodoro-state :long-break) (concat "{" (org-pomodoro-format-seconds) "}"))
|
|
(t ""))))
|
|
state)
|
|
"")))
|
|
|
|
(defun awesome-tray-module-pdf-view-page-info ()
|
|
(with-demoted-errors
|
|
""
|
|
(cond
|
|
((and (derived-mode-p 'eaf-mode)
|
|
(string-equal eaf--buffer-app-name "pdf-viewer"))
|
|
(eaf-call-sync "execute_function" eaf--buffer-id "get_progress"))
|
|
((featurep 'pdf-view)
|
|
(let ((state
|
|
(cond ((derived-mode-p 'pdf-view-mode) (format "%d/%d" (eval '(pdf-view-current-page)) (pdf-cache-number-of-pages)))
|
|
(t ""))))
|
|
state))
|
|
(t ""))))
|
|
|
|
(defun awesome-tray-module-flymake-info ()
|
|
"A module for showing Flymake state."
|
|
;; Parts of the code are from doom-modeline package
|
|
(with-demoted-errors
|
|
""
|
|
(if (and (featurep 'flymake) flymake--state)
|
|
(let* ((known (hash-table-keys flymake--state))
|
|
(running (flymake-running-backends))
|
|
(disabled (flymake-disabled-backends))
|
|
(reported (flymake-reporting-backends))
|
|
(disabledp (and disabled (null running)))
|
|
(waiting (cl-set-difference running reported)))
|
|
(when-let
|
|
((flymake-state
|
|
(cond
|
|
(waiting "⏳")
|
|
((null known) "❔")
|
|
(disabledp "❕")
|
|
(t (let ((.error 0)
|
|
(.warning 0)
|
|
(.note 0))
|
|
(cl-loop
|
|
with warning-level = (warning-numeric-level :warning)
|
|
with note-level = (warning-numeric-level :debug)
|
|
for state being the hash-values of flymake--state
|
|
do (cl-loop
|
|
with diags = (flymake--state-diags state)
|
|
for diag in diags do
|
|
(let ((severity (flymake--lookup-type-property (flymake--diag-type diag) 'severity
|
|
(warning-numeric-level :error))))
|
|
(cond ((> severity warning-level) (cl-incf .error))
|
|
((> severity note-level) (cl-incf .warning))
|
|
(t (cl-incf .note))))))
|
|
(let ((num (+ .error .warning .note)))
|
|
(if (> num 0)
|
|
(string-clean-whitespace
|
|
(string-join
|
|
(list
|
|
(when (> .note 0)
|
|
(concat "🔵:" (propertize (number-to-string .note) 'face 'awesome-tray-module-flymake-note)))
|
|
(when (> .warning 0)
|
|
(concat "🟠:" (propertize (number-to-string .warning) 'face 'awesome-tray-module-flymake-warning)))
|
|
(when (> .error 0)
|
|
(concat "🔴:" (propertize (number-to-string .error) 'face 'awesome-tray-module-flymake-error))))
|
|
" "))
|
|
"🟢")))))))
|
|
flymake-state)))))
|
|
|
|
|
|
(with-eval-after-load 'flycheck
|
|
(add-hook 'flycheck-status-changed-functions 'awesome-tray-flycheck-status-update-cache)
|
|
(add-hook 'window-buffer-change-functions (lambda (_) (awesome-tray-flycheck-status-update-cache)))
|
|
)
|
|
|
|
(defun awesome-tray-flycheck-status-update-cache (&optional status)
|
|
(if (or status flycheck-last-status-change)
|
|
(let* ((status (symbol-name flycheck-last-status-change))
|
|
(status (pcase status
|
|
;;("not-checked" "💤")
|
|
;;("no-checker" "❌")
|
|
("running" "⏳")
|
|
("errored" "⚠️")
|
|
("finished" "")
|
|
("interrupted" "⏸️")
|
|
("suspicious" "🤔")
|
|
(_ status)))
|
|
(counts (flycheck-count-errors flycheck-current-errors)))
|
|
;;(debug)
|
|
|
|
(setq awesome-tray-flycheck-status-cache
|
|
(if (not (member status '("not-checked" "no-checker")))
|
|
(let ((errors (cdr (assq 'error counts)))
|
|
(warnings (cdr (assq 'warning counts))))
|
|
(format "%s 🔴:%s|🟠:%s"
|
|
status
|
|
(propertize (number-to-string (or errors 0)) 'face 'awesome-tray-module-flymake-error)
|
|
(propertize (number-to-string (or warnings 0)) 'face 'awesome-tray-module-flymake-warning)))
|
|
""
|
|
))
|
|
;;(message awesome-tray-flycheck-status-cache)
|
|
)
|
|
(setq awesome-tray-flycheck-status-cache "")
|
|
)
|
|
)
|
|
|
|
(defun awesome-tray-module-flycheck-info ()
|
|
(when (featurep 'flycheck)
|
|
awesome-tray-flycheck-status-cache
|
|
)
|
|
)
|
|
|
|
(defun awesome-tray-get-match-nodes (query)
|
|
(ignore-errors
|
|
(mapcar #'(lambda (range)
|
|
(cons (treesit-node-at (car range)) query))
|
|
(treesit-query-range
|
|
(treesit-node-language (treesit-buffer-root-node))
|
|
query))))
|
|
|
|
(defun awesome-tray-truncate-string (string length &optional right)
|
|
"Truncate STRING to LENGTH, replacing the surplus with an ellipsis.
|
|
|
|
If right is non nil, replace to the right"
|
|
(let ((strlen (length string)))
|
|
(if (<= strlen length)
|
|
string
|
|
(setq length (max 0 (- length (length awesome-tray-ellipsis))))
|
|
(if right
|
|
(format "%s%s" (substring string 0 length) awesome-tray-ellipsis)
|
|
(format "%s%s" awesome-tray-ellipsis (substring string (max 0 (- strlen length))))))))
|
|
|
|
(defun awesome-tray-get-frame-width ()
|
|
"Only calculating a main Frame width, to avoid wrong width when new frame, such as `snails'."
|
|
;; `window-width' can calculate the width of the minibuffer more accurately than `frame-width'.
|
|
;; We need remove `awesome-tray-info-padding-right'
|
|
(if (display-graphic-p)
|
|
(with-selected-frame
|
|
(if (daemonp)
|
|
(car (last (butlast (frame-list))))
|
|
(car (last (frame-list))))
|
|
(window-width (minibuffer-window)))
|
|
(window-width (minibuffer-window))))
|
|
|
|
(defun awesome-tray-process-exit-code-and-output (program &rest args)
|
|
"Run PROGRAM with ARGS and return the exit code and output in a list."
|
|
(with-temp-buffer
|
|
(list (apply 'call-process program nil (current-buffer) nil args)
|
|
(buffer-string))))
|
|
|
|
(defun awesome-tray-current-seconds ()
|
|
(string-to-number (format-time-string "%s")))
|
|
|
|
;;;###autoload
|
|
(define-minor-mode awesome-tray-mode
|
|
"Display text at the end of the echo area."
|
|
:global t
|
|
(if awesome-tray-mode
|
|
(awesome-tray-enable)
|
|
(awesome-tray-disable)))
|
|
|
|
;;;###autoload
|
|
(defun awesome-tray-enable ()
|
|
"Turn on the awesome-tray."
|
|
(interactive)
|
|
;; Disable any existing awesome-tray to remove conflicts
|
|
(awesome-tray-disable)
|
|
|
|
(when awesome-tray-hide-mode-line
|
|
;; Save mode-line colors when first time.
|
|
;; Don't change `awesome-tray-mode-line-colors' anymore.
|
|
(unless awesome-tray-mode-line-colors
|
|
(setq awesome-tray-mode-line-colors
|
|
(list (face-attribute 'mode-line :foreground)
|
|
(face-attribute 'mode-line :background)
|
|
(face-attribute 'mode-line :family)
|
|
(face-attribute 'mode-line :box)
|
|
(face-attribute 'mode-line-inactive :foreground)
|
|
(face-attribute 'mode-line-inactive :background)
|
|
(face-attribute 'mode-line-inactive :family)
|
|
(face-attribute 'mode-line-inactive :box))))
|
|
|
|
(setq awesome-tray-mode-line-default-height (face-attribute 'mode-line :height))
|
|
|
|
;; Disable mode line.
|
|
(set-face-attribute 'mode-line nil
|
|
:foreground awesome-tray-mode-line-active-color
|
|
:background awesome-tray-mode-line-active-color
|
|
:height awesome-tray-mode-line-height
|
|
:box nil)
|
|
(set-face-attribute 'mode-line-inactive nil
|
|
:foreground awesome-tray-mode-line-inactive-color
|
|
:background awesome-tray-mode-line-inactive-color
|
|
:height awesome-tray-mode-line-height
|
|
:box nil
|
|
:inherit 'unspecified))
|
|
|
|
;; Create overlays in each echo area buffer
|
|
(dolist (buf '(" *Echo Area 0*" " *Echo Area 1*"))
|
|
(with-current-buffer (get-buffer-create buf)
|
|
(remove-overlays (point-min) (point-max))
|
|
(push (make-overlay (point-min) (point-max) nil nil t)
|
|
awesome-tray-overlays)))
|
|
|
|
;; Start the timer to automatically update
|
|
(when awesome-tray-update-interval
|
|
(run-with-timer 0 awesome-tray-update-interval 'awesome-tray-update))
|
|
|
|
;; Add the setup function to the minibuffer hook
|
|
(when awesome-tray-minibuffer
|
|
(add-hook 'minibuffer-setup-hook #'awesome-tray--minibuffer-setup))
|
|
|
|
;; Add git hooks
|
|
(if (or (member "git" awesome-tray-active-modules) (member "git" awesome-tray-essential-modules))
|
|
(dolist (hook awesome-tray-git-update-hooks)
|
|
(add-hook hook 'awesome-tray-git-command-update-cache)))
|
|
|
|
;; Add anzu advice
|
|
(if (or (member "anzu" awesome-tray-active-modules) (member "anzu" awesome-tray-essential-modules))
|
|
(progn (advice-add #'anzu--where-is-here :override #'awesome-tray--fix-anzu-count)
|
|
;; manage modeline segment ourselves
|
|
(setq anzu-cons-mode-line-p nil))))
|
|
|
|
;;;###autoload
|
|
(defun awesome-tray-disable ()
|
|
"Turn off the awesome-tray."
|
|
(interactive)
|
|
(when awesome-tray-hide-mode-line
|
|
;; Restore mode-line colors.
|
|
(when awesome-tray-mode-line-colors
|
|
(set-face-attribute 'mode-line nil
|
|
:foreground (nth 0 awesome-tray-mode-line-colors)
|
|
:background (nth 1 awesome-tray-mode-line-colors)
|
|
:family (nth 2 awesome-tray-mode-line-colors)
|
|
:box (nth 3 awesome-tray-mode-line-colors)
|
|
:height awesome-tray-mode-line-default-height)
|
|
(set-face-attribute 'mode-line-inactive nil
|
|
:foreground (nth 4 awesome-tray-mode-line-colors)
|
|
:background (nth 5 awesome-tray-mode-line-colors)
|
|
:family (nth 6 awesome-tray-mode-line-colors)
|
|
:box (nth 7 awesome-tray-mode-line-colors)
|
|
:height awesome-tray-mode-line-default-height)))
|
|
|
|
;; Remove awesome-tray overlays
|
|
(mapc 'delete-overlay awesome-tray-overlays)
|
|
(setq awesome-tray-overlays nil)
|
|
|
|
;; Remove text from Minibuf-0
|
|
(with-current-buffer " *Minibuf-0*"
|
|
(delete-region (point-min) (point-max)))
|
|
|
|
;; Cancel the update timer
|
|
(cancel-function-timers #'awesome-tray-update)
|
|
|
|
;; Remove the setup function from the minibuffer hook
|
|
(remove-hook 'minibuffer-setup-hook #'awesome-tray--minibuffer-setup)
|
|
|
|
;; Remove git hooks
|
|
(dolist (hook awesome-tray-git-update-hooks)
|
|
(remove-hook hook 'awesome-tray-git-command-update-cache)))
|
|
|
|
(defun awesome-tray-is-rime-display-in-minibuffer ()
|
|
(if (and (featurep 'rime) (eq rime-show-candidate 'minibuffer))
|
|
rime--current-input-key
|
|
nil))
|
|
|
|
(defun awesome-tray-set-text (text)
|
|
"Set the text displayed by the awesome-tray to TEXT."
|
|
;; Only set tray information when minibuffer not in `input' state.
|
|
;; Don't fill tray information if user is typing in minibuffer.
|
|
(unless (or (active-minibuffer-window) (awesome-tray-is-rime-display-in-minibuffer))
|
|
(let* ((wid (+ (string-width text) awesome-tray-info-padding-right))
|
|
(spc (pcase awesome-tray-position
|
|
('center (propertize " " 'cursor 1 'display
|
|
`(space :align-to (- center ,(/ wid 2)))))
|
|
('left (propertize " " 'cursor 1 'display
|
|
`(space :align-to (- left-fringe ,wid))))
|
|
('right (propertize " " 'cursor 1 'display
|
|
`(space :align-to (- right-fringe
|
|
,(if (display-graphic-p)
|
|
(if (= (nth 1 (window-fringes)) 0)
|
|
;; no right fringe, need 1 char padding to avoid
|
|
;; line wrap
|
|
1
|
|
(if (and (not overflow-newline-into-fringe)
|
|
(= awesome-tray-info-padding-right 0))
|
|
;; need 1 pixel padding to avoid line wrap when
|
|
;; overflow-newline-into-fringe is nil
|
|
'(1)
|
|
'(0)))
|
|
(if (= awesome-tray-info-padding-right 0)
|
|
;; need 1 char in TUI to avoid line wrap
|
|
1
|
|
0))
|
|
,wid)))))))
|
|
|
|
(setq awesome-tray-text (concat (if awesome-tray-second-line "\n") spc text))
|
|
|
|
;; Remove any dead overlays from the minibuffer from the beginning of the list
|
|
(while (null (overlay-buffer (car awesome-tray-overlays)))
|
|
(pop awesome-tray-overlays))
|
|
|
|
;; Add the correct text to each awesome-tray overlay
|
|
(dolist (o awesome-tray-overlays)
|
|
(when (overlay-buffer o)
|
|
(overlay-put o 'after-string awesome-tray-text)))
|
|
|
|
;; Display the text in Minibuf-0
|
|
(with-current-buffer " *Minibuf-0*"
|
|
(delete-region (point-min) (point-max))
|
|
(insert awesome-tray-text)))))
|
|
|
|
(defun awesome-tray--minibuffer-setup ()
|
|
"Setup the awesome-tray in the minibuffer."
|
|
(push (make-overlay (point-max) (point-max) nil t t) awesome-tray-overlays)
|
|
(overlay-put (car awesome-tray-overlays) 'priority 1)
|
|
(awesome-tray-update))
|
|
|
|
(defun awesome-tray-adjust-mode-line-color ()
|
|
(let ((mode-line-color
|
|
(cond
|
|
;; Use `awesome-tray-mode-line-active-color' when current buffer is minibuffer or blink-search input buffer.
|
|
((or (minibufferp)
|
|
(member (buffer-name (current-buffer)) '(" *blink search input*")))
|
|
awesome-tray-mode-line-active-color)
|
|
;; Use `awesome-tray-mode-line-modified-readonly-color' if buffer is modified and read-only.
|
|
((and (buffer-modified-p) buffer-read-only)
|
|
awesome-tray-mode-line-modified-readonly-color)
|
|
;; Use `awesome-tray-mode-line-readonly-color' if buffer is read-only.
|
|
(buffer-read-only
|
|
awesome-tray-mode-line-readonly-color)
|
|
;; Use `awesome-tray-mode-line-active-color' if `auto-save' plugin is enable, avoid blink eyes.
|
|
((buffer-modified-p)
|
|
(if (require 'auto-save nil t)
|
|
awesome-tray-mode-line-active-color
|
|
awesome-tray-mode-line-modified-color))
|
|
(t
|
|
awesome-tray-mode-line-active-color))))
|
|
(set-face-attribute 'mode-line nil
|
|
:foreground mode-line-color
|
|
:background mode-line-color)))
|
|
|
|
(defun awesome-tray-update ()
|
|
"Get new text to be displayed."
|
|
(interactive)
|
|
|
|
;; Adjust mode-line color with buffer's state.
|
|
(when awesome-tray-adjust-mode-line-color-enable
|
|
(awesome-tray-adjust-mode-line-color))
|
|
|
|
(let* ((tray-active-info (awesome-tray-build-active-info))
|
|
;; Get minibuffer content.
|
|
(echo-message (current-message))
|
|
;; Remove text property from content.
|
|
(_ (set-text-properties 0 (length echo-message) nil echo-message))
|
|
;; Set empty string if `echo-message' not string.
|
|
(minibuffer-info (if (stringp echo-message) echo-message ""))
|
|
;; Only fetch last line from content to calculate the width of left side minibuffer.
|
|
(minibuffer-last-line (car (last (split-string minibuffer-info "\n"))))
|
|
;; Calculate blank length between message and active tray info.
|
|
(blank-length (- (awesome-tray-get-frame-width)
|
|
(string-width tray-active-info)
|
|
(string-width minibuffer-last-line))))
|
|
(awesome-tray-set-text
|
|
(if (> blank-length 0)
|
|
;; Show active tray info if have blank.
|
|
tray-active-info
|
|
;; Otherwise show essential tray info.
|
|
(awesome-tray-build-essential-info)))))
|
|
|
|
(provide 'awesome-tray)
|
|
|
|
;;; awesome-tray.el ends here
|