dotfiles-mirror/.emacs.d/elpa/bui-20210108.1141/bui-info.el
2025-06-29 03:58:41 +03:30

372 lines
13 KiB
EmacsLisp
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;;; bui-info.el --- 'Info' buffer interface for displaying data -*- lexical-binding: t -*-
;; Copyright © 20142017 Alex Kost <alezost@gmail.com>
;; Copyright © 2015 Ludovic Courtès <ludo@gnu.org>
;; 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 <http://www.gnu.org/licenses/>.
;;; Commentary:
;; This file provides 'info' (help-like) buffer interface for displaying
;; an arbitrary data.
;;; Code:
(require 'dash)
(require 'bui-core)
(require 'bui-entry)
(require 'bui-button)
(require 'bui-utils)
(bui-define-groups bui-info)
(defface bui-info-heading
'((((type tty pc) (class color)) :weight bold)
(t :inherit variable-pitch :height 1.2 :weight bold))
"Face for headings."
:group 'bui-info-faces)
(defface bui-info-param-title
'((t :inherit font-lock-type-face))
"Face used for titles of parameters."
:group 'bui-info-faces)
;;; General 'info' variables
(defvar bui-info-format nil
"List of methods for inserting entries.
Each METHOD should be either nil, a function or a list.
If METHOD is nil, newline is inserted at point.
If METHOD is a function, it is called with an entry as argument.
If METHOD is a list, it should have the following form:
(PARAM INSERT-TITLE INSERT-VALUE)
PARAM is a name of the entry parameter.
INSERT-TITLE may be either a symbol or a list. If it is a
symbol, it should be a function or an alias from
`bui-info-title-aliases', in which case it is called with title
as argument. If it is a list, it should have a
form (FUN-OR-ALIAS [ARGS ...]), in which case FUN-OR-ALIAS is
called with title and ARGS as arguments.
INSERT-VALUE may be either a symbol or a list. If it is a
symbol, it should be a function or an alias from
`bui-info-value-aliases', in which case it is called with value
and entry as arguments. If it is a list, it should have a
form (FUN-OR-ALIAS [ARGS ...]), in which case FUN-OR-ALIAS is
called with value and ARGS as arguments.
After inserting title/value with such a list METHOD, a new line
is inserted.
Parameters are inserted in the same order as defined by this list.")
(put 'bui-info-format 'permanent-local t)
(defcustom bui-info-ignore-empty-values nil
"If non-nil, do not display non-boolean parameters with nil values."
:type 'boolean
:group 'bui-info)
(put 'bui-info-ignore-empty-values 'permanent-local t)
(defcustom bui-info-ignore-void-values t
"If non-nil, do not display non-existing parameters."
:type 'boolean
:group 'bui-info)
(put 'bui-info-ignore-void-values 'permanent-local t)
(defcustom bui-info-fill t
"If non-nil, fill string parameters to fit the window.
If nil, insert text parameters in a raw form."
:type 'boolean
:group 'bui-info)
(put 'bui-info-fill 'permanent-local t)
(defcustom bui-info-param-title-format "%-18s: "
"String used to format a title of a parameter.
It should be a '%s'-sequence. After inserting a title formatted
with this string, a value of the parameter is inserted.
This string is used by `bui-info-insert-title-format'."
:type 'string
:group 'bui-info)
(put 'bui-info-param-title-format 'permanent-local t)
(defcustom bui-info-multiline-prefix
(make-string (length (format bui-info-param-title-format " "))
?\s)
"String used to format multi-line parameter values.
If a value occupies more than one line, this string is inserted
in the beginning of each line after the first one.
This string is used by `bui-info-insert-value-format'."
:type 'string
:group 'bui-info)
(put 'bui-info-multiline-prefix 'permanent-local t)
(defcustom bui-info-delimiter "\n\f\n"
"String used to separate entries."
:type 'string
:group 'bui-info)
(put 'bui-info-delimiter 'permanent-local t)
(defconst bui-info-symbol-specifications
'((:delimiter delimiter t)
(:fill fill t)
(:format format always)
(:ignore-empty-values ignore-empty-values t)
(:ignore-void-values ignore-void-values t)
(:multiline-prefix multiline-prefix t)
(:title-format param-title-format t))
"Specifications for generating 'info' variables.
See `bui-symbol-specifications' for details.")
;;; Wrappers for 'info' variables
(defun bui-info-symbol (entry-type symbol)
"Return symbol for ENTRY-TYPE and 'info' buffer type."
(bui-symbol entry-type 'info symbol))
(defun bui-info-symbol-value (entry-type symbol)
"Return SYMBOL's value for ENTRY-TYPE and 'info' buffer type."
(bui-symbol-value entry-type 'info symbol))
(defun bui-info-param-title (entry-type param)
"Return a title of an ENTRY-TYPE parameter PARAM."
(bui-param-title entry-type 'info param))
(defun bui-info-format (entry-type)
"Return 'info' format for ENTRY-TYPE."
(bui-info-symbol-value entry-type 'format))
(defun bui-info-displayed-params (entry-type)
"Return a list of ENTRY-TYPE parameters that should be displayed."
(-non-nil
(--map (pcase it
(`(,param . ,_) param))
(bui-info-format entry-type))))
;;; Inserting entries
(defvar bui-info-title-aliases
'((format . bui-info-insert-title-format)
(simple . bui-info-insert-title-simple))
"Alist of aliases and functions to insert titles.")
(defvar bui-info-value-aliases
'((format . bui-info-insert-value-format)
(indent . bui-info-insert-value-indent)
(simple . bui-info-insert-value-simple)
(time . bui-info-insert-time))
"Alist of aliases and functions to insert values.")
(defun bui-info-title-function (fun-or-alias)
"Convert FUN-OR-ALIAS into a function to insert a title."
(or (bui-assq-value bui-info-title-aliases fun-or-alias)
fun-or-alias))
(defun bui-info-value-function (fun-or-alias)
"Convert FUN-OR-ALIAS into a function to insert a value."
(or (bui-assq-value bui-info-value-aliases fun-or-alias)
fun-or-alias))
(defun bui-info-title-method->function (method)
"Convert title METHOD into a function to insert a title."
(pcase method
((pred null) #'ignore)
((pred symbolp) (bui-info-title-function method))
(`(,fun-or-alias . ,rest-args)
(lambda (title)
(apply (bui-info-title-function fun-or-alias)
title rest-args)))
(_ (error "Unknown title method '%S'" method))))
(defun bui-info-value-method->function (method)
"Convert value METHOD into a function to insert a value."
(pcase method
((pred null) #'ignore)
((pred functionp) method)
(`(,fun-or-alias . ,rest-args)
(lambda (value _)
(apply (bui-info-value-function fun-or-alias)
value rest-args)))
(_ (error "Unknown value method '%S'" method))))
(defun bui-info-insert-entries (entries entry-type)
"Display ENTRY-TYPE ENTRIES in the current info buffer."
(bui-mapinsert (lambda (entry)
(bui-info-insert-entry entry entry-type))
entries
bui-info-delimiter)
(bui-history-insert-buttons))
(defun bui-info-insert-entry (entry entry-type &optional indent-level)
"Insert ENTRY-TYPE ENTRY into the current info buffer.
If INDENT-LEVEL is non-nil, indent displayed data by this number
of `bui-indent' spaces."
(bui-with-indent (* (or indent-level 0)
bui-indent)
(dolist (spec (bui-info-format entry-type))
(bui-info-insert-entry-unit spec entry entry-type))))
(defun bui-info-insert-entry-unit (format-spec entry entry-type)
"Insert title and value of a PARAM at point.
ENTRY is alist with parameters and their values.
ENTRY-TYPE is a type of ENTRY."
(pcase format-spec
((pred null)
(bui-newline))
((pred functionp)
(funcall format-spec entry))
(`(,param ,title-method ,value-method)
(let* ((value (bui-entry-value entry param))
(void? (bui-void-value? value))
(empty? (null value))
(boolean? (bui-boolean-param? entry-type 'info param)))
(unless (or (and bui-info-ignore-void-values void?)
(and bui-info-ignore-empty-values
empty? (not boolean?)))
(let ((title (bui-info-param-title entry-type param))
(insert-title (bui-info-title-method->function title-method))
(insert-value (bui-info-value-method->function value-method)))
(funcall insert-title title)
(cond
(void? (insert bui-empty-string))
((and empty? boolean?) (insert bui-false-string))
(t (funcall insert-value value entry)))
(bui-newline)))))
(_ (error "Unknown format specification '%S'" format-spec))))
(defun bui-info-insert-title-simple (title &optional face)
"Insert \"TITLE: \" string at point.
If FACE is nil, use `bui-info-param-title'."
(bui-format-insert title
(or face 'bui-info-param-title)
"%s: "))
(defun bui-info-insert-title-format (title &optional face)
"Insert TITLE using `bui-info-param-title-format' at point.
If FACE is nil, use `bui-info-param-title'."
(bui-format-insert title
(or face 'bui-info-param-title)
bui-info-param-title-format))
(defun bui-info-insert-value-simple (value &optional button-or-face indent)
"Format and insert parameter VALUE at point.
VALUE may be split into several short lines to fit the current
window, depending on `bui-info-fill', and each line is indented
with INDENT number of spaces.
If BUTTON-OR-FACE is a button type symbol, transform VALUE into
this (these) button(s) and insert each one on a new line. If it
is a face symbol, propertize inserted line(s) with this face."
(or indent (setq indent 0))
(bui-with-indent indent
(let* ((button? (bui-button-type? button-or-face))
(face (unless button? button-or-face))
(fill-col (unless (or button?
(and (stringp value)
(not bui-info-fill)))
(- (bui-fill-column) indent)))
(value (if (and value button?)
(bui-buttonize value button-or-face "\n")
value)))
(bui-split-insert value face fill-col "\n"))))
(defun bui-info-insert-value-indent (value &optional button-or-face)
"Format and insert parameter VALUE at point.
This function is intended to be called after inserting a title
with `bui-info-insert-title-simple'.
VALUE may be split into several short lines to fit the current
window, depending on `bui-info-fill', and each line is indented
with `bui-indent'.
For the meaning of BUTTON-OR-FACE, see `bui-info-insert-value-simple'."
(when value (bui-newline))
(bui-info-insert-value-simple value button-or-face bui-indent))
(defun bui-info-insert-value-format (value &optional button-or-face
&rest button-properties)
"Format and insert parameter VALUE at point.
This function is intended to be called after inserting a title
with `bui-info-insert-title-format'.
VALUE may be split into several short lines to fit the current
window, depending on `bui-info-fill' and
`bui-info-multiline-prefix'. If VALUE is a list, its elements
will be separated with `bui-list-separator'.
If BUTTON-OR-FACE is a button type symbol, transform VALUE into
this (these) button(s). If it is a face symbol, propertize
inserted line(s) with this face.
BUTTON-PROPERTIES are passed to `bui-buttonize' (only if
BUTTON-OR-FACE is a button type)."
(let* ((button? (bui-button-type? button-or-face))
(face (unless button? button-or-face))
(fill-col (when (or button?
bui-info-fill
(not (stringp value)))
(- (bui-fill-column)
(length bui-info-multiline-prefix))))
(value (if (and value button?)
(apply #'bui-buttonize
value button-or-face bui-list-separator
button-properties)
value)))
(bui-split-insert value face fill-col
(concat "\n" bui-info-multiline-prefix))))
(defun bui-info-insert-time (time &optional face)
"Insert formatted time string using TIME at point.
See `bui-get-time-string' for the meaning of TIME."
(bui-format-insert (bui-get-time-string time)
(or face 'bui-time)))
;;; Major mode
(defvar bui-info-mode-map
(let ((map (make-sparse-keymap)))
(set-keymap-parent
map (make-composed-keymap (list bui-map button-buffer-map)
special-mode-map))
map)
"Keymap for `bui-info-mode' buffers.")
(define-derived-mode bui-info-mode special-mode "BUI-Info"
"Parent mode for displaying data in 'info' form."
(bui-info-initialize))
(defun bui-info-initialize ()
"Set up the current 'info' buffer."
;; Without this, syntactic fontification is performed, and it may
;; break highlighting. For example, if there is a single "
;; (double-quote) character, the default syntactic fontification
;; highlights the rest text after it as a string.
;; See (info "(elisp) Font Lock Basics") for details.
(setq font-lock-defaults '(nil t)))
(provide 'bui-info)
;;; bui-info.el ends here