diff --git a/early-init.el b/early-init.el index 8c74155a..a8cc4ebd 100644 --- a/early-init.el +++ b/early-init.el @@ -85,5 +85,17 @@ (if (display-graphic-p) (add-hook 'kill-emacs-hook 'my-frame-geometry-save)))) +;; spacemacs-theme https://github.com/nashamri/spacemacs-theme +(use-package spacemacs-theme + :defer t + :config + (require 'cl-lib) ;; spacemacs-common misses to load cl-lib + (setq spacemacs-theme-comment-bg nil) + ;;(load-theme 'spacemacs-dark t) + ) +(use-package my-theme + :config + (load-theme 'my t)) + (provide 'early-init) ;;; early-init.el ends here diff --git a/init b/init index aef873a7..85c8dd2c 100644 --- a/init +++ b/init @@ -11,6 +11,7 @@ ;; Requirements: git gnuplot ledger ;;; Code: +;; early-init spacemacs-theme (require 'early-init (concat (file-name-directory (file-truename (or load-file-name @@ -30,7 +31,7 @@ (require 'general-settings) ;; requires which-key (require 'my-settings) (require 'gui-settings) ;; emacs modeline indent rainbow focus dashboard -(require 'theme-settings) ;; spacemacs-theme fonts emojify +(require 'theme-settings) ;; fonts emojify (require 'popwin-settings) ;; https://melpa.org/#/popwin (require 'toolbar-settings) (require 'deft-settings) ;; https://melpa.org/#/deft diff --git a/lisp/awesome-tray.el b/lisp/awesome-tray.el deleted file mode 100644 index 578c357c..00000000 --- a/lisp/awesome-tray.el +++ /dev/null @@ -1,930 +0,0 @@ -;;; awesome-tray.el --- Modular tray bar - -;; Filename: awesome-tray.el -;; Description: Modular tray bar -;; Author: Andy Stewart -;; Maintainer: Andy Stewart -;; Copyright (C) 2018, Andy Stewart, all rights reserved. -;; Created: 2018-10-07 07:30:16 -;; Version: 4.2 -;; Last-Updated: 2020-06-18 21:02:39 -;; By: Andy Stewart -;; URL: http://www.emacswiki.org/emacs/download/awesome-tray.el -;; Keywords: -;; Compatibility: GNU Emacs 27.0.50 -;; -;; 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-en-style' -;; `awesome-tray-input-method-zh-style' -;; `awesome-tray-buffer-read-only-style' -;; -;; All of the above can customize by: -;; M-x customize-group RET awesome-tray RET -;; - -;;; Change log: -;; -;; 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) - -;;; Code: -(defgroup awesome-tray nil - "Modular tray bar." - :group 'awesome-tray) - -(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-active-modules - '("location" "buffer-name" "belong" "file-path" "mode-name" "input-method" "battery" "date") - "Default active modules." - :type 'list - :group 'awesome-tray) - -(defcustom awesome-tray-essential-modules - '("location" "buffer-name" "belong" "file-path") - "Default ellipsis modules, show when minibuffer is too long." - :type 'list - :group 'awesome-tray) - -(defcustom awesome-tray-buffer-name-max-length 20 - "Max length of buffer name." - :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-git-update-duration 5 - "Update duration of git command, in seconds. - -It's very slow start new process in Windows platform. -Maybe you need set this option with bigger value to speedup on Windows platform." - :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-en-style "EN" - "English input method display style for input-method module." - :type 'string - :group 'awesome-tray) - -(defcustom awesome-tray-input-method-zh-style "ZH" - "Chinese input method display style for input-method module." - :type 'string - :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-file-path-truncate-dirname-levels 0 - "In file-path module, how many levels of parent directories should be shown in -their first character. - -These goes before those shown in their full names." - :type 'integer - :group 'awesome-tray) - -(defface awesome-tray-default-face '((t :inherit default)) - "Face for string constant ouside modules." - :group 'awesome-tray) - -(defface awesome-tray-module-git-face - '((((background light)) - :foreground "#cc2444" :bold t) - (t - :foreground "#ff2d55" :bold t)) - "Git face." - :group 'awesome-tray) - -(defface awesome-tray-module-rvm-face - '((((background light)) - :foreground "#2832cc" :bold t) - (t - :foreground "#333fff" :bold t)) - "RVM face." - :group 'awesome-tray) - -(defface awesome-tray-module-circe-face - '((((background light)) - :foreground "#2832cc" :bold t) - (t - :foreground "#333fff" :bold t)) - "Circe face." - :group 'awesome-tray) - -(defface awesome-tray-module-mode-name-face - '((((background light)) - :foreground "#00a400" :bold t) - (t - :foreground "green3" :bold t)) - "Mode name face." - :group 'awesome-tray) - -(defface awesome-tray-module-location-face - '((((background light)) - :foreground "#cc7700" :bold t) - (t - :foreground "#ff9500" :bold t)) - "Location face." - :group 'awesome-tray) - -(defface awesome-tray-module-date-face - '((((background light)) - :foreground "#717175" :bold t) - (t - :foreground "#8e8e93" :bold t)) - "Date face." - :group 'awesome-tray) - -(defface awesome-tray-module-last-command-face - '((((background light)) - :foreground "#0061cc" :bold t) - (t - :foreground "#007aff" :bold t)) - "Date face." - :group 'awesome-tray) - -(defface awesome-tray-module-buffer-name-face - '((((background light)) - :foreground "#cc7700" :bold t) - (t - :foreground "#ff9500" :bold t)) - "Buffer name face." - :group 'awesome-tray) - -(defface awesome-tray-module-parent-dir-face - '((((background light)) - :foreground "#5e8e2e" :bold t) - (t - :foreground "#9ded4d" :bold t)) - "Parent dir face." - :group 'awesome-tray) - -(defface awesome-tray-module-file-path-face - '((((background light)) - :foreground "#5e8e2e" :bold t) - (t - :foreground "#9ded4d" :bold t)) - "Parent dir face." - :group 'awesome-tray) - -(defface awesome-tray-module-awesome-tab-face - '((((background light)) - :foreground "#b83059" :bold t) - (t - :foreground "#e73c70" :bold t)) - "Awesome tab face." - :group 'awesome-tray) - -(defface awesome-tray-module-evil-face - '((((background light)) - :foreground "#008080" :bold t) - (t - :foreground "#00ced1" :bold t)) - "Evil state face." - :group 'awesome-tray) - -(defface awesome-tray-module-battery-face - '((((background light)) - :foreground "#008080" :bold t) - (t - :foreground "#00ced1" :bold t)) - "Battery state face." - :group 'awesome-tray) - -(defface awesome-tray-module-buffer-read-only-face - '((((background light)) - :foreground "#cc2444" :bold t) - (t - :foreground "#ff2d55" :bold t)) - "Buffer read only face." - :group 'awesome-tray) - -(defface awesome-tray-module-belong-face - '((((background light)) - :foreground "#cc2444" :bold t) - (t - :foreground "#ff2d55" :bold t)) - "Buffer read only face." - :group 'awesome-tray) - -(defface awesome-tray-module-input-method-face - '((((background light)) - :foreground "#008080" :bold t) - (t - :foreground "#00ced1" :bold t)) - "Input method face." - :group 'awesome-tray) - -;;;###autoload -(define-minor-mode awesome-tray-mode - "Modular tray bar." - :require 'awesome-tray-mode - :global t - (if awesome-tray-mode - (awesome-tray-enable) - (awesome-tray-disable))) - -(defvar awesome-tray-info-padding-right 0) - -(defvar awesome-tray-mode-line-colors nil) - -(defvar awesome-tray-timer nil) - -(defvar awesome-tray-active-p nil) - -(defvar awesome-tray-git-command-last-time 0) - -(defvar awesome-tray-git-command-cache "") - -(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-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)) - ("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)) - ("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)) - )) - -(defun awesome-tray-enable () - ;; 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 0.1 - :box nil) - (set-face-attribute 'mode-line-inactive nil - :foreground awesome-tray-mode-line-inactive-color - :background awesome-tray-mode-line-inactive-color - :height 0.1 - :box nil - :inherit 'unspecified) - ;; Add update timer. - (setq awesome-tray-timer - (run-with-timer 0 awesome-tray-refresh-idle-delay 'awesome-tray-show-info)) - (add-hook 'focus-in-hook 'awesome-tray-show-info) - (setq awesome-tray-active-p t)) - -(defun awesome-tray-disable () - ;; Restore 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) - ;; Cancel timer. - (when (timerp awesome-tray-timer) - (cancel-timer awesome-tray-timer)) - (remove-hook 'focus-in-hook 'awesome-tray-show-info) - ;; Update mode-line. - (force-mode-line-update) - (redraw-display) - (with-current-buffer " *Minibuf-0*" - (erase-buffer)) - (setq awesome-tray-active-p nil)) - -(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)) " ") - (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)) " ") - (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-git-info () - (if (executable-find "git") - (let ((current-seconds (awesome-tray-current-seconds))) - (if (> (- current-seconds awesome-tray-git-command-last-time) awesome-tray-git-update-duration) - (progn - (setq awesome-tray-git-command-last-time current-seconds) - (awesome-tray-update-git-command-cache)) - 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 ((string-equal battery-type "on-line") - (setq battery-type "ON") - (setq battery-status (battery-format "-%p%%" battery-info))) - ((string-equal battery-type "off-line") - (setq battery-type "OFF") - (setq battery-status (battery-format "-%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 () - (format "%s:%s %s" - (format-mode-line "%l") - (format-mode-line "%c") - (format-mode-line "%p") - )) - -(defun awesome-tray-module-date-info () - (format-time-string "%m-%d %H:%M %a")) - -(defun awesome-tray-module-last-command-info () - (format "%s" last-command)) - -(defun awesome-tray-module-buffer-name-info () - (let ((ellipsis "...") - 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)))) - (if (> (length bufname) awesome-tray-buffer-name-max-length) - (format "%s%s" (substring bufname 0 (- awesome-tray-buffer-name-max-length (length ellipsis))) ellipsis) - bufname))) - -(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 () - (if (eq current-input-method nil) - (format "%s" awesome-tray-input-method-en-style) - (format "%s" awesome-tray-input-method-zh-style))) - -(defun awesome-tray-module-parent-dir-info () - (format "%s" (file-name-nondirectory (directory-file-name default-directory)))) - -(defun awesome-tray-shrink-dir-name (name) - "Shrink NAME to be its first letter, or the first two if starts \".\" - -NAME is a string, typically a directory name." - (let ((dot-num (if (string-match "^\\.+" name) - (length (match-string 0 name)) - 0))) - (substring name 0 (min (length name) (+ dot-num awesome-tray-file-path-truncated-name-length))))) - -(defun awesome-tray-module-file-path-info () - (if (not buffer-file-name) - (let ((ellipsis "...") - (bufname (buffer-name))) - (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)))) - (if (> (length bufname) awesome-tray-file-name-max-length) - (format "%s%s" (substring bufname 0 (- awesome-tray-file-name-max-length (length ellipsis))) ellipsis) - bufname)) - (let* ((file-path (split-string (buffer-file-name) "/" t)) - (shown-path) - (path-len (length file-path)) - (modp (if (buffer-modified-p) "*" "")) - (full-num awesome-tray-file-path-full-dirname-levels) - (trunc-num awesome-tray-file-path-truncate-dirname-levels) - (show-name awesome-tray-file-path-show-filename)) - (when (> path-len (+ 1 full-num)) - (push (string-join - (mapcar #'awesome-tray-shrink-dir-name - (cl-subseq file-path - (max 0 (- path-len (+ 1 full-num trunc-num))) - (- path-len (1+ full-num)))) "/") - shown-path)) - (when (> path-len 1) - (push (string-join - (cl-subseq file-path - (max 0 (- path-len (1+ full-num))) - (1- path-len)) "/") - shown-path)) - (when show-name - (push (car (last file-path)) shown-path)) - (concat modp - (if (<= path-len (+ 1 full-num trunc-num)) - "/" - ".../") - (string-join (nreverse (cl-remove "" shown-path)) "/") - (when (and shown-path (not show-name)) "/"))))) - -(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 ((evil-normal-state-p) "") - ((evil-emacs-state-p) "") - ((evil-insert-state-p) "") - ((evil-motion-state-p) "") - ((evil-visual-state-p) "") - ((evil-operator-state-p) "") - ((evil-replace-state-p) "") - (t "")))) - state) - ""))) - -(defun awesome-tray-module-belong-info () - (if (featurep 'tree-sitter) - (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)"))) - (function-nodes (append (awesome-tray-get-match-nodes "(function_definition name: (symbol) @x)") - (awesome-tray-get-match-nodes "(function_definition name: (identifier) @x)"))) - which-belong-info - which-class-info - which-func-info) - (setq which-class-info (catch 'found - (dolist (class-node class-nodes) - (when (and (> (point) (tsc-node-start-position (tsc-get-parent class-node))) - (< (point) (tsc-node-end-position (tsc-get-parent class-node)))) - (throw 'found (tsc-node-text class-node))) - ) - (throw 'found ""))) - (setq which-func-info (catch 'found - (dolist (function-node function-nodes) - (when (and (> (point) (tsc-node-start-position (tsc-get-parent function-node))) - (< (point) (tsc-node-end-position (tsc-get-parent function-node)))) - (throw 'found (tsc-node-text function-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-get-match-nodes (match-rule) - (ignore-errors - (let* ((query (tsc-make-query tree-sitter-language match-rule)) - (root-node (tsc-root-node tree-sitter-tree)) - (captures (mapcar #'cdr (tsc-query-captures query root-node #'tsc--buffer-substring-no-properties)))) - captures))) - -(defun awesome-tray-show-info () - ;; Only flush tray info when current message is empty. - (unless (current-message) - (awesome-tray-flush-info))) - -(defun awesome-tray-get-frame-width () - "Only calculating a main Frame width, to avoid wrong width when new frame, such as `snails'." - (if (display-graphic-p) - (with-selected-frame (car (last (frame-list))) - (frame-width)) - (frame-width))) - -(defun awesome-tray-flush-info () - (let* ((tray-info (awesome-tray-build-active-info))) - (with-current-buffer " *Minibuf-0*" - (erase-buffer) - (insert (concat (make-string (max 0 (- (awesome-tray-get-frame-width) (string-width tray-info) awesome-tray-info-padding-right)) ?\ ) tray-info))))) - -(defun awesome-tray-get-echo-format-string (message-string) - (let* ((tray-info (awesome-tray-build-active-info)) - (blank-length (- (awesome-tray-get-frame-width) (string-width tray-info) (string-width message-string) awesome-tray-info-padding-right))) - (prog1 - (cond - ;; Fill message's end with whitespace to keep tray info at right of minibuffer. - ((> blank-length 0) - (concat message-string - (make-string (max 0 (- (awesome-tray-get-frame-width) - (string-width message-string) - (string-width tray-info) - awesome-tray-info-padding-right)) ?\ ) - tray-info)) - ;; Fill empty whitespace if new message contain duplicate tray-info (cause by move mouse on minibuffer window). - ((and awesome-tray-last-tray-info - message-string - (string-suffix-p awesome-tray-last-tray-info message-string)) - (concat (make-string (max 0 (- (awesome-tray-get-frame-width) - (string-width tray-info) - awesome-tray-info-padding-right)) ?\ ) - tray-info)) - (t - (let* ((essential-info (awesome-tray-build-essential-info)) - (fill-string (make-string (max 0 (- (awesome-tray-get-frame-width) - (string-width essential-info) - (string-width message-string) - awesome-tray-info-padding-right)) ?\ ))) - (if (> (+ (string-width message-string) (string-width fill-string) (string-width essential-info)) - (awesome-tray-get-frame-width)) - ;; Don't show tray information if message is too long. - message-string - (concat message-string fill-string essential-info)) - ))) - ;; Record last tray information. - (setq awesome-tray-last-tray-info tray-info)))) - -(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"))) - -(defun awesome-tray-update-git-command-cache () - (let* ((git-info (awesome-tray-process-exit-code-and-output "git" "symbolic-ref" "--short" "HEAD")) - (status (nth 0 git-info)) - (result (format "git:%s" (nth 1 git-info)))) - (setq awesome-tray-git-command-cache - (if (equal status 0) - (replace-regexp-in-string "\n" "" result) - "")) - awesome-tray-git-command-cache)) - -;; Wrap `message' make tray information visible always -;; even other plugins call `message' to flush minibufer. -(defun awesome-tray-message-advice (old-message &rest arguments) - (if (ignore-errors - (cond - ;; Don't wrap tray info if `awesome-tray-active-p' is nil. - ((not awesome-tray-active-p) - (apply old-message arguments)) - - ;; Don't wrap awesome-tray info if variable `inhibit-message' is non-nil. - (inhibit-message - (apply old-message arguments)) - - ;; Just flush tray info if message string is empty. - ((not (car arguments)) - (apply old-message arguments) - (awesome-tray-flush-info)) - - ;; Otherwise, wrap message string with tray info and show it in echo area, - ;; logging origin message at `*Messages*' buffer if allowed. - (t - (if message-log-max - (let ((inhibit-message t)) - (apply old-message arguments))) - (let ((message-log-max nil)) - (apply old-message "%s" (cons (awesome-tray-get-echo-format-string (apply 'format arguments)) '()))))) - - ;; Return t if everything is okay. - t) - ;; Return origin message string. if not, `message' function will always return `nil'. - (if (car arguments) - (apply 'format arguments)) - (apply old-message arguments))) - -(advice-add #'message :around #'awesome-tray-message-advice) - -(defun awesome-tray-current-message-advice (old-func &rest arguments) - (let ((message-string (apply old-func arguments))) - (if (and message-string awesome-tray-last-tray-info) - (string-trim-right (replace-regexp-in-string awesome-tray-last-tray-info "" message-string)) - message-string))) - -(advice-add #'current-message :around #'awesome-tray-current-message-advice) - -(defun awesome-tray-end-of-buffer-advice (old-func &rest arguments) - (apply old-func arguments) - (message "")) - -(advice-add #'end-of-buffer :around #'awesome-tray-end-of-buffer-advice) - -(defun awesome-tray-beginning-of-buffer-advice (old-func &rest arguments) - (apply old-func arguments) - (message "")) - -(advice-add #'beginning-of-buffer :around #'awesome-tray-beginning-of-buffer-advice) - -(provide 'awesome-tray) - -;;; awesome-tray.el ends here diff --git a/lisp/awesome-tray/README.md b/lisp/awesome-tray/README.md new file mode 100644 index 00000000..a1f64c8d --- /dev/null +++ b/lisp/awesome-tray/README.md @@ -0,0 +1,134 @@ + + +[More screenshots](./screenshots/README.md) + +### What's this? +I don't like the mode-line, it's too high and 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 +Clone this repository + +```console +$ git clone --depth=1 https://github.com/manateelazycat/awesome-tray.git +``` + +Then put awesome-tray.el to your load-path. + +The load-path is usually `~/elisp/`. It's set in your `~/.emacs` like this: + +```Elisp +(add-to-list `load-path (expand-file-name "~/elisp")) +(require 'awesome-tray) +(awesome-tray-mode 1) +``` + +## Customize Mode line. + +- `awesome-tray-hide-mode-line`: Enabled by default, makes the mode-line very thin and highlight it when its active/inactive. +- `awesome-tray-mode-line-active-color`: Use for customize active color. +- `awesome-tray-mode-line-inactive-color`: Use for customize inactive color. +- `awesome-tray-adjust-mode-line-color-enable`: Disabled by default. If non-nil, adjust mode-line color when buffer state changes. +- `awesome-tray-mode-line-modified-readonly-color`: Use for customize modified and readonly color. +- `awesome-tray-mode-line-readonly-color`: Use for customize readonly color. +- `awesome-tray-mode-line-modified-color`: Use for customize modified color. +- `awesome-tray-mode-line-height`: Mode line height, default is 0.1 +- `awesome-tray-date-format`: Use to customize the date string format. +- `awesome-tray-mpd-format`: Use to customize the mpd string format, see the variable docstring for details. +- `awesome-tray-git-format`: Use to customize the git string format. +- `awesome-tray-location-format`: Use to customize the location string format, see `mode-line-format`. +- `awesome-tray-location-info-all`: Use to customize the location "All", if `mode-line-format` contains `%p`. +- `awesome-tray-location-info-top`: Use to customize the location "Top", if `mode-line-format` contains `%p`. +- `awesome-tray-location-info-bottom`: Use to customize the location "Bottom", if `mode-line-format` contains `%p`. +- `awesome-tray-git-show-status`: If non-nil, show current file status on the git module. +- `awesome-tray-ellipsis`: Use to customize the ellipses used when truncating. +- `awesome-tray-separator`: Use to customize the separator between modules. +- `awesome-tray-evil-show-mode`: If non-nil, show current evil mode in the evil module. +- `awesome-tray-evil-show-macro`: If non-nil, show recording macro in the evil module. +- `awesome-tray-evil-show-cursor-count`: If non-nil, show multiple cursors count in the evil module. +- `awesome-tray-github-update-duration`: Update duration of the github notification, in seconds. +- `awesome-tray-github-erase-duration`: Github notification time before it gets removed from the bar, in seconds. +- `awesome-tray-meow-show-mode`: If non-nil, show current meow mode in the meow module. +- `awesome-tray-input-method-default-style`: Input method indicator you want to show when no input method is toggled on. +- `awesome-tray-input-method-local-style`: Input method indicator for your local input method. +- `awesome-tray-input-method-local-methods`: List of input methods as your local input method. If input method is toggled on, but not a member of this list, `input-method-title` will display in as input method indicator in awesome-tray, such as "DE@" for German. Default is "rime". + +## Dangerous options +Please read the docstring for those variables + +**Those options can make your awesome-tray look weird, if your minibuffer looks weird disable them** + +- `awesome-tray-second-line`: [screenshot](./screenshots/screenshot2.png), Displays awesome-tray in a second line keeping the minibuffer messages readable. +- `awesome-tray-position`: [screenshot](./screenshots/centered.png), Displays awesome-tray in the left, right or center, better to be used with `awesome-tray-second-line` enabled. + +## Customize Module +You can control modules through option ```awesome-tray-active-modules```. + +**When changing the modules load awesome-tray-mode after setting the modules to prevent useless hooks and changes** + +You can find all modules name in the keys of variable ```awesome-tray-module-alist```. Currently we have: + +- `awesome-tab`: Show group information of [awesome-tab](https://github.com/manateelazycat/awesome-tab). +- `buffer-name`: Show buffer name. +- `circe`: Show circe tracking buffer information. +- `date`: Show current date. +- `celestial`: If you are not settled for date, you can add lunar phase and sunrise/set time. Requires `celestial-mode-line` package. +- `evil`: Show evil state, recording macro and multiple cursors count in both [evil-mc](https://github.com/gabesoft/evil-mc) and [multiple-cursors](https://github.com/magnars/multiple-cursors.el). +- `file-path`: Show file path with full customizability. When the path is long, it can be shrinked into something like `.../.em/el/awesome-tray/awesome-tray.el`. See `awesome-tray-file-path-***` variables for details. +- `git`: Show git information. +- `last-command`: Show last execute command. +- `location`: Show point position in buffer. +- `pdf-view-page`: Show page number in pdf-view-mode. +- `location-or-page`: Show location or pdf page number depends on current mode. +- `parent-dir`: Show direct parent directory. +- `mode-name`: Show major mode name. +- `rvm`: Show Ruby version information given by `rvm-prompt`. +- `battery`: Show battery status. +- `input-method`: Show input method status. +- `buffer-read-only`: Show read only status. +- `belong`: Show which class/function status, need install `treesit` first. +- `org-pomodoro`: Show `org-pomodoro` status. Denote the rest time of pomodoro by `[.]`, short break by `(.)` and long break by `{.}`. +- `flymake`: Show Flymake state. +- `flycheck`: Show Flycheck state. +- `meow`: Show meow state. +- `mpd`: Show mpd information using [libmpdel](https://github.com/mpdel/libmpdel), you need to connect to a mpd profile, use `(libmpdel-connect-profile (libmpdel--select-profile))` unless you have multiple profiles. +- `volume`: Show current volume using [volume.el](https://github.com/dbrock/volume.el). +- `word-count`: Show file and selected region word-count. +- `anzu`: Show searched word count and current index using [anzu](https://github.com/emacsorphanage/anzu). +- `github`: Show github notifications using [async](https://github.com/jwiegley/emacs-async) and [ghub](https://github.com/magit/ghub). +- `hostname`: Show remote buffers hostname. + +## Create a Module +Let's create a module that says hello to you. With a module you need: + +- A name. Let's simply call it "hello". + +- A info function that returns the string to be displayed. Here's a simple one + + ``` emacs-lisp + (defun my-module-hello-info () + (concat "Hello " (user-login-name) "!")) + ``` + + A complex info function may encounter an error, awesome-tray will handle this and not show any information there. + +- a face. Let's use a simple yet elegant italic style: + + ``` emacs-lisp + (defface my-module-hello-face + '((t (:italic t))) + "Hello module face." + :group 'awesome-tray) + ``` + +- Awesome-tray uses `awesome-tray-module-alist` to find informations about a module. Let's put ours in it: + + ``` emacs-lisp + (add-to-list 'awesome-tray-module-alist + '("hello" . (my-module-hello-info my-module-hello-face))) + ``` + +- Now put `"hello"` in the `awesome-tray-active-modules` list, and you will see awesome-tray say hello to you! + +If you created a module that could be useful to others, please consider contributing it to awesome-tray! diff --git a/lisp/awesome-tray/awesome-tray-faces.el b/lisp/awesome-tray/awesome-tray-faces.el new file mode 100644 index 00000000..f50c90f6 --- /dev/null +++ b/lisp/awesome-tray/awesome-tray-faces.el @@ -0,0 +1,293 @@ +;;; awesome-tray-faces.el --- Faces for Awesome Tray -*-lexical-binding: t; -*- +;; +;; This file is not part of GNU Emacs. +;; +;; 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 +;; of the License, 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 GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. +;; +;;; Commentary: +;; +;; This module provides the faces for Awesome Tray. +;; +;;; Code: + + +;; Base Faces: + +(defface awesome-tray-default-face '((t :inherit default :bold t)) + "Face for string constant ouside modules." + :group 'awesome-tray) + +(defface awesome-tray-grey-face + '((((background light)) :foreground "dim grey" :bold t) + (t :foreground "dark grey" :bold t)) + "Awesome tray grey." + :group 'awesome-tray) + +(defface awesome-tray-red-face + '((((background light)) :foreground "#cc2444" :bold t) + (t :foreground "#ff2d55" :bold t)) + "Awesome tray red." + :group 'awesome-tray) + +(defface awesome-tray-green-face + '((((background light)) :foreground "#00a400" :bold t) + (t :foreground "green3" :bold t)) + "Awesome tray green." + :group 'awesome-tray) + +(defface awesome-tray-green-path-face + '((((background light)) :foreground "#5e8e2e" :bold t) + (t :foreground "#9ded4d" :bold t)) + "Awesome green face for paths." + :group 'awesome-tray) + +(defface awesome-tray-blue-face + '((((background light)) :foreground "#2832cc" :bold t) + (t :foreground "#333fff" :bold t)) + "Awesome tray blue." + :group 'awesome-tray) + +(defface awesome-tray-blue-bright-face + '((((background light)) :foreground "#0061cc" :bold t) + (t :foreground "#007aff" :bold t)) + "Date face." + :group 'awesome-tray) + +(defface awesome-tray-orange-face + '((((background light)) :foreground "#cc7700" :bold t) + (t :foreground "#ff9500" :bold t)) + "Awesome tray orange." + :group 'awesome-tray) + +(defface awesome-tray-yellow-face + '((((background light)) :foreground "gold" :bold t) + (t :foreground "yellow" :bold t)) + "Awesome tray yellow." + :group 'awesome-tray) + +(defface awesome-tray-pink-face + '((((background light)) :foreground "deep pink" :bold t) + (t :foreground "hot pink" :bold t)) + "Awesome tab pink." + :group 'awesome-tray) + +(defface awesome-tray-magenta-face + '((((background light)) :foreground "dark magenta" :bold t) + (t :foreground "magenta" :bold t)) + "Awesome tray magenta." + :group 'awesome-tray) + +(defface awesome-tray-cyan-face + '((((background light)) :foreground "#008080" :bold t) + (t :foreground "#00ced1" :bold t)) + "Awesome tray cyan." + :group 'awesome-tray) + + +;; Contextual Faces + +(defface awesome-tray-module-git-face + '((((background light)) :inherit awesome-tray-red-face) + (t :inherit awesome-tray-red-face)) + "Git face." + :group 'awesome-tray) + +(defface awesome-tray-module-awesome-tab-face + '((((background light)) :inherit awesome-tray-pink-face) + (t :inherit awesome-tray-pink-face)) + "Awesome tab face." + :group 'awesome-tray) + +(defface awesome-tray-module-rvm-face + '((((background light)) :inherit awesome-tray-blue-face) + (t :inherit awesome-tray-blue-face)) + "RVM face." + :group 'awesome-tray) + +(defface awesome-tray-module-circe-face + '((((background light)) :inherit awesome-tray-blue-face) + (t :inherit awesome-tray-blue-face)) + "Circe face." + :group 'awesome-tray) + +(defface awesome-tray-module-mode-name-face + '((((background light)) :inherit awesome-tray-green-face) + (t :inherit awesome-tray-green-face)) + "Mode name face." + :group 'awesome-tray) + +(defface awesome-tray-module-location-face + '((((background light)) :inherit awesome-tray-orange-face) + (t :inherit awesome-tray-orange-face)) + "Location face." + :group 'awesome-tray) + +(defface awesome-tray-module-location-or-page-face + '((((background light)) :inherit awesome-tray-orange-face) + (t :inherit awesome-tray-orange-face)) + "Location or page face." + :group 'awesome-tray) + +(defface awesome-tray-module-word-count-face + '((((background light)) :inherit awesome-tray-orange-face) + (t :inherit awesome-tray-orange-face)) + "Word count face." + :group 'awesome-tray) + +(defface awesome-tray-module-anzu-face + '((((background light)) :inherit awesome-tray-orange-face) + (t :inherit awesome-tray-orange-face)) + "Anzu face." + :group 'awesome-tray) + +(defface awesome-tray-module-github-face + '((((background light)) :inherit awesome-tray-cyan-face) + (t :inherit awesome-tray-cyan-face)) + "Github face." + :group 'awesome-tray) + +(defface awesome-tray-module-hostname-face + '((((background light)) :inherit awesome-tray-cyan-face) + (t :inherit awesome-tray-cyan-face)) + "Hostname face." + :group 'awesome-tray) + +(defface awesome-tray-module-volume-face + '((((background light)) :inherit awesome-tray-cyan-face) + (t :inherit awesome-tray-cyan-face)) + "Volume face." + :group 'awesome-tray) + +(defface awesome-tray-module-mpd-face + '((((background light)) :inherit awesome-tray-cyan-face) + (t :inherit awesome-tray-cyan-face)) + "Mpd face." + :group 'awesome-tray) + +(defface awesome-tray-module-date-face + '((((background light)) :inherit awesome-tray-grey-face) + (t :inherit awesome-tray-grey-face)) + "Date face." + :group 'awesome-tray) + +(defface awesome-tray-module-celestial-face + '((((background light)) :inherit awesome-tray-grey-face) + (t :inherit awesome-tray-grey-face)) + "Celestial lunar phase and sunrise/set face." + :group 'awesome-tray) + +(defface awesome-tray-module-last-command-face + '((((background light)) :inherit awesome-tray-blue-bright-face) + (t :inherit awesome-tray-blue-bright-face)) + "Date face." + :group 'awesome-tray) + +(defface awesome-tray-module-buffer-name-face + '((((background light)) :inherit awesome-tray-orange-face) + (t :inherit awesome-tray-orange-face)) + "Buffer name face." + :group 'awesome-tray) + +(defface awesome-tray-module-file-path-face + '((((background light)) :inherit awesome-tray-green-path-face) + (t :inherit awesome-tray-green-path-face)) + "Parent dir face." + :group 'awesome-tray) + +(defface awesome-tray-module-parent-dir-face + '((((background light)) :inherit awesome-tray-green-path-face) + (t :inherit awesome-tray-green-path-face)) + "Parent dir face." + :group 'awesome-tray) + +(defface awesome-tray-module-awesome-tab-face + '((((background light)) :inherit awesome-tray-pink-face) + (t :inherit awesome-tray-pink-face)) + "Awesome tab face." + :group 'awesome-tray) + +(defface awesome-tray-module-evil-face + '((((background light)) :inherit awesome-tray-cyan-face) + (t :inherit awesome-tray-cyan-face)) + "Evil state face." + :group 'awesome-tray) + +(defface awesome-tray-module-meow-face + '((((background light)) :inherit awesome-tray-cyan-face) + (t :inherit awesome-tray-cyan-face)) + "Meow state face." + :group 'awesome-tray) + +(defface awesome-tray-module-battery-face + '((((background light)) :inherit awesome-tray-cyan-face) + (t :inherit awesome-tray-cyan-face)) + "Battery state face." + :group 'awesome-tray) + +(defface awesome-tray-module-buffer-read-only-face + '((((background light)) :inherit awesome-tray-red-face) + (t :inherit awesome-tray-red-face)) + "Buffer read only face." + :group 'awesome-tray) + +(defface awesome-tray-module-belong-face + '((((background light)) :inherit awesome-tray-red-face) + (t :inherit awesome-tray-red-face)) + "Buffer read only face." + :group 'awesome-tray) + +(defface awesome-tray-module-input-method-face + '((((background light)) :inherit awesome-tray-cyan-face) + (t :inherit awesome-tray-cyan-face)) + "Input method face." + :group 'awesome-tray) + +(defface awesome-tray-module-clock-face + '((((background light)) :inherit awesome-tray-blue-bright-face) + (t :inherit awesome-tray-blue-bright-face)) + "Org clock face." + :group 'awesome-tray) + +(defface awesome-tray-module-org-pomodoro-face + '((((background light)) :inherit awesome-tray-magenta-face) + (t :inherit awesome-tray-magenta-face)) + "Org-pomodoro face." + :group 'awesome-tray) + +(defface awesome-tray-module-pdf-view-page-face + '((((background light)) :inherit awesome-tray-orange) + (t :inherit awesome-tray-pink-face)) + "Pdf-view-page face." + :group 'awesome-tray) + +(defface awesome-tray-module-flymake-error + '((t :inherit awesome-tray-red-face)) + "Flymake error face." + :group 'awesome-tray) + +(defface awesome-tray-module-flymake-warning + '((t :inherit awesome-tray-yellow-face)) + "Flymake warning face." + :group 'awesome-tray) + +(defface awesome-tray-module-flymake-note + '((t :inherit awesome-tray-blue-bright-face)) + "Flymake note face." + :group 'awesome-tray) + +(provide 'awesome-tray-faces) + +;;; awesome-tray-faces.el ends here diff --git a/lisp/awesome-tray/awesome-tray.el b/lisp/awesome-tray/awesome-tray.el new file mode 100644 index 00000000..04d373a0 --- /dev/null +++ b/lisp/awesome-tray/awesome-tray.el @@ -0,0 +1,1420 @@ +;;; awesome-tray.el --- Modular tray bar + +;; Filename: awesome-tray.el +;; Description: Modular tray bar +;; Author: Andy Stewart +;; Maintainer: Andy Stewart +;; 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) "") + ((evil-emacs-state-p) "") + ((evil-insert-state-p) "") + ((evil-motion-state-p) "") + ((evil-visual-state-p) "") + ((evil-operator-state-p) "") + ((evil-replace-state-p) "") + (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 diff --git a/lisp/awesome-tray/screenshots/README.md b/lisp/awesome-tray/screenshots/README.md new file mode 100644 index 00000000..21a3a6e2 --- /dev/null +++ b/lisp/awesome-tray/screenshots/README.md @@ -0,0 +1,11 @@ +# Screenshots + + + +# With `awesome-tray-second-line` enabled + + + +# With `awesome-tray-position` set to center + + diff --git a/lisp/awesome-tray/screenshots/centered.png b/lisp/awesome-tray/screenshots/centered.png new file mode 100644 index 00000000..5cae1d11 Binary files /dev/null and b/lisp/awesome-tray/screenshots/centered.png differ diff --git a/lisp/awesome-tray/screenshots/screenshot.png b/lisp/awesome-tray/screenshots/screenshot.png new file mode 100644 index 00000000..8a55781b Binary files /dev/null and b/lisp/awesome-tray/screenshots/screenshot.png differ diff --git a/lisp/awesome-tray/screenshots/screenshot2.png b/lisp/awesome-tray/screenshots/screenshot2.png new file mode 100644 index 00000000..a649acef Binary files /dev/null and b/lisp/awesome-tray/screenshots/screenshot2.png differ diff --git a/settings/gui-settings.el b/settings/gui-settings.el index a6936af0..96e7eaf0 100644 --- a/settings/gui-settings.el +++ b/settings/gui-settings.el @@ -160,32 +160,139 @@ DISPLAY-START: `integer', e.g. 3820" (my-view-gnuplot)))) (use-package awesome-tray - :defer 0.2 + ;;:after my-theme + :hook (after-init . awesome-tray-mode) :config (setq awesome-tray-info-padding-right 1) (setq awesome-tray-buffer-name-buffer-changed t) (setq awesome-tray-mode-line-active-color "#008b8b") (setq awesome-tray-mode-line-inactive-color "#333333") - ;; see available modules in `awesome-tray-module-alist' + (setq awesome-tray-file-path-show-filename nil) + (setq awesome-tray-file-path-truncated-name-length 2) + (setq awesome-tray-file-path-full-dirname-levels 2) + + ;; flycheck custom string (defun my-awesome-tray-module-flycheck-info () - (string-trim (flycheck-mode-line-status-text))) + (let ((flycheck-mode-line-prefix "fc")) + (string-trim (flycheck-mode-line-status-text)))) + + ;; flycheck color string (defface my-awesome-tray-module-flycheck-face (list (list t (list :foreground (face-foreground 'font-lock-warning-face)))) "Flycheck module face." :group 'awesome-tray) + + ;; flycheck add as module (add-to-list 'awesome-tray-module-alist - '("flycheck" . (my-awesome-tray-module-flycheck-info my-awesome-tray-module-flycheck-face))) - (setq awesome-tray-active-modules ;; circe parent-dir battery + '("flycheck" . (my-awesome-tray-module-flycheck-info my-awesome-tray-module-flycheck-face))) + + ;; flymake custom string + (defun my-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 "*") + ;;(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 (>= .error 0) + ;; "🔴:" + (concat "" (propertize (number-to-string .error) 'face 'awesome-tray-module-flymake-error))) + (when (>= .warning 0) + ;; "🟠:" + (concat "" (propertize (number-to-string .warning) 'face 'awesome-tray-module-flymake-warning))) + (when (>= .note 0) + ;; "🔵:" + (concat "" (propertize (number-to-string .note) 'face 'awesome-tray-module-flymake-note))) + ) + ":" ;; " " joining string + )) + "" ;; "🟢" no error/warning/note + ))))))) + flymake-state))))) + + ;; flycheck add as module + ;; (add-to-list 'awesome-tray-module-alist + ;; '("flymake" . (my-awesome-tray-module-flymake-info nil))) + (add-to-list 'awesome-tray-module-alist + '("flymake" . (my-awesome-tray-module-flymake-info my-awesome-tray-module-flycheck-face))) + + ;; doc-view custom string + (defun my-awesome-tray-module-doc-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)) + ((featurep 'doc-view) + (let ((state + (cond ((derived-mode-p 'doc-view-mode) (format "%d/%d" (eval '(doc-view-current-page)) (doc-view-last-page-number))) + (t "")))) + state)) + (t "")))) + (defun my-awesome-tray-module-location-or-page-info () + "Show Location or PDF page depends on current mode." + (let ((page-info (my-awesome-tray-module-doc-view-page-info))) + (if (string= page-info "") + (awesome-tray-module-location-info) + page-info))) + + ;; doc-view add as module + (add-to-list 'awesome-tray-module-alist + '("location-or-page" . (my-awesome-tray-module-location-or-page-info awesome-tray-module-location-face))) + + ;; see available modules in `awesome-tray-module-alist' + (setq awesome-tray-active-modules '("file-path" "buffer-name" "buffer-read-only" - "location" + ;; "location" + "location-or-page" "mode-name" "flycheck" + "flymake" "git")) (set-face-foreground 'awesome-tray-module-file-path-face (face-foreground 'font-lock-keyword-face)) (set-face-foreground 'awesome-tray-module-buffer-name-face (face-foreground 'font-lock-constant-face)) (set-face-foreground 'awesome-tray-module-location-face (face-foreground 'vertical-border)) + (set-face-foreground 'awesome-tray-module-location-or-page-face (face-foreground 'vertical-border)) (set-face-foreground 'awesome-tray-module-mode-name-face (face-foreground 'font-lock-string-face)) (defun my-awesome-tray-module-file-path-info-advice (&rest args) "If file path is same as buffer name omit output." @@ -201,7 +308,7 @@ DISPLAY-START: `integer', e.g. 3820" (concat (buffer-name) awesome-tray-buffer-name-buffer-changed-style) (buffer-name)) (format "%s" (buffer-name)))) - (awesome-tray-mode 1)) + ) (use-package doc-view :defer t @@ -233,6 +340,7 @@ DISPLAY-START: `integer', e.g. 3820" (use-package dashboard :delight (dashboard-mode "Db") ;; "\u01F153 + :hook (after-init . dashboard-setup-startup-hook) ;; activate `dashboard' :config ;; see `dashboad-widget' (setq dashboard-icon-type 'all-the-icons) @@ -461,9 +569,7 @@ See also `dashboard-insert-section' for the sequence of elements." `(lambda (&rest _) (switch-to-buffer ,el)) (abbreviate-file-name el))) (add-to-list 'dashboard-item-generators '(custom . dashboard-insert-custom)) - - ;; activate `dashboard' - (dashboard-setup-startup-hook)) + ) ;; too slow if all levels are displayed for a medium large file, ;; therefore not all levels and if toggled on and mode default off