Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to make presets for prefix's initial value? #183

Closed
stasvlasov opened this issue Dec 28, 2021 · 4 comments
Closed

How to make presets for prefix's initial value? #183

stasvlasov opened this issue Dec 28, 2021 · 4 comments
Labels
enhancement New feature or request

Comments

@stasvlasov
Copy link

What would be a 'correct' way to approach setting presets for initial prefix value while in the transient so that the user can clearly see which arguments are changing when switching between different presets? Is there something already build-in that I can use for that?

For example, it would be very intuitive if one could simply write something like:

  (transient-define-prefix imaginary-example-of-presets-prefix ()
    :value ["Presets"
            ("1" "Preset 1" ("--int=0" "--color=red" "--flag"))
            ("2" "Preset 2" ("--int=100" "--color=green"))]
    ["Settings"
     ("i" "Set integer value" "--int=")
     ("c" "Set color" "--color=")
     ("f" "Set flag" "--flag")]
    ["Actions"
     ("x" "Execute cli command with args" command-that-takes-int-and-color-args)])
@tarsius
Copy link
Member

tarsius commented Dec 29, 2021

I'll probably implement something like that eventually.

If you need it now, #89 contains some hints.

@tarsius tarsius added the enhancement New feature or request label Dec 29, 2021
@stasvlasov
Copy link
Author

stasvlasov commented Jan 2, 2022

First, Happy New Year! Thank you for the reference. It got me thinking that a new infix class could be a nice solution for presets. But the bit I was actually looking for was in the transient-history-prev/next functions, i.e. to (re)set values for all suffixes after setting prefix's default value you just need to (mapc #'transient-init-value transient--suffixes)). Here is a possible solution/proof of concept for transient-preset class:

(defclass transient-preset (transient-infix)
  ((transient                            :initform t)
   (format      :initarg :format         :initform " %k %d %v")
   (arguments   :initarg :arguments))
  "Class used for command-line arguments presets.")

(cl-defmethod transient-init-value ((obj transient-preset))
  "if default values match the arguments slot of transient_preset then set its init value to t"
  (oset obj value
        (seq-set-equal-p (oref obj arguments)
                         (oref transient--prefix value))))

(cl-defmethod transient-infix-read ((obj transient-preset))
  "Toggle the preset on or off setting all the arguments to corresponding infixes."
  (seq-set-equal-p (oref obj arguments)
                   (transient-args transient-current-command)))

(cl-defmethod transient-infix-set ((obj transient-preset) value)
  "Toggle the preset on or off setting all the arguments to corresponding infixes."
  (oset obj value value)
  (unless value
    (oset transient--prefix value (oref obj arguments))
    (mapc #'transient-init-value transient--suffixes)))

(cl-defmethod transient-format-value ((obj transient-preset))
  (propertize
   (concat "[" (mapconcat 'identity (oref obj arguments) " ") "]")
   'face (if (oref obj value)
             'transient-argument
           'transient-inactive-argument)))

(cl-defmethod transient-infix-value ((_ transient-preset))
  "Return nil, which means \"no value\"."
  nil)

Usage example:

(transient-define-suffix command-that-takes-cli-args (&optional args)
  "Displays current transient args"
  (interactive (list (transient-args transient-current-command)))
  (print args))

(transient-define-infix preset-1 ()
  :class transient-preset
  :arguments '("--int=0" "--color=red" "--flag"))

(transient-define-infix preset-2 ()
  :class transient-preset
  :arguments '("--int=100" "--color=green"))

(transient-define-prefix imaginary-example-of-presets-prefix ()
  :value '("--int=0" "--color=red" "--flag")
  ["Presets"
   ("1" "Preset 1" preset-1)
   ("2" "Preset 2" preset-2)]
  ["Settings"
   ("i" "Set integer value" "--int=")
   ("c" "Set color" "--color=")
   ("f" "Set flag" "--flag")]
  ["Actions"
   ("x" "Execute cli command with args" command-that-takes-cli-args)])

(imaginary-example-of-presets-prefix)

It works as expected. However, it would be great if the current preset can be deactivated (reset it's value to nil) when you change some infixes individually and the current prefix arguments no longer matches the preset's arguments. Any ideas/tips how to achieve that?

@tarsius
Copy link
Member

tarsius commented Oct 26, 2023

Happy New Year to you too! ;D

I'll probably add something like this to Transient, probably after implementing :-/:+ as an alternative to :=. These would modify the active arguments, instead of replacing them. I also plan to add a command that saves currently active arguments on the fly.

Implementation:

(defclass transient--preset (transient-suffix)
  ((set :initarg := :initform nil))
  "Class used by the `transient-preset' suffix command.")

(transient-define-suffix transient-preset ()
  "Put this preset into action."
  :class transient--preset
  :transient t
  (interactive)
  (setf (oref transient--prefix value)
        (oref (transient-suffix-object) set)))

(cl-defmethod transient-format-description ((obj transient--preset))
  (pcase-let* (((eieio description key set) obj)
               ((eieio value) transient--prefix)
               (active (seq-set-equal-p set value)))
    (concat (propertize (if description
                            (concat description " ")
                          (format "Preset %s " key))
                        'face (and active 'transient-argument))
            (format (propertize "(%s)" 'face 'transient-delimiter)
                    (propertize (mapconcat 'identity set " ")
                                'face (if active
                                          'transient-argument
                                        'transient-inactive-argument))))))

Demo:

(transient-define-prefix demo ()
  :value '("--int=0" "--color=red" "--flag")
  :refresh-suffixes t
  ["Presets"
   ("1" transient-preset := ("--int=0" "--color=red" "--flag"))
   ("2" transient-preset := ("--int=100" "--color=green"))]
  ["Settings"
   ("i" "Set integer value" "--int=")
   ("c" "Set color" "--color=")
   ("f" "Set flag" "--flag")]
  ["Actions"
   (transient-echo-arguments)])

;; (demo)

@tarsius
Copy link
Member

tarsius commented Jun 22, 2024

I've merged an updated version of the above.

:-/:+ as an alternative to :=. These would modify the active arguments, instead of replacing them. I also plan to add a command that saves currently active arguments on the fly.

I haven't done that for now, but if there actually is a need, its still on the table.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants