;;; jao-mode-line.el --- mode-line info -*- lexical-binding: t; -*-

;; Copyright (C) 2022, 2025  jao

;; Author: jao <mail@jao.io>
;; Keywords: convenience

;; 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:

;; Using jao-minibuffer to display mode-line info in the minibuffer,
;; or toggle it off in non-active windows.

;;; Code:

(require 'jao-minibuffer)


;;;; mode line toggle
(defun jao-mode-line--face-height (face &optional all)
  (let* ((h (face-attribute face :height (window-frame)))
         (nh (if (eq 'unspecified h) 10 'unspecified)))
    (set-face-attribute face (when (not all) (window-frame)) :height nh)))

(defun jao-mode-line--set-inactive-face (x frame)
  (unless (eq x (face-attribute 'mode-line-inactive :height frame))
    (set-face-attribute 'mode-line-inactive frame :height x)))

;;;###autoload
(defun jao-mode-line-toggle (&optional all)
  (interactive "P")
  (jao-mode-line--face-height 'mode-line-active all))

;;;###autoload
(defun jao-mode-line-toggle-inactive (&optional all)
  (interactive "P")
  (jao-mode-line--face-height 'mode-line-inactive all))

(defun jao-mode-line--old-str ()
  (thread-first (format-mode-line jao-mode-line--old-format)
                (substring-no-properties)
                (string-trim)))

;;;###autoload
(defun jao-mode-line-echo ()
  (interactive)
  (message "%s" (jao-mode-line--old-str))
  (setq-local header-line-format
              (if header-line-format nil jao-mode-line--old-format)))

;;;###autoload
(defun jao-mode-line-hide-inactive (frame)
  (jao-mode-line--set-inactive-face 10 frame))

;;;###autoload
(defun jao-mode-line-show-inactive (frame)
  (jao-mode-line--set-inactive-face 'unspecified frame))


;;;; mode line format

(defvar exwm-class-name nil)

(defvar jao-mode-line--position
  '(exwm-class-name
    ("")
    ("%n %2c %l " (:eval (format "%d" (line-number-at-pos (point-max)))))))

(defvar-local eww-data nil)

(defvar jao-mode-line--bid
  '(:eval (cond ((derived-mode-p 'gnus-group-mode
                                 'gnus-article-mode
                                 'gnus-summary-mode)
                 mode-line-buffer-identification)
                ((not (null eww-data))
                 (or (plist-get eww-data :title) "No title"))
                (t "%b"))))

(defvar jao-mode-line--format
  `("%[" (:propertize ,jao-mode-line--bid face jao-themes-f00) "%]"
    (:propertize " (" face jao-themes-dimm)
    (:propertize mode-name face jao-themes-f00)
    (:propertize ("" minor-mode-alist) face jao-themes-f11)
    (:propertize ")" face jao-themes-dimm)
    (:propertize (vc-mode vc-mode) face jao-themes-f10)
    (:propertize mode-line-position face jao-themes-f12)
    " "
    global-mode-string
    (:propertize (" %Z%*%+ " (current-input-method current-input-method-title))
                 face jao-themes-warning)
    (:propertize "·" display "")))


;;;; mode line in minibuffer

(defvar jao-mode-line--old-format mode-line-format)
(defvar jao-mode-line--face nil)
(defvar jao-mode-line--inactive-face nil)
(defvar jao-mode-line--props
  '(:box :height :background :foreground :overline :underline :extend))

(defun jao-mode-line--extract-face (inactive)
  (let ((atts nil)
        (face (if inactive 'mode-line-inactive 'mode-line)))
    (dolist (a jao-mode-line--props)
      (push (face-attribute face a) atts)
      (push a atts))
    (set (if inactive 'jao-mode-line--inactive-face 'jao-mode-line--face) atts)))

(defun jao-mode-line--revert-face (inactive)
  (apply #'set-face-attribute (if inactive 'mode-line-inactive 'mode-line) nil
         (if inactive jao-mode-line--inactive-face jao-mode-line--face)))

(defun jao-mode-line-adjust-faces ()
  (interactive)
  (let ((bg (and (display-graphic-p)
                 (frame-parameter nil 'background-color)))
        (ol (and (display-graphic-p) jao-minibuffer-active-buffer-line-color))
        (ul (and (display-graphic-p)
                 jao-minibuffer-inactive-buffer-line-color)))
    (jao-mode-line--extract-face nil)
    (jao-mode-line--extract-face t)
    (set-face-attribute 'mode-line-active nil :box nil :height 10
                        :background bg :foreground bg
                        :overline ol :underline ul :extend t)
    (set-face-attribute 'mode-line-inactive nil :box nil :height 10
                        :background bg :foreground bg
                        ;; :overline bg
                        :underline ul :extend t)))

(defun jao-mode-line--maybe-refresh ()
  (when (mode-line-window-selected-p) (jao-minibuffer-refresh)))

(defconst jao-mode-line--hidden-format
  '("" (:eval (jao-mode-line--maybe-refresh))))

(defun jao-mode-line--add-to-minibuffer (order msg-p)
  (interactive)
  (setq jao-mode-line--old-format mode-line-format)
  (setq-default mode-line-format jao-mode-line--hidden-format)
  (setq-default mode-line-position jao-mode-line--position)
  (dolist (b (buffer-list))
    (with-current-buffer b
      (setq-local mode-line-format jao-mode-line--hidden-format)))
  (if msg-p
      (jao-minibuffer-add-msg-variable '(jao-mode-line--old-str) (or order 90))
    (jao-minibuffer-add-variable 'jao-mode-line--format (or order 90)))
  (jao-mode-line-adjust-faces))

;;;###autoload
(defun jao-mode-line-add-to-minibuffer-right (&optional order)
  (interactive)
  (jao-mode-line--add-to-minibuffer order nil))

;;;###autoload
(defun jao-mode-line-add-to-minibuffer-left (&optional order)
  (interactive)
  (jao-mode-line--add-to-minibuffer order t))

;;;###autoload
(defun jao-mode-line-remove-from-minibuffer ()
  (interactive)
  (jao-mode-line--revert-face nil)
  (jao-mode-line--revert-face t)
  (setq-default mode-line-format jao-mode-line--old-format)
  (dolist (b (buffer-list))
    (with-current-buffer b
      (setq-local mode-line-format jao-mode-line--old-format)))
  (jao-minibuffer-remove-variable 'jao-mode-line--format)
  (jao-minibuffer-remove-variable '(jao-mode-line--old-str)))


(provide 'jao-mode-line)
;;; jao-mode-line.el ends here
