biome-query: infix spam :'-(

This commit is contained in:
Pavel Korytov 2023-07-10 15:41:16 +03:00
parent 648cb287f6
commit 1bc7a354ee

View file

@ -26,6 +26,7 @@
;;; Code: ;;; Code:
(require 'biome-api-data) (require 'biome-api-data)
(require 'font-lock)
(require 'compat) (require 'compat)
(require 'transient) (require 'transient)
@ -51,12 +52,17 @@ have to be displayed separately.")
It is an alist with the following keys: It is an alist with the following keys:
- `:name' - name of the root section. - `:name' - name of the root section.
- `:kind' - name of the group (see `biome-query-groups'). - `:kind' - name of the group (see `biome-query-groups').
- `:parameters' - alist with parameters, where the key is either nil - `:params' - alist with parameters, where the key is either nil (for
(for global parameters) or the value of `:param' key of the global parameters) or the value of `:param' key of the corresponding
corresponding section. section.
In the former case, the value is an alist with values; in the latter In the former case, the value is an alist with values; in the latter
case, the value is a list of variable names available in the group.") case, the value is a list of variable names available in the group.")
(defvar biome-query--layout-cache (make-hash-table :test 'equal)
"Cache for dynamic transient layout.")
(setq biome-query--layout-cache (make-hash-table :test 'equal))
(defclass biome-query--transient-report (transient-suffix) (defclass biome-query--transient-report (transient-suffix)
((transient :initform t)) ((transient :initform t))
"A transient class to display the current report.") "A transient class to display the current report.")
@ -73,6 +79,89 @@ It is an alist with the following keys:
:class 'biome-query--transient-report :class 'biome-query--transient-report
:key "~~1") :key "~~1")
(defclass biome-query--transient-path (transient-suffix)
((transient :initform t))
"A transient class to display the current path.")
(cl-defmethod transient-init-value ((_ biome-query--transient-path))
"A dummy method for `biome-query--transient-report'."
nil)
(cl-defmethod transient-format ((_ biome-query--transient-path))
"Format the current path."
(let* ((scope (oref (or transient--prefix
transient-current-prefix)
scope))
(parents (alist-get :parents scope))
(section (alist-get :section scope)))
(concat
(cl-loop for parent in (reverse parents)
concat (propertize
(alist-get :name parent)
'face 'font-lock-variable-name-face)
concat " > ")
(propertize
(alist-get :name section)
'face 'transient-heading))))
(transient-define-infix biome-query--transient-path-infix ()
:class 'biome-query--transient-path
:key "~~1")
(defclass biome-query--transient-switch-variable (transient-argument)
((name :initarg :name)
(param :initarg :param :initform nil))
"A transient class to display a switch.")
(cl-defmethod transient-init-value ((obj biome-query--transient-switch-variable))
(oset obj value
(not
(null
(member
(oref obj name)
(if-let ((param (oref obj param)))
(cdr
(assoc
param
(alist-get :params biome-query-current)))
(alist-get :params biome-query-current)))))))
(defmacro biome-query--update-list (item list-place add)
`(setf ,list-place
(if ,add
(cons ,item ,list-place)
(delete ,item ,list-place))))
(cl-defmethod transient-infix-read ((obj biome-query--transient-switch-variable))
"Toggle the switch on or off."
(setq my/test obj)
(let ((new-value (not (oref obj value)))
(param (oref obj param))
(name (oref obj name)))
(if param
(biome-query--update-list
name (alist-get param (alist-get :params biome-query-current) nil nil #'equal)
new-value)
(biome-query--update-list
name (alist-get :params biome-query-current nil nil #'equal)
new-value))
new-value))
(cl-defmethod transient-format ((obj biome-query--transient-switch-variable))
"Return a string generated using OBJ's `format'.
%k is formatted using `transient-format-key'.
%d is formatted using `transient-format-description'.
%v is formatted using `transient-format-value'."
(concat
(string-pad (transient-format-key obj) 6)
(transient-format-description obj)
(when (oref obj value)
(propertize " (+)" 'face 'transient-argument))))
(transient-define-infix biome-query--transient-switch-variable-infix ()
:class 'biome-query--transient-switch-variable
:key "~~1")
(defun biome-query--cartesian-product (a b) (defun biome-query--cartesian-product (a b)
"Compute the Cartesian product of A and B." "Compute the Cartesian product of A and B."
(mapcan (mapcan
@ -159,28 +248,51 @@ NAMES is a list of strings."
do (puthash name key keys-by-name))) do (puthash name key keys-by-name)))
keys-by-name)) keys-by-name))
(defun biome-query--section-fields-children (fields keys) (defun biome-query--section-fields-children (fields keys parents cache-key)
"Get transient laoyut for FIELDS. "Get transient laoyut for FIELDS.
FIELDS is a list of fields as defined in `biome-api-parse--page'. FIELDS is a list of fields as defined in `biome-api-parse--page'.
KEYS is the result of `biome-query--unique-keys'." KEYS is the result of `biome-query--unique-keys'. PARENTS is a list
of parent sections."
(when fields (when fields
`(["Fields" (let ((param (seq-some (lambda (s) (alist-get :param s)) parents))
:class transient-columns (infix-name (concat "biome-query--transient-" cache-key "-")))
,@(thread-last (cl-loop
fields for field in fields
(seq-map-indexed for field-api-key = (car field)
(lambda (field idx) (cons field (/ idx biome-query-max-fields-in-row)))) for name = (alist-get :name (cdr field))
(seq-group-by #'cdr) for key = (gethash name keys)
(mapcar (lambda (group) for type = (alist-get :type (cdr field))
(apply #'vector for infix-symbol = (intern (concat infix-name field-api-key))
(mapcar do (eval (pcase type
(lambda (el) ('checkbox
(let* ((field (car el)) `(transient-define-infix ,infix-symbol ()
(name (alist-get :name (cdr field)))) :class 'biome-query--transient-switch-variable
;; TODO :key ,key
(list (gethash name keys) name #'transient-quit-one))) :description ,name
(cdr group))))))]))) :argument ,name
:name ,name
:param ,param))
(_
`(transient-define-infix ,infix-symbol ()
:key ,key
:name ,name)))))
`(["Fields"
:class transient-columns
,@(thread-last
fields
(seq-map-indexed
(lambda (field idx) (cons field (/ idx biome-query-max-fields-in-row))))
(seq-group-by #'cdr)
(mapcar
(lambda (group)
(apply
#'vector
(mapcar
(lambda (el)
(let* ((field-api-key (caar el)))
(list (intern (concat infix-name field-api-key)))))
(cdr group))))))]))))
(defun biome-query--section-sections-children (sections keys parents) (defun biome-query--section-sections-children (sections keys parents)
"Get transient layout for SECTIONS. "Get transient layout for SECTIONS.
@ -201,21 +313,43 @@ list of parent sections."
:transient transient--do-replace)) :transient transient--do-replace))
sections)]))) sections)])))
(defmacro biome-query--with-layout-cache (cache-key &rest body)
"Cache layout for CACHE-KEY.
BODY is the body of the macro."
(declare (indent 1))
`(let ((layout (gethash ,cache-key biome-query--layout-cache)))
(if layout
layout
(let* ((cache-key ,cache-key)
(layout (progn ,@body)))
(puthash ,cache-key layout biome-query--layout-cache)
layout))))
(defun biome-query--section-layout (section parents) (defun biome-query--section-layout (section parents)
"Get transient layout for SECTION. "Get transient layout for SECTION.
SECTION is a form as defined by `biome-api-parse--page'. PARENTS SECTION is a form as defined by `biome-api-parse--page'. PARENTS
is a list of parent sections." is a list of parent sections."
(let* ((sections (or (alist-get :children section) (biome-query--with-layout-cache
(alist-get :sections section))) (string-join
(fields (alist-get :fields section)) (mapcar
(keys (biome-query--unique-keys (lambda (s) (string-replace " " "-" s))
(append (cons
(mapcar (lambda (s) (alist-get :name s)) sections) (alist-get :name section)
(mapcar (lambda (s) (alist-get :name (cdr s))) fields))))) (mapcar (lambda (s) (alist-get :name s)) parents)))
(append "-")
(biome-query--section-fields-children fields keys) (let* ((sections (or (alist-get :children section)
(biome-query--section-sections-children sections keys (cons section parents))))) (alist-get :sections section)))
(fields (alist-get :fields section))
(keys (biome-query--unique-keys
(append
(mapcar (lambda (s) (alist-get :name s)) sections)
(mapcar (lambda (s) (alist-get :name (cdr s))) fields))))
(parents (cons section parents)))
(append
(biome-query--section-fields-children fields keys parents cache-key)
(biome-query--section-sections-children sections keys parents)))))
(defun biome-query--transient-prepare-layout (name suffixes) (defun biome-query--transient-prepare-layout (name suffixes)
"Prepare dynamic transient layout for NAME. "Prepare dynamic transient layout for NAME.
@ -234,13 +368,11 @@ SECTION is a form as defined in `biome-api-parse--page'."
(interactive (list nil)) (interactive (list nil))
(unwind-protect (unwind-protect
(progn (progn
(setq my/test section)
(biome-query--prepare-layout (biome-query--prepare-layout
'biome-query--section 'biome-query--section
(append (append
'([:description '([(biome-query--transient-path-infix)])
(lambda () (alist-get :name (car (oref transient--prefix scope)))) '([(biome-query--transient-report-infix)])
(biome-query--transient-report-infix)])
(biome-query--section-layout section parents) (biome-query--section-layout section parents)
'(["Actions" '(["Actions"
:class transient-row :class transient-row
@ -249,7 +381,7 @@ SECTION is a form as defined in `biome-api-parse--page'."
(transient-setup 'biome-query--section nil nil :scope (transient-setup 'biome-query--section nil nil :scope
`((:section . ,section) `((:section . ,section)
(:parents . ,parents)))) (:parents . ,parents))))
(put 'biome-query-section 'transient--layout nil))) (put 'biome-query-section 'transient--layout nil)))
(transient-define-prefix biome-query () (transient-define-prefix biome-query ()
["Open Meteo Data" ["Open Meteo Data"
@ -268,7 +400,7 @@ SECTION is a form as defined in `biome-api-parse--page'."
(setq biome-query-current (setq biome-query-current
'((:name . ,name) '((:name . ,name)
(:kind . nil) (:kind . nil)
(:parameters . nil)))) (:params . nil))))
(biome-query--section ',params)) (biome-query--section ',params))
:transient transient--do-replace))))] :transient transient--do-replace))))]
["Actions" ["Actions"