summaryrefslogtreecommitdiff
path: root/modally.el
diff options
context:
space:
mode:
Diffstat (limited to 'modally.el')
-rw-r--r--modally.el241
1 files changed, 241 insertions, 0 deletions
diff --git a/modally.el b/modally.el
new file mode 100644
index 0000000..d029ee7
--- /dev/null
+++ b/modally.el
@@ -0,0 +1,241 @@
+;;; modally.el --- An Emacs mode-line -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2024 Blake Romero
+
+;; Author: Blake Romero <codeblake@outlook.com>
+;; Keywords: extensions
+
+;; 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 this program. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+
+;;; Code:
+(require 'subr-x)
+(require 'cl-lib)
+(require 'vc-git)
+(require 'flymake)
+(require 'org-timer)
+
+(require 'modally-faces)
+
+;; FUNCTIONS
+(defun modally--buffer-name ()
+ "Return a propertized buffer name string."
+ (let* ((buffer-face (cond
+ ((buffer-modified-p) 'modally-buffer-modified)
+ (buffer-read-only 'modally-buffer-readonly)
+ ('modally-buffer)))
+ (buffer-name (if buffer-file-name
+ (if (string-match "^\\(/home/[^/]+\\)\\(.+\\)"
+ buffer-file-name)
+ (concat "~" (match-string 2 buffer-file-name))
+ buffer-file-name)
+ (buffer-name (current-buffer))))
+ (spath (string-split buffer-name "/")))
+
+ ;; Format
+ (if (> (length spath) 1)
+ ;; if buffer has a path
+ (let ((path (string-join (butlast spath) "/"))
+ (filename (car (last spath))))
+ (format "\s%s/%s"
+ (propertize path 'face 'modally-buffer-path)
+ (propertize filename 'face buffer-face)))
+ ;; if a buffer
+ (format "\s%s" (propertize buffer-name 'face buffer-face))
+ )))
+
+(defun modally--major-mode ()
+ "Return a propertized major mode string."
+ (let ((mode (string-remove-suffix "-mode" (symbol-name major-mode))))
+ (format-mode-line (format "\s%s" mode) 'modally-major-mode)))
+
+(defun modally--line-column ()
+ "Return a propertized line column position."
+ (format-mode-line
+ "\sC%C"
+ `(,(let ((column (current-column)))
+ (cond
+ ((and (>= column (- fill-column 10))
+ (< column fill-column))
+ 'warning)
+ ((>= column fill-column)
+ 'modally-column-error))))))
+
+(defun modally--git-branch ()
+ "Return a propertized Git branch string."
+ (when-let* ((buffer (buffer-file-name))
+ (branch (vc-git--symbolic-ref buffer)))
+ (format "\s%s |" (propertize branch 'face 'modally-git-branch))))
+
+(defun modally--flymake-diagnostics ()
+ "Return `flymake-mode' alert counts."
+ (let ((errors 0) (warnings 0) (notes 0) (alerts))
+ (dolist (d (flymake-diagnostics))
+ (pcase (flymake-diagnostic-type d)
+ (':error (cl-incf errors))
+ (':warning (cl-incf warnings))
+ (':note (cl-incf notes))))
+ (when (or (> errors 0) (> warnings 0) (> notes 0))
+ (when (> notes 0)
+ (cl-pushnew
+ (propertize (format "i%s" notes) 'face 'modus-themes-fg-blue) alerts))
+ (when (> warnings 0)
+ (cl-pushnew
+ (propertize (format "w%s" warnings) 'face 'warning) alerts))
+ (when (> errors 0)
+ (cl-pushnew
+ (propertize (format "e%s" errors) 'face 'error) alerts))
+ (format "\s%s |" (string-join alerts "\s")))))
+
+(defun modally--approx-time (time)
+ "Return an approximation of TIME."
+ (let ((time (replace-regexp-in-string "<\\|>" "" time))
+ (h (string-to-number
+ (nth 0 (string-split time ":"))))
+ (m (string-to-number
+ (nth 1 (string-split time ":"))))
+ (s (string-to-number
+ (nth 2 (string-split time ":")))))
+ (cond
+ ((and (eq h 0) (eq m 0))
+ (format "%ds" s))
+ ((and (eq h 0) (> m 0))
+ (format "~%dm" m))
+ ((and (> h 0) (> m 0))
+ (format "~%dh:%dm" h m)))))
+
+(defun modally--org-timer ()
+ "Return a timer from `org-timer'."
+ (when (or org-timer-mode-line-timer
+ org-timer-pause-time)
+ (let ((face (if org-timer-pause-time
+ 'modally-org-timer-pause
+ 'modally-org-timer)))
+ (format "\s%s |"
+ (propertize
+ (modally--approx-time org-timer-mode-line-string)
+ 'face face)))))
+
+;; VARIABLES
+(defvar modally-display-buffer-name
+ '(:eval (modally--buffer-name))
+ "Modeline construct to display the buffer name.")
+
+(defvar modally-display-major-mode
+ '(:eval (modally--major-mode))
+ "Modeline construct to display the major mode.")
+
+(defvar modally-display-git-branch
+ '(:eval (modally--git-branch))
+ "Modeline construct to display the Git branch name.")
+
+(defvar modally-display-line-column
+ '(:eval (modally--line-column))
+ "Modeline construct to display line & column position.")
+
+(defvar modally-display-line-row
+ '(:eval (format-mode-line "\sL%l"))
+ "Modeline construct to display line & column position.")
+
+(defvar modally-display-file-size
+ '(:eval (format-mode-line "\s%I"))
+ "Modeline construct to display file size of buffer.")
+
+(defvar modally-display-flymake
+ '(:eval (modally--flymake-diagnostics))
+ "Modeline construct to display flymake info.")
+
+(defvar modally-display-org-timer
+ '(:eval (modally--org-timer))
+ "Modeline construct to display `org-timer' info.")
+
+;; set as risky local variable
+(dolist (construct '(modally-display-buffer-name
+ modally-display-major-mode
+ modally-display-git-branch
+ modally-display-line-row
+ modally-display-line-column
+ modally-display-file-size
+ modally-display-flymake
+ modally-display-org-timer))
+ (put construct 'risky-local-variable #'stringp))
+
+;; FORMATS
+(defvar modally-format-default
+ `("%e"
+ modally-display-buffer-name
+
+ mode-line-format-right-align
+ modally-display-org-timer
+ modally-display-line-row
+ modally-display-line-column
+ " |"
+ modally-display-git-branch
+ modally-display-file-size
+ " |"
+ modally-display-flymake
+ modally-display-major-mode
+ )
+ "Default modally format for the mode-line.")
+
+;; HELPERS
+(defun modally--set-face ()
+ "Set mode-line face."
+ (set-face-attribute
+ 'mode-line-active nil
+ :background "black"
+ :foreground "white"
+ :box '(:line-width (20 . 2) :color "#444444"))
+ (set-face-attribute
+ 'mode-line-inactive nil
+ :background "black"
+ :foreground "grey"
+ :box '(:line-width (20 . 2) :color "#222222")))
+
+(defun modally--reset-face()
+ "Reset mode-line face."
+ (set-face-attribute
+ 'mode-line nil
+ :background "black"
+ :foreground "white"
+ :box t))
+
+(defun modally--reset-mode-line ()
+ "Reset mode-line."
+ (setq-default mode-line-format (car (get 'mode-line-format 'standard-value)))
+ (modally--reset-face))
+
+(defun modally--set-mode-line ()
+ "Set modally mode-line."
+ (setq-default mode-line-format modally-format-default)
+ (with-eval-after-load 'keycast
+ (setq-default keycast-mode-line-insert-after 'modally-display-git-branch))
+ (modally--set-face))
+
+;; MODE
+;;;###autoload
+(define-minor-mode modally-mode
+ "An Emacs mode-line."
+ :group 'modally
+ :global t
+ :require '(subr-x vc-git flymake cl-lib)
+ :lighter " MDL"
+ (if modally-mode
+ (modally--set-mode-line)
+ (modally--reset-mode-line)))
+
+(provide 'modally)
+;;; modally.el ends here