emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Community improvements to the Emacs Widget Library manual?


From: Mauro Aranda
Subject: Re: Community improvements to the Emacs Widget Library manual?
Date: Fri, 14 Jul 2023 21:08:25 -0300
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.11.0

bovine@cyberscientist.ca writes:

> On 2023-07-14 10:41, Mauro Aranda wrote:
>> Bryce Carson <bovine@cyberscientist.ca> writes:
>>
>>> Further, I can't seem to get these functions to work as documented or
>>> expected.
>>> Without these defined when I'm creating a widget with the following
>>> code, I do get a button but the internal value is displayed in the
>>> clickable
>>> button. I'd like the external value to be displayed in the button
>>> %v, just
>>> as the menu-tag is is "externally facing".
>>> <<widget>>=
>>> (define-widget 'project-widget 'list
>>>   :tag (let ((s "\n\tProject"))
>>>          (put-text-property 0 (length s) 'face 'bold s) s)
>>>   :format "%t\n%v "
>>>   :offset 0
>>>   :indent 0
>>>   :convert-widget 'widget-types-convert-widget
>>>   :args '((menu-choice
>>>            :tag "EmacSQL-supported backend"
>>>            :format "%[%t%]: %[%v%]"
>>>            :value "sqlite"
>>>            :value-to-external <<menu-choice internal value to
>>> external lambda>>
>>>            :value-to-internal <<menu-choice external value to
>>> internal lambda>>
>>>            (choice-item :menu-tag "MySQL" :value "mysql")
>>>            (choice-item :menu-tag "PostgreSQL" :value "postgresql")
>>>            (choice-item :menu-tag "SQLite" :value "sqlite"))))
>>> <<menu-choice internal value to external lambda>>=
>>> (lambda (widget internal-value)
>>>   "Converts lowercase, internal values to the casing of trademarks."
>>>   (pcase internal-value
>>>     ("mysql" "MySQL")
>>>     ("sqlite" "SQLite")
>>>     ("postgresql" "PostgreSQL")))
>>> <<menu-choice external value to internal lambda>>=
>>> (lambda (widget external-value)
>>>   "Converts the casing of trademarked names to lowercase, internal
>>> values."
>>>   (pcase external-value
>>>     ("MySQL" "mysql")
>>>     ("SQLite" "sqlite")
>> When possible, please post code that can be evaled without making
>> tweaks.
>> Some things I noted:
>> - Since the super is a list widget, then you don't need to specify
>> :convert-widget.  The :convert-widget function is one of the few that
>> gets called for all supers, so you end up converting twice the widget.
>> In this case, it doesn't seem you want that.
>> - You're specifying a value in the internal format for the
>> menu-choice.
>> The manual specifies that when creating a widget or defining a new
>> one, the ‘:value’ should be in the external format.
>> - I think you should give similar conversion functions to all
>> choice-item, and also pass the :value in external format.
>> Let me know if you still find problems after fixing these things.
>
> I fixed those issues and I do not see the invalid or void state, but
> only nil is ever displayed in the buffer.
> Below is the code I defined.

OK, I think you ran into something that's unsupported (maybe a bug, but
I'm not quite sure).

And thank you for providing the code, it made things easier for me to
see it.

> (define-widget 'project-widget 'list
>   "A mimimal example to demonstrate 'styled' choice item buttons in a
>   choice menu."
>   :tag (let ((s "\n\tProject"))
>          (put-text-property 0 (length s) 'face 'bold s) s)
>   :format "%t\n%v "
>
>   :args '((menu-choice
>            :tag "EmacSQL-supported backend"
>            :size 50
>            :format "%[%t%]: %[%v%] \n"
>
>            :value "SQLite"
>            :choice (database-choice-item :menu-tag "SQLite" :value
>            "SQLite")
>
>            :value-to-external menu-choice-value-to-external
>            :value-to-internal menu-choice-value-to-internal
>
>            (database-choice-item :menu-tag "MySQL" :value "MySQL")
>            (database-choice-item :menu-tag "PostgreSQL" :value
>            "PostgreSQL")
>            (database-choice-item :menu-tag "SQLite" :value
>            "SQLite"))))

The menu-choice creation assumes no difference between the internal
format and external format.  So for now, try removing the
:value-to-external and :value-to-internal.  I think it does that
because there's no big reason for converting a menu-choice value, since
the menu-choice will get its value from a valid choice, and the
individual choice is responsible for the conversion between formats.

Oh, and don't use :value and :choice at the same.  Just use :value to
give it a default value.  So this widget should be:

(define-widget 'project-widget 'list
  "A mimimal example to demonstrate 'styled' choice item buttons in a
  choice menu."
  :tag (let ((s "\n\tProject"))
         (put-text-property 0 (length s) 'face 'bold s) s)
  :format "%t\n%v "
  :args '((menu-choice
           :tag "EmacSQL-supported backend"
           :size 50
           :format "%[%t%]: %[%v%] \n"
       :value "MySQL"
           (database-choice-item :menu-tag "MySQL"      :value "MySQL")
           (database-choice-item :menu-tag "PostgreSQL" :value
           "PostgreSQL")
           (database-choice-item :menu-tag "SQLite"     :value
           "SQLite"))))

> (define-widget 'database-choice-item 'choice-item
>   nil
>   :value-to-external #'menu-choice-value-to-external
>   :value-to-internal #'menu-choice-value-to-internal)

And now, you need a :match function for this widget, so that when it
gets passed an external value, such as "MySQL", it returns non-nil.

So maybe something like this:
(define-widget 'database-choice-item 'choice-item
  nil
  :match (lambda (widget value)
       (equal (widget-get widget :value) (widget-apply widget
                               :value-to-internal
                               value)))
  :value-to-external #'menu-choice-value-to-external
  :value-to-internal #'menu-choice-value-to-internal)

You need a custom :match function because otherwise the
database-choice-item would resort to matching like an item, and that's
not good when you have different internal and external formats.
Basically, if you use different formats, you should consider providing a
:match function yourself.

I think with these fixes, your code will run just as you expect it.




reply via email to

[Prev in Thread] Current Thread [Next in Thread]