unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* [ELPA] New package: dict
@ 2023-05-11 13:22 Eshel Yaron
  2023-05-11 13:59 ` Eli Zaretskii
  2023-05-11 14:18 ` Philip Kaludercic
  0 siblings, 2 replies; 42+ messages in thread
From: Eshel Yaron @ 2023-05-11 13:22 UTC (permalink / raw)
  To: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 1335 bytes --]

Hey all,

I want to propose a new package to GNU ELPA, called Dict or dict.el.

Please find below an appropriate patch for elpa.git.

Similarly to the (now built-in) dictionary.el library, Dict obtains and displays
dictionary definitions from RFC2229 dictionary servers.

Dict's differentiation comes from its simplicity and extensibility--while
dictionary.el defines a bespoke major mode and interface for browsing word
definitions, Dict leverages Emacs's Help mode by default.  It also let's users
extend and control most aspects of its behavior via customization options.  See
the manual in the repo or online at https://eshelyaron.com/dict.html for more
information.

The main motivation behind this package was to resolve some usability issues
that I came across with dictionary.el.  Namely, I'm not satisfied with the fact
that dictionary.el unconditionally switches to the *Dictionary* buffer when
displaying a definition, and I don't appreciate how it tries to remember my
previous windows configuration and revert back to it when I close the
*Dictionary* buffer with the q key.  Of course, I'm open to the possibility of
modifying dictionary.el instead of adding this separate package GNU ELPA if
anyone thinks that's preferable, but I also think it would be nice to let people
try out Dict and get some feedback beforehand.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-elpa-packages-dict-New-package.patch --]
[-- Type: text/x-patch, Size: 725 bytes --]

From 623c4d3b8be00f180e03480633a24ab61326e5cc Mon Sep 17 00:00:00 2001
From: Eshel Yaron <me@eshelyaron.com>
Date: Thu, 11 May 2023 14:20:16 +0300
Subject: [PATCH] * elpa-packages (dict): New package

---
 elpa-packages | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/elpa-packages b/elpa-packages
index d5603f7803..fab548b336 100644
--- a/elpa-packages
+++ b/elpa-packages
@@ -201,6 +201,8 @@
   :news "CHANGELOG.org"
   :readme "README.md")
  (devdocs		:url "https://github.com/astoff/devdocs.el")
+ (dict		        :url "git://git.eshelyaron.com/dict.git"
+  :doc "README.org")
  (dict-tree		:url "http://www.dr-qubit.org/git/predictive.git"
   :manual-sync t ;; The upstream doesn't exist any more!
   )
-- 
2.40.1


[-- Attachment #3: Type: text/plain, Size: 18 bytes --]


-- 
Best,

Eshel

^ permalink raw reply related	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-11 13:22 [ELPA] New package: dict Eshel Yaron
@ 2023-05-11 13:59 ` Eli Zaretskii
  2023-05-11 14:14   ` Philip Kaludercic
  2023-05-11 14:18 ` Philip Kaludercic
  1 sibling, 1 reply; 42+ messages in thread
From: Eli Zaretskii @ 2023-05-11 13:59 UTC (permalink / raw)
  To: Eshel Yaron; +Cc: emacs-devel

> From: Eshel Yaron <me@eshelyaron.com>
> Date: Thu, 11 May 2023 16:22:06 +0300
> 
> The main motivation behind this package was to resolve some usability issues
> that I came across with dictionary.el.  Namely, I'm not satisfied with the fact
> that dictionary.el unconditionally switches to the *Dictionary* buffer when
> displaying a definition, and I don't appreciate how it tries to remember my
> previous windows configuration and revert back to it when I close the
> *Dictionary* buffer with the q key.  Of course, I'm open to the possibility of
> modifying dictionary.el instead of adding this separate package GNU ELPA if
> anyone thinks that's preferable, but I also think it would be nice to let people
> try out Dict and get some feedback beforehand.

I think if we could augment dictionary.el so as to satisfy your needs,
perhaps as some kind of minor mode or user option, that would be
better than having an entirely separate package.

Thanks.



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-11 13:59 ` Eli Zaretskii
@ 2023-05-11 14:14   ` Philip Kaludercic
  2023-05-11 17:56     ` Eshel Yaron
  0 siblings, 1 reply; 42+ messages in thread
From: Philip Kaludercic @ 2023-05-11 14:14 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Eshel Yaron, emacs-devel

Eli Zaretskii <eliz@gnu.org> writes:

>> From: Eshel Yaron <me@eshelyaron.com>
>> Date: Thu, 11 May 2023 16:22:06 +0300
>> 
>> The main motivation behind this package was to resolve some usability issues
>> that I came across with dictionary.el.  Namely, I'm not satisfied with the fact
>> that dictionary.el unconditionally switches to the *Dictionary* buffer when
>> displaying a definition, and I don't appreciate how it tries to remember my
>> previous windows configuration and revert back to it when I close the
>> *Dictionary* buffer with the q key.  Of course, I'm open to the possibility of
>> modifying dictionary.el instead of adding this separate package GNU ELPA if
>> anyone thinks that's preferable, but I also think it would be nice to let people
>> try out Dict and get some feedback beforehand.
>
> I think if we could augment dictionary.el so as to satisfy your needs,
> perhaps as some kind of minor mode or user option, that would be
> better than having an entirely separate package.

I don't think that is possible, Eshel writes on his website:

   Dict’s differentiation comes from its simplicity and
   extensibility–while dictionary.el defines a bespoke major mode and
   interface for browsing word definitions, Dict leverages Emacs’s Help
   mode by default, and let’s you extend and control every aspect of its
   behavior via customization options.

   dict.el is also shorter than dictionary.el–just under 300 lines of
   code!

This is a ERC vs rcirc like situation.

> Thanks.



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-11 13:22 [ELPA] New package: dict Eshel Yaron
  2023-05-11 13:59 ` Eli Zaretskii
@ 2023-05-11 14:18 ` Philip Kaludercic
  2023-05-11 18:00   ` Eshel Yaron
  1 sibling, 1 reply; 42+ messages in thread
From: Philip Kaludercic @ 2023-05-11 14:18 UTC (permalink / raw)
  To: Eshel Yaron; +Cc: emacs-devel

Eshel Yaron <me@eshelyaron.com> writes:

> From 623c4d3b8be00f180e03480633a24ab61326e5cc Mon Sep 17 00:00:00 2001
> From: Eshel Yaron <me@eshelyaron.com>
> Date: Thu, 11 May 2023 14:20:16 +0300
> Subject: [PATCH] * elpa-packages (dict): New package
>
> ---
>  elpa-packages | 2 ++
>  1 file changed, 2 insertions(+)
>
> diff --git a/elpa-packages b/elpa-packages
> index d5603f7803..fab548b336 100644
> --- a/elpa-packages
> +++ b/elpa-packages
> @@ -201,6 +201,8 @@
>    :news "CHANGELOG.org"
>    :readme "README.md")
>   (devdocs		:url "https://github.com/astoff/devdocs.el")
> + (dict		        :url "git://git.eshelyaron.com/dict.git"

Do you have any other access method beside git://?

> +  :doc "README.org")

Should we add a ":readme ignore" to prevent the contents of this file
from also appearing when the user invokes C-h P dict RET ? 

>   (dict-tree		:url "http://www.dr-qubit.org/git/predictive.git"
>    :manual-sync t ;; The upstream doesn't exist any more!
>    )
> -- 
> 2.40.1



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-11 14:14   ` Philip Kaludercic
@ 2023-05-11 17:56     ` Eshel Yaron
  2023-05-11 18:16       ` Eli Zaretskii
  2023-05-11 18:29       ` Philip Kaludercic
  0 siblings, 2 replies; 42+ messages in thread
From: Eshel Yaron @ 2023-05-11 17:56 UTC (permalink / raw)
  To: Philip Kaludercic; +Cc: Eli Zaretskii, emacs-devel

Eli, Philip, thanks for looking into it.

Philip Kaludercic <philipk@posteo.net> writes:

> Eli Zaretskii <eliz@gnu.org> writes:
>
>>> From: Eshel Yaron <me@eshelyaron.com>
>>> Date: Thu, 11 May 2023 16:22:06 +0300
>>> 
>>> The main motivation behind this package was to resolve some usability issues
>>> that I came across with dictionary.el.  Namely, I'm not satisfied with the fact
>>> that dictionary.el unconditionally switches to the *Dictionary* buffer when
>>> displaying a definition, and I don't appreciate how it tries to remember my
>>> previous windows configuration and revert back to it when I close the
>>> *Dictionary* buffer with the q key.  Of course, I'm open to the possibility of
>>> modifying dictionary.el instead of adding this separate package GNU ELPA if
>>> anyone thinks that's preferable, but I also think it would be nice to let people
>>> try out Dict and get some feedback beforehand.
>>
>> I think if we could augment dictionary.el so as to satisfy your needs,
>> perhaps as some kind of minor mode or user option, that would be
>> better than having an entirely separate package.

Alright, I can give augmenting dictionary.el a shot.  The way I see it,
this has the downside that it'll only be available in Emacs 30, and I'm
not sure how elegant that's gonna be, but I guess I can put a patch
together for emacs.git and then reassess.
>
> I don't think that is possible, Eshel writes on his website:
>
>    Dict’s differentiation comes from its simplicity and
>    extensibility–while dictionary.el defines a bespoke major mode and
>    interface for browsing word definitions, Dict leverages Emacs’s Help
>    mode by default, and let’s you extend and control every aspect of its
>    behavior via customization options.
>
>    dict.el is also shorter than dictionary.el–just under 300 lines of
>    code!
>
> This is a ERC vs rcirc like situation.

I'm afraid I haven't used ERC enough to understand this comparison, does
it imply that you think it'll be hard to keep Dict's simplicity intact
upon incorporating it with dictionary.el?


-- 
Best,

Eshel



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-11 14:18 ` Philip Kaludercic
@ 2023-05-11 18:00   ` Eshel Yaron
  2023-05-11 18:31     ` Philip Kaludercic
  2023-05-13 22:30     ` Richard Stallman
  0 siblings, 2 replies; 42+ messages in thread
From: Eshel Yaron @ 2023-05-11 18:00 UTC (permalink / raw)
  To: Philip Kaludercic; +Cc: emacs-devel

Philip Kaludercic <philipk@posteo.net> writes:

> Eshel Yaron <me@eshelyaron.com> writes:
>
>> From 623c4d3b8be00f180e03480633a24ab61326e5cc Mon Sep 17 00:00:00 2001
>> From: Eshel Yaron <me@eshelyaron.com>
>> Date: Thu, 11 May 2023 14:20:16 +0300
>> Subject: [PATCH] * elpa-packages (dict): New package
>>
>> ---
>>  elpa-packages | 2 ++
>>  1 file changed, 2 insertions(+)
>>
>> diff --git a/elpa-packages b/elpa-packages
>> index d5603f7803..fab548b336 100644
>> --- a/elpa-packages
>> +++ b/elpa-packages
>> @@ -201,6 +201,8 @@
>>    :news "CHANGELOG.org"
>>    :readme "README.md")
>>   (devdocs		:url "https://github.com/astoff/devdocs.el")
>> + (dict		        :url "git://git.eshelyaron.com/dict.git"
>
> Do you have any other access method beside git://?

For anonymous access, currently no.  But I can mirror the repo to
Sourcehut from where you can clone it via HTTPS.  Would that be more
convenient?

>> +  :doc "README.org")
>
> Should we add a ":readme ignore" to prevent the contents of this file
> from also appearing when the user invokes C-h P dict RET ? 

Sure, in this case would C-h P show the commentary section of dict.el?


Thanks,
Eshel



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-11 17:56     ` Eshel Yaron
@ 2023-05-11 18:16       ` Eli Zaretskii
  2023-05-11 18:29       ` Philip Kaludercic
  1 sibling, 0 replies; 42+ messages in thread
From: Eli Zaretskii @ 2023-05-11 18:16 UTC (permalink / raw)
  To: Eshel Yaron; +Cc: philipk, emacs-devel

> From: Eshel Yaron <me@eshelyaron.com>
> Cc: Eli Zaretskii <eliz@gnu.org>,  emacs-devel@gnu.org
> Date: Thu, 11 May 2023 20:56:10 +0300
> 
> Alright, I can give augmenting dictionary.el a shot.

Thank you.

> The way I see it, this has the downside that it'll only be available
> in Emacs 30, and I'm not sure how elegant that's gonna be, but I
> guess I can put a patch together for emacs.git and then reassess.

If this turns out to be a significant issue, we could always make
dictionary.el available from ELPA as well.



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-11 17:56     ` Eshel Yaron
  2023-05-11 18:16       ` Eli Zaretskii
@ 2023-05-11 18:29       ` Philip Kaludercic
  2023-05-12 13:17         ` Eshel Yaron
  1 sibling, 1 reply; 42+ messages in thread
From: Philip Kaludercic @ 2023-05-11 18:29 UTC (permalink / raw)
  To: Eshel Yaron; +Cc: Eli Zaretskii, emacs-devel

Eshel Yaron <me@eshelyaron.com> writes:

> Eli, Philip, thanks for looking into it.
>
> Philip Kaludercic <philipk@posteo.net> writes:
>
>> Eli Zaretskii <eliz@gnu.org> writes:
>>
>>>> From: Eshel Yaron <me@eshelyaron.com>
>>>> Date: Thu, 11 May 2023 16:22:06 +0300
>>>> 
>>>> The main motivation behind this package was to resolve some usability issues
>>>> that I came across with dictionary.el.  Namely, I'm not satisfied with the fact
>>>> that dictionary.el unconditionally switches to the *Dictionary* buffer when
>>>> displaying a definition, and I don't appreciate how it tries to remember my
>>>> previous windows configuration and revert back to it when I close the
>>>> *Dictionary* buffer with the q key.  Of course, I'm open to the possibility of
>>>> modifying dictionary.el instead of adding this separate package GNU ELPA if
>>>> anyone thinks that's preferable, but I also think it would be nice to let people
>>>> try out Dict and get some feedback beforehand.
>>>
>>> I think if we could augment dictionary.el so as to satisfy your needs,
>>> perhaps as some kind of minor mode or user option, that would be
>>> better than having an entirely separate package.
>
> Alright, I can give augmenting dictionary.el a shot.  The way I see it,
> this has the downside that it'll only be available in Emacs 30, and I'm
> not sure how elegant that's gonna be, but I guess I can put a patch
> together for emacs.git and then reassess.
>
>> I don't think that is possible, Eshel writes on his website:
>>
>>    Dict’s differentiation comes from its simplicity and
>>    extensibility–while dictionary.el defines a bespoke major mode and
>>    interface for browsing word definitions, Dict leverages Emacs’s Help
>>    mode by default, and let’s you extend and control every aspect of its
>>    behavior via customization options.
>>
>>    dict.el is also shorter than dictionary.el–just under 300 lines of
>>    code!
>>
>> This is a ERC vs rcirc like situation.
>
> I'm afraid I haven't used ERC enough to understand this comparison, 

rcirc and ERC are just two different IRC clients, respectively
minimalist and maximalist.

>                                                                     does
> it imply that you think it'll be hard to keep Dict's simplicity intact
> upon incorporating it with dictionary.el?

Right, you'll either have to remove stuff from dictionary.el that people
have started to depend on, or ignore that fact.



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-11 18:00   ` Eshel Yaron
@ 2023-05-11 18:31     ` Philip Kaludercic
  2023-05-12 13:32       ` Eshel Yaron
  2023-05-13 22:30     ` Richard Stallman
  1 sibling, 1 reply; 42+ messages in thread
From: Philip Kaludercic @ 2023-05-11 18:31 UTC (permalink / raw)
  To: Eshel Yaron; +Cc: emacs-devel

Eshel Yaron <me@eshelyaron.com> writes:

> Philip Kaludercic <philipk@posteo.net> writes:
>
>> Eshel Yaron <me@eshelyaron.com> writes:
>>
>>> From 623c4d3b8be00f180e03480633a24ab61326e5cc Mon Sep 17 00:00:00 2001
>>> From: Eshel Yaron <me@eshelyaron.com>
>>> Date: Thu, 11 May 2023 14:20:16 +0300
>>> Subject: [PATCH] * elpa-packages (dict): New package
>>>
>>> ---
>>>  elpa-packages | 2 ++
>>>  1 file changed, 2 insertions(+)
>>>
>>> diff --git a/elpa-packages b/elpa-packages
>>> index d5603f7803..fab548b336 100644
>>> --- a/elpa-packages
>>> +++ b/elpa-packages
>>> @@ -201,6 +201,8 @@
>>>    :news "CHANGELOG.org"
>>>    :readme "README.md")
>>>   (devdocs		:url "https://github.com/astoff/devdocs.el")
>>> + (dict		        :url "git://git.eshelyaron.com/dict.git"
>>
>> Do you have any other access method beside git://?
>
> For anonymous access, currently no.  But I can mirror the repo to
> Sourcehut from where you can clone it via HTTPS.  Would that be more
> convenient?

That would be good, my understanding is that git:// is not encrypted so
we should avoid using it if possible.

>>> +  :doc "README.org")
>>
>> Should we add a ":readme ignore" to prevent the contents of this file
>> from also appearing when the user invokes C-h P dict RET ? 
>
> Sure, in this case would C-h P show the commentary section of dict.el?

Right.  Feel free to extend that with pointers, I just think we should
avoid overwhelming users with the entire documentation if they just want
to get the basic gist of a package.

> Thanks,
> Eshel



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-11 18:29       ` Philip Kaludercic
@ 2023-05-12 13:17         ` Eshel Yaron
  2023-05-12 13:44           ` Eli Zaretskii
  0 siblings, 1 reply; 42+ messages in thread
From: Eshel Yaron @ 2023-05-12 13:17 UTC (permalink / raw)
  To: Philip Kaludercic; +Cc: Eli Zaretskii, emacs-devel

Philip Kaludercic <philipk@posteo.net> writes:

> Eshel Yaron <me@eshelyaron.com> writes:
>
>> Alright, I can give augmenting dictionary.el a shot.
>>
>> [...]
>>
>> does it imply that you think it'll be hard to keep Dict's simplicity
>> intact upon incorporating it with dictionary.el?
>
> Right, you'll either have to remove stuff from dictionary.el that people
> have started to depend on, or ignore that fact.

After studying dictionary.el more carefully, I don't currently see a
good way of augmenting it to facilitate the same behavior that Dict
provides.

Basically, Dict has just one command, `dict-describe-word`, and the
question is how this command can be implemented or imitated in terms of
dictionary.el.

`dict-describe-word` is not complex, its behavior is described in
https://eshelyaron.com/dict.html#word-definitions, but let's just take a
look at its definition:

--8<---------------cut here---------------start------------->8---
(defun dict-describe-word (word)
  "Display the definition of WORD.
..."
  (interactive (list (dict-read-word)))
  (let ((definition (dict-define-word word)))
    (if definition
        (funcall dict-display-definition-function word definition)
      (user-error "No definition found for \"%s\"" word))))
--8<---------------cut here---------------end--------------->8---

It only uses two Dict-specific functions: `dict-read-word` and
`dict-define-word`.  `dict-define-word` takes a word and returns its
definition, as a string.  `dict-read-word` reads a word using
`completing-read`, with completion based on dictionary matches.  It
relies on another function, `dict-match-word`, to retrieve the list of
completion candidates from the dictionary server.

In order to implement `dict-describe-word` as part of dictionary.el, I'd
need to replace `dict-match-word` and `dict-describe-word` with
corresponding functions from dictionary.el.  Unfortunately, the parts of
dictionary.el that deal with obtaining information and the parts that
deal with displaying it are not easily separable.  Indeed, their is no
API for obtaining word definitions or matches, and the functions that
perform these actions also do unrelated UI stuff.

For that reason I don't see a good way to reuse code from dictionary.el
to port `dict-describe-word`.

Another option would be to refactor dictionary.el to make it more
modular and to provide a cleaner API.  That's possible, but refactoring
would most likely mean risking breaking stuff, and I couldn't find any
tests that'd help circumvent that risk.

All in all, I currently think it's best to keep these two separate after all.
The only concrete downside that I see is that Dict define a couple of user
options that are very similar to those defined in dictionary.el, and users of
both packages may find it annoying to customize both.  Perhaps I can have Dict
pick up these user options from their corresponding dictionary.el variables if
they're already set.

Any thoughts/ideas?



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-11 18:31     ` Philip Kaludercic
@ 2023-05-12 13:32       ` Eshel Yaron
  2023-05-16 19:38         ` Philip Kaludercic
  0 siblings, 1 reply; 42+ messages in thread
From: Eshel Yaron @ 2023-05-12 13:32 UTC (permalink / raw)
  To: Philip Kaludercic; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 1096 bytes --]

Philip Kaludercic <philipk@posteo.net> writes:

> Eshel Yaron <me@eshelyaron.com> writes:
>
>> Philip Kaludercic <philipk@posteo.net> writes:
>>
>>> Eshel Yaron <me@eshelyaron.com> writes:
>>>
>>>> + (dict		        :url "git://git.eshelyaron.com/dict.git"
>>>
>>> Do you have any other access method beside git://?
>>
>> For anonymous access, currently no.  But I can mirror the repo to
>> Sourcehut from where you can clone it via HTTPS.  Would that be more
>> convenient?
>
> That would be good, my understanding is that git:// is not encrypted so
> we should avoid using it if possible.

>>>> +  :doc "README.org")
>>>
>>> Should we add a ":readme ignore" to prevent the contents of this file
>>> from also appearing when the user invokes C-h P dict RET ? 
>>
>> Sure, in this case would C-h P show the commentary section of dict.el?
>
> Right.  Feel free to extend that with pointers, I just think we should
> avoid overwhelming users with the entire documentation if they just want
> to get the basic gist of a package.

Alright, I'm attaching a new patch that addresses both these points.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: v2-0001-elpa-packages-dict-New-package.patch --]
[-- Type: text/x-patch, Size: 743 bytes --]

From 2466225fd527e3748c266307d6858407011105f5 Mon Sep 17 00:00:00 2001
From: Eshel Yaron <me@eshelyaron.com>
Date: Thu, 11 May 2023 14:20:16 +0300
Subject: [PATCH v2] * elpa-packages (dict): New package

---
 elpa-packages | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/elpa-packages b/elpa-packages
index d5603f7803..637d71685e 100644
--- a/elpa-packages
+++ b/elpa-packages
@@ -201,6 +201,9 @@
   :news "CHANGELOG.org"
   :readme "README.md")
  (devdocs		:url "https://github.com/astoff/devdocs.el")
+ (dict		        :url "https://git.sr.ht/~eshel/dict"
+  :doc "README.org"
+  :readme ignore)
  (dict-tree		:url "http://www.dr-qubit.org/git/predictive.git"
   :manual-sync t ;; The upstream doesn't exist any more!
   )
-- 
2.40.1


[-- Attachment #3: Type: text/plain, Size: 18 bytes --]


-- 
Best,

Eshel

^ permalink raw reply related	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-12 13:17         ` Eshel Yaron
@ 2023-05-12 13:44           ` Eli Zaretskii
  2023-05-14  6:41             ` Eshel Yaron
  0 siblings, 1 reply; 42+ messages in thread
From: Eli Zaretskii @ 2023-05-12 13:44 UTC (permalink / raw)
  To: Eshel Yaron; +Cc: philipk, emacs-devel

> From: Eshel Yaron <me@eshelyaron.com>
> Cc: Eli Zaretskii <eliz@gnu.org>,  emacs-devel@gnu.org
> Date: Fri, 12 May 2023 16:17:53 +0300
> 
> Any thoughts/ideas?

How about adding to dictionary.el a customizable function that
dictionary-search would call instead of its default operation?



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-11 18:00   ` Eshel Yaron
  2023-05-11 18:31     ` Philip Kaludercic
@ 2023-05-13 22:30     ` Richard Stallman
  2023-05-14  6:48       ` Eshel Yaron
  1 sibling, 1 reply; 42+ messages in thread
From: Richard Stallman @ 2023-05-13 22:30 UTC (permalink / raw)
  To: Eshel Yaron; +Cc: philipk, emacs-devel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > > Do you have any other access method beside git://?

  > For anonymous access, currently no.  But I can mirror the repo to
  > Sourcehut from where you can clone it via HTTPS.  Would that be more
  > convenient?

How about leaving github entirely for sourcehut?
sourcehut respects users' freedom more than github.

-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-12 13:44           ` Eli Zaretskii
@ 2023-05-14  6:41             ` Eshel Yaron
  2023-05-14  9:14               ` Eli Zaretskii
  2023-05-14 16:06               ` Stephen Leake
  0 siblings, 2 replies; 42+ messages in thread
From: Eshel Yaron @ 2023-05-14  6:41 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: philipk, emacs-devel

Eli Zaretskii <eliz@gnu.org> writes:

>> From: Eshel Yaron <me@eshelyaron.com>
>> Cc: Eli Zaretskii <eliz@gnu.org>,  emacs-devel@gnu.org
>> Date: Fri, 12 May 2023 16:17:53 +0300
>>
>> Any thoughts/ideas?
>
> How about adding to dictionary.el a customizable function that
> dictionary-search would call instead of its default operation?

Thanks, this would be a good way to expose the different behavior that I
want to add.  However, my difficulty lies elsewhere.  The issue I
brought up in my previous message is with implementing this behavior
without introducing unnecessary code duplication to dictionary.el.

In short, we need two things: a way to obtain a word's definition and a
way to obtain dictionary matches given some input (for completion).
dictionary.el does these things already, but in way that's too coupled
with its user interface to admit reuse for my purposes.  So the question
is whether to add the needed stuff from Dict to dictionary.el and accept
some code duplication, or try to refactor the parts of dictionary.el
that communicate with the dictionary server to provide a cleaner API.


-- 
Best,

Eshel



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-13 22:30     ` Richard Stallman
@ 2023-05-14  6:48       ` Eshel Yaron
  0 siblings, 0 replies; 42+ messages in thread
From: Eshel Yaron @ 2023-05-14  6:48 UTC (permalink / raw)
  To: Richard Stallman; +Cc: philipk, emacs-devel

Richard Stallman <rms@gnu.org> writes:

> [[[ To any NSA and FBI agents reading my email: please consider    ]]]
> [[[ whether defending the US Constitution against all enemies,     ]]]
> [[[ foreign or domestic, requires you to follow Snowden's example. ]]]
>
>   > > Do you have any other access method beside git://?
>
>   > For anonymous access, currently no.  But I can mirror the repo to
>   > Sourcehut from where you can clone it via HTTPS.  Would that be more
>   > convenient?
>
> How about leaving github entirely for sourcehut?
> sourcehut respects users' freedom more than github.

I agree, but GitHub was never on the table here.  I originally provided
a URL to my own Git server (no relation to GitHub).



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-14  6:41             ` Eshel Yaron
@ 2023-05-14  9:14               ` Eli Zaretskii
  2023-05-15 18:50                 ` Eshel Yaron
  2023-05-14 16:06               ` Stephen Leake
  1 sibling, 1 reply; 42+ messages in thread
From: Eli Zaretskii @ 2023-05-14  9:14 UTC (permalink / raw)
  To: Eshel Yaron; +Cc: philipk, emacs-devel

> From: Eshel Yaron <me@eshelyaron.com>
> Cc: philipk@posteo.net,  emacs-devel@gnu.org
> Date: Sun, 14 May 2023 09:41:52 +0300
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> > How about adding to dictionary.el a customizable function that
> > dictionary-search would call instead of its default operation?
> 
> Thanks, this would be a good way to expose the different behavior that I
> want to add.  However, my difficulty lies elsewhere.  The issue I
> brought up in my previous message is with implementing this behavior
> without introducing unnecessary code duplication to dictionary.el.
> 
> In short, we need two things: a way to obtain a word's definition and a
> way to obtain dictionary matches given some input (for completion).
> dictionary.el does these things already, but in way that's too coupled
> with its user interface to admit reuse for my purposes.  So the question
> is whether to add the needed stuff from Dict to dictionary.el and accept
> some code duplication, or try to refactor the parts of dictionary.el
> that communicate with the dictionary server to provide a cleaner API.

I'd say try the latter if it's reasonably easy; otherwise try the
former.



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-14  6:41             ` Eshel Yaron
  2023-05-14  9:14               ` Eli Zaretskii
@ 2023-05-14 16:06               ` Stephen Leake
  2023-05-15 18:58                 ` Eshel Yaron
  1 sibling, 1 reply; 42+ messages in thread
From: Stephen Leake @ 2023-05-14 16:06 UTC (permalink / raw)
  To: Eshel Yaron; +Cc: Eli Zaretskii, philipk, emacs-devel

Eshel Yaron <me@eshelyaron.com> writes:

> Eli Zaretskii <eliz@gnu.org> writes:
>
>>> From: Eshel Yaron <me@eshelyaron.com>
>>> Cc: Eli Zaretskii <eliz@gnu.org>,  emacs-devel@gnu.org
>>> Date: Fri, 12 May 2023 16:17:53 +0300
>>>
>>> Any thoughts/ideas?
>>
>> How about adding to dictionary.el a customizable function that
>> dictionary-search would call instead of its default operation?
>
> Thanks, this would be a good way to expose the different behavior that I
> want to add.  However, my difficulty lies elsewhere.  The issue I
> brought up in my previous message is with implementing this behavior
> without introducing unnecessary code duplication to dictionary.el.
>
> In short, we need two things: a way to obtain a word's definition and a
> way to obtain dictionary matches given some input (for completion).
> dictionary.el does these things already, but in way that's too coupled
> with its user interface to admit reuse for my purposes.  So the question
> is whether to add the needed stuff from Dict to dictionary.el and accept
> some code duplication, or try to refactor the parts of dictionary.el
> that communicate with the dictionary server to provide a cleaner API.

Maybe you can rewrite the higher-level code in dictionary.el to depend
on the lower-level code in dict.el (while combining them into one file).
-- 
-- Stephe



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-14  9:14               ` Eli Zaretskii
@ 2023-05-15 18:50                 ` Eshel Yaron
  2023-05-18  7:57                   ` Eshel Yaron
                                     ` (2 more replies)
  0 siblings, 3 replies; 42+ messages in thread
From: Eshel Yaron @ 2023-05-15 18:50 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: philipk, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 1889 bytes --]

Eli Zaretskii <eliz@gnu.org> writes:

>> From: Eshel Yaron <me@eshelyaron.com>
>> Cc: philipk@posteo.net,  emacs-devel@gnu.org
>> Date: Sun, 14 May 2023 09:41:52 +0300
>>
>> Eli Zaretskii <eliz@gnu.org> writes:
>>
>> > How about adding to dictionary.el a customizable function that
>> > dictionary-search would call instead of its default operation?
>>
>> Thanks, this would be a good way to expose the different behavior that I
>> want to add.  However, my difficulty lies elsewhere.  The issue I
>> brought up in my previous message is with implementing this behavior
>> without introducing unnecessary code duplication to dictionary.el.
>>
>> In short, we need two things: a way to obtain a word's definition and a
>> way to obtain dictionary matches given some input (for completion).
>> dictionary.el does these things already, but in way that's too coupled
>> with its user interface to admit reuse for my purposes.  So the question
>> is whether to add the needed stuff from Dict to dictionary.el and accept
>> some code duplication, or try to refactor the parts of dictionary.el
>> that communicate with the dictionary server to provide a cleaner API.
>
> I'd say try the latter if it's reasonably easy; otherwise try the
> former.

Alright, I'm attaching a patch that extends dictionary.el with new user
options that modify the behavior of `dictionary-search`.  With this
patch, `dictionary-search` behaves like my `dict-describe-word` after
applying the following customizations:

--8<---------------cut here---------------start------------->8---
(setq dictionary-read-dictionary-function
      #'dictionary-completing-read-dictionary)
(setq dictionary-read-word-function
      #'dictionary-completing-read-word)
(setq dictionary-display-definition-function
      #'dictionary-display-definition-in-help-buffer)
--8<---------------cut here---------------end--------------->8---


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Add-customization-options-for-dictionary-search.patch --]
[-- Type: text/x-patch, Size: 11408 bytes --]

From 1b5eecf46a40888c8c9ba900b17c1701fb3bcd70 Mon Sep 17 00:00:00 2001
From: Eshel Yaron <me@eshelyaron.com>
Date: Mon, 15 May 2023 21:04:21 +0300
Subject: [PATCH] Add customization options for dictionary-search

Allow users to customize 'dictionary-search' via several new
customization options.

* lisp/net/dictionary.el (dictionary-define-word)
(dictionary-match-word)
(dictionary-completing-read-word)
(dictionary-dictionaries)
(dictionary-completing-read-dictionary)
(dictionary-display-definition-in-help-buffer): New functions.
(dictionary-read-word-prompt)
(dictionary-display-definition-function)
(dictionary-read-word-function)
(dictionary-read-dictionary-function): New user options.
(dictionary-search): Use them.
* etc/NEWS: Announce.
---
 etc/NEWS               |  36 +++++++++
 lisp/net/dictionary.el | 166 +++++++++++++++++++++++++++++++++++++----
 2 files changed, 187 insertions(+), 15 deletions(-)

diff --git a/etc/NEWS b/etc/NEWS
index b4846eb11b0..8a9afa53cdc 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -322,6 +322,42 @@ instead of:
         and another_expression):
         do_something()
 
+** Dictionary
+
+---
+*** New user option 'dictionary-read-word-prompt'.
+This allows the user to customize the prompt that is used by
+'dictionary-search' when asking for a word to search in the
+dictionary.
+
+---
+*** New user option 'dictionary-display-definition-function'.
+This allows the user to customize the way in which 'dictionary-search'
+displays word definitions.  If non-nil, this user option should be set
+to a function that displays a word definition obtained from a
+dictionary server.  The new function
+'dictionary-display-definition-in-help-buffer' can be used to display
+the definition in a *Help* buffer, instead of the default *Dictionary*
+buffer.
+
+---
+*** New user option 'dictionary-read-word-function'.
+This allows the user to customize the way in which 'dictionary-search'
+prompts for a word to search in the dictionary.  If non-nil, this user
+option should be set to a function that lets the user select a word
+and returns it as a string.  The new function
+'dictionary-completing-read-word' can be used to prompt with
+completion based on dictionary matches.
+
+---
+*** New user option 'dictionary-read-dictionary-function'.
+This allows the user to customize the way in which 'dictionary-search'
+prompts for a dictionary to search in.  If non-nil, this user option
+should be set to a function that lets the user select a dictionary and
+returns its name as a string.  The new function
+'dictionary-completing-read-dictionary' can be used to prompt with
+completion based on dictionaries that the server supports.
+
 \f
 * New Modes and Packages in Emacs 30.1
 
diff --git a/lisp/net/dictionary.el b/lisp/net/dictionary.el
index ba65225692a..adf1f409f26 100644
--- a/lisp/net/dictionary.el
+++ b/lisp/net/dictionary.el
@@ -38,6 +38,7 @@
 (require 'custom)
 (require 'dictionary-connection)
 (require 'button)
+(require 'help-mode)
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Stuff for customizing.
@@ -247,6 +248,39 @@ dictionary-coding-systems-for-dictionaries
                                )))
   :version "28.1")
 
+(defcustom dictionary-read-word-prompt "Search word"
+  "Prompt string to use when prompting for a word."
+  :type 'string
+  :version "30.1")
+
+(defcustom dictionary-display-definition-function nil
+  "Function to use for displaying dictionary definitions.
+It is called with three string arguments: the word being defined,
+the dictionary name, and the full definition."
+  :type '(choice (const :tag "Dictionary buffer" nil)
+                 (const :tag "Help buffer"
+                        dictionary-display-definition-in-help-buffer)
+                 (function :tag "Custom function"))
+  :version "30.1")
+
+(defcustom dictionary-read-word-function nil
+  "Function to use for prompting for a word.
+It is called with no arguments and must return a string."
+  :type '(choice (const :tag "Default" nil)
+                 (const :tag "Dictionary-based completion"
+                        dictionary-completing-read-word)
+                 (function :tag "Custom function"))
+  :version "30.1")
+
+(defcustom dictionary-read-dictionary-function nil
+  "Function to use for prompting for a dictionary.
+It is called with no arguments and must return a string."
+  :type '(choice (const :tag "Default" nil)
+                 (const :tag "Choose among server-provided dictionaries"
+                        dictionary-completing-read-dictionary)
+                 (function :tag "Custom function"))
+  :version "30.1")
+
 (defface dictionary-word-definition-face
 '((((supports (:family "DejaVu Serif")))
    (:family "DejaVu Serif"))
@@ -366,6 +400,8 @@ dictionary-word-history
   '()
   "History list of searched word.")
 
+(defvar dictionary--last-match nil)
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Basic function providing startup actions
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -1149,23 +1185,33 @@ dictionary-search
 It presents the selection or word at point as default input and
 allows editing it."
   (interactive
-   (list (let ((default (dictionary-search-default)))
-           (read-string (format-prompt "Search word" default)
-                        nil 'dictionary-word-history default))
-	 (if current-prefix-arg
-	     (read-string (if dictionary-default-dictionary
-			      (format "Dictionary (%s): " dictionary-default-dictionary)
-			    "Dictionary: ")
-			  nil nil dictionary-default-dictionary)
-	   dictionary-default-dictionary)))
-
-  ;; if called by pressing the button
-  (unless word
-    (setq word (read-string "Search word: " nil 'dictionary-word-history)))
-  ;; just in case non-interactively called
+   (let ((dict
+          (if current-prefix-arg
+	      (if dictionary-read-dictionary-function
+                  (funcall dictionary-read-dictionary-function)
+                (read-string (if dictionary-default-dictionary
+			         (format "Dictionary (%s): "
+                                         dictionary-default-dictionary)
+			       "Dictionary: ")
+			     nil nil dictionary-default-dictionary))
+	    dictionary-default-dictionary)))
+     (list (if dictionary-read-word-function
+               (funcall dictionary-read-word-function)
+             (let ((default (dictionary-search-default)))
+               (read-string (format-prompt dictionary-read-word-prompt default)
+                            nil 'dictionary-word-history default)))
+           dict)))
   (unless dictionary
     (setq dictionary dictionary-default-dictionary))
-  (dictionary-new-search (cons word dictionary)))
+  (if dictionary-display-definition-function
+      (if-let ((definition (dictionary-define-word word dictionary)))
+          (funcall dictionary-display-definition-function word dictionary definition)
+        (user-error "No definition found for \"%s\"" word))
+    ;; if called by pressing the button
+    (unless word
+      (setq word (read-string "Search word: " nil 'dictionary-word-history)))
+    ;; just in case non-interactively called
+    (dictionary-new-search (cons word dictionary))))
 
 ;;;###autoload
 (defun dictionary-lookup-definition ()
@@ -1386,5 +1432,95 @@ dictionary-context-menu
       'dictionary-separator))
   menu)
 
+(defun dictionary-define-word (word dictionary)
+  "Return the definition of WORD in DICTIONARY, or nil if not found."
+  (dictionary-send-command
+   (format "define %s \"%s\"" dictionary word))
+  (when (and (= (read (dictionary-read-reply)) 150)
+             (= (read (dictionary-read-reply)) 151))
+    (dictionary-read-answer)))
+
+(defun dictionary-match-word (word)
+  "Return dictionary matches for WORD as a list of strings."
+  (unless (string-empty-p word)
+    (if (string= (car dictionary--last-match) word)
+        (cdr dictionary--last-match)
+      (dictionary-send-command
+       (format "match %s %s \"%s\""
+               dictionary-default-dictionary
+               dictionary-default-strategy
+               word))
+      (when (and (= (read (dictionary-read-reply)) 152))
+        (with-temp-buffer
+          (insert (dictionary-read-answer))
+          (goto-char (point-min))
+          (let ((result nil))
+            (while (not (eobp))
+              (search-forward " " nil t)
+              (push (read (current-buffer)) result)
+              (search-forward "\n" nil t))
+            (setq result (reverse result))
+            (setq dictionary--last-match (cons word result))
+            result))))))
+
+(defun dictionary-completing-read-word ()
+  "Prompt for a word with completion based on dictionary matches."
+  (let* ((completion-ignore-case t)
+         (word-at-point (thing-at-point 'word t))
+         (default (dictionary-match-word word-at-point)))
+    (completing-read (format-prompt dictionary-read-word-prompt default)
+                     (completion-table-dynamic #'dictionary-match-word)
+                     nil t nil 'dictionary-word-history default t)))
+
+(defun dictionary-dictionaries ()
+  "Return the list of dictionaries the server supports."
+  (dictionary-send-command "show db")
+  (when (and (= (read (dictionary-read-reply)) 110))
+    (with-temp-buffer
+      (insert (dictionary-read-answer))
+      (goto-char (point-min))
+      (let ((result '(("!" . "First matching dictionary")
+                      ("*" . "All dictionaries"))))
+        (while (not (eobp))
+          (push (cons (buffer-substring
+                       (search-forward "\n" nil t)
+                       (1- (search-forward " " nil t)))
+                      (read (current-buffer)))
+                result))
+        (reverse result)))))
+
+(defun dictionary-completing-read-dictionary ()
+  "Prompt for a dictionary the server supports."
+  (let* ((dicts (dictionary-dictionaries))
+         (len (apply #'max (mapcar #'length (mapcar #'car dicts))))
+         (completion-extra-properties
+          (list :annotation-function
+                (lambda (key)
+                  (concat (make-string (1+ (- len (length key))) ?\s)
+                          (alist-get key dicts nil nil #'string=))))))
+    (completing-read (format-prompt "Select dictionary"
+                                    dictionary-default-dictionary)
+                     dicts nil t nil nil dictionary-default-dictionary)))
+
+(define-button-type 'help-word
+  :supertype 'help-xref
+  'help-function 'dictionary-search
+  'help-echo (purecopy "mouse-2, RET: describe this word"))
+
+(defun dictionary-display-definition-in-help-buffer (word dictionary definition)
+  "Display DEFINITION, the definition of WORD in DICTIONARY."
+  (let ((help-buffer-under-preparation t))
+    (help-setup-xref (list #'dictionary-search word dictionary)
+                     (called-interactively-p 'interactive))
+    (with-help-window (help-buffer)
+      (with-current-buffer (help-buffer)
+        (insert definition)
+        (goto-char (point-min))
+        (while (re-search-forward (rx "{"
+                                      (group-n 1 (* (not (any ?}))))
+                                      "}")
+                                  nil t)
+          (help-xref-button 1 'help-word (match-string 1)))))))
+
 (provide 'dictionary)
 ;;; dictionary.el ends here
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-14 16:06               ` Stephen Leake
@ 2023-05-15 18:58                 ` Eshel Yaron
  0 siblings, 0 replies; 42+ messages in thread
From: Eshel Yaron @ 2023-05-15 18:58 UTC (permalink / raw)
  To: Stephen Leake; +Cc: Eli Zaretskii, philipk, emacs-devel

Stephen Leake <stephen_leake@stephe-leake.org> writes:

> Eshel Yaron <me@eshelyaron.com> writes:
>
>> Eli Zaretskii <eliz@gnu.org> writes:
>>
>>>> From: Eshel Yaron <me@eshelyaron.com>
>>>> Cc: Eli Zaretskii <eliz@gnu.org>,  emacs-devel@gnu.org
>>>> Date: Fri, 12 May 2023 16:17:53 +0300
>>>>
>>>> Any thoughts/ideas?
>>>
>>> How about adding to dictionary.el a customizable function that
>>> dictionary-search would call instead of its default operation?
>>
>> Thanks, this would be a good way to expose the different behavior that I
>> want to add.  However, my difficulty lies elsewhere.  The issue I
>> brought up in my previous message is with implementing this behavior
>> without introducing unnecessary code duplication to dictionary.el.
>>
>> In short, we need two things: a way to obtain a word's definition and a
>> way to obtain dictionary matches given some input (for completion).
>> dictionary.el does these things already, but in way that's too coupled
>> with its user interface to admit reuse for my purposes.  So the question
>> is whether to add the needed stuff from Dict to dictionary.el and accept
>> some code duplication, or try to refactor the parts of dictionary.el
>> that communicate with the dictionary server to provide a cleaner API.
>
> Maybe you can rewrite the higher-level code in dictionary.el to depend
> on the lower-level code in dict.el (while combining them into one file).

That'd definitely make it easier to integrate new functionality, but I
think it would be quite hard to do without risking breaking existing
dictionary.el features.  For now I avoided making extensive changes.

--
Best,

Eshel



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-12 13:32       ` Eshel Yaron
@ 2023-05-16 19:38         ` Philip Kaludercic
  2023-05-17  2:25           ` Eli Zaretskii
  0 siblings, 1 reply; 42+ messages in thread
From: Philip Kaludercic @ 2023-05-16 19:38 UTC (permalink / raw)
  To: Eshel Yaron; +Cc: emacs-devel

Eshel Yaron <me@eshelyaron.com> writes:

> Philip Kaludercic <philipk@posteo.net> writes:
>
>> Eshel Yaron <me@eshelyaron.com> writes:
>>
>>> Philip Kaludercic <philipk@posteo.net> writes:
>>>
>>>> Eshel Yaron <me@eshelyaron.com> writes:
>>>>
>>>>> + (dict		        :url "git://git.eshelyaron.com/dict.git"
>>>>
>>>> Do you have any other access method beside git://?
>>>
>>> For anonymous access, currently no.  But I can mirror the repo to
>>> Sourcehut from where you can clone it via HTTPS.  Would that be more
>>> convenient?
>>
>> That would be good, my understanding is that git:// is not encrypted so
>> we should avoid using it if possible.
>
>>>>> +  :doc "README.org")
>>>>
>>>> Should we add a ":readme ignore" to prevent the contents of this file
>>>> from also appearing when the user invokes C-h P dict RET ? 
>>>
>>> Sure, in this case would C-h P show the commentary section of dict.el?
>>
>> Right.  Feel free to extend that with pointers, I just think we should
>> avoid overwhelming users with the entire documentation if they just want
>> to get the basic gist of a package.
>
> Alright, I'm attaching a new patch that addresses both these points.
>
> From 2466225fd527e3748c266307d6858407011105f5 Mon Sep 17 00:00:00 2001
> From: Eshel Yaron <me@eshelyaron.com>
> Date: Thu, 11 May 2023 14:20:16 +0300
> Subject: [PATCH v2] * elpa-packages (dict): New package
>
> ---
>  elpa-packages | 3 +++
>  1 file changed, 3 insertions(+)
>
> diff --git a/elpa-packages b/elpa-packages
> index d5603f7803..637d71685e 100644
> --- a/elpa-packages
> +++ b/elpa-packages
> @@ -201,6 +201,9 @@
>    :news "CHANGELOG.org"
>    :readme "README.md")
>   (devdocs		:url "https://github.com/astoff/devdocs.el")
> + (dict		        :url "https://git.sr.ht/~eshel/dict"
> +  :doc "README.org"
> +  :readme ignore)
>   (dict-tree		:url "http://www.dr-qubit.org/git/predictive.git"
>    :manual-sync t ;; The upstream doesn't exist any more!
>    )
> -- 
> 2.40.1

So what is the resolution here.  Are we to add this as an additional
package to GNU ELPA, or is the intention to merge dictionary and dict?



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-16 19:38         ` Philip Kaludercic
@ 2023-05-17  2:25           ` Eli Zaretskii
  0 siblings, 0 replies; 42+ messages in thread
From: Eli Zaretskii @ 2023-05-17  2:25 UTC (permalink / raw)
  To: Philip Kaludercic; +Cc: me, emacs-devel

> From: Philip Kaludercic <philipk@posteo.net>
> Cc: emacs-devel@gnu.org
> Date: Tue, 16 May 2023 19:38:59 +0000
> 
> So what is the resolution here.  Are we to add this as an additional
> package to GNU ELPA, or is the intention to merge dictionary and dict?

Let's wait until after the review of what Eshel proposed as
dictionary.el extensions.



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-15 18:50                 ` Eshel Yaron
@ 2023-05-18  7:57                   ` Eshel Yaron
  2023-05-18  8:32                     ` Eli Zaretskii
  2023-05-18 10:59                   ` Eli Zaretskii
  2023-05-18 12:59                   ` Philip Kaludercic
  2 siblings, 1 reply; 42+ messages in thread
From: Eshel Yaron @ 2023-05-18  7:57 UTC (permalink / raw)
  To: emacs-devel; +Cc: philipk, Eli Zaretskii

Hi all,

> Alright, I'm attaching a patch that extends dictionary.el with new user
> options that modify the behavior of `dictionary-search`.  With this
> patch, `dictionary-search` behaves like my `dict-describe-word` after
> applying the following customizations:
>
> (setq dictionary-read-dictionary-function
>       #'dictionary-completing-read-dictionary)
> (setq dictionary-read-word-function
>       #'dictionary-completing-read-word)
> (setq dictionary-display-definition-function
>       #'dictionary-display-definition-in-help-buffer)

Any comments on this patch?

-- 
Thanks,

Eshel



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-18  7:57                   ` Eshel Yaron
@ 2023-05-18  8:32                     ` Eli Zaretskii
  0 siblings, 0 replies; 42+ messages in thread
From: Eli Zaretskii @ 2023-05-18  8:32 UTC (permalink / raw)
  To: Eshel Yaron; +Cc: emacs-devel, philipk

> From: Eshel Yaron <me@eshelyaron.com>
> Cc: philipk@posteo.net,  Eli Zaretskii <eliz@gnu.org>
> Date: Thu, 18 May 2023 10:57:00 +0300
> 
> Hi all,
> 
> > Alright, I'm attaching a patch that extends dictionary.el with new user
> > options that modify the behavior of `dictionary-search`.  With this
> > patch, `dictionary-search` behaves like my `dict-describe-word` after
> > applying the following customizations:
> >
> > (setq dictionary-read-dictionary-function
> >       #'dictionary-completing-read-dictionary)
> > (setq dictionary-read-word-function
> >       #'dictionary-completing-read-word)
> > (setq dictionary-display-definition-function
> >       #'dictionary-display-definition-in-help-buffer)
> 
> Any comments on this patch?

I didn't yet have time to review it, sorry.  Will do soon.



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-15 18:50                 ` Eshel Yaron
  2023-05-18  7:57                   ` Eshel Yaron
@ 2023-05-18 10:59                   ` Eli Zaretskii
  2023-05-18 12:21                     ` Eshel Yaron
  2023-05-18 12:59                   ` Philip Kaludercic
  2 siblings, 1 reply; 42+ messages in thread
From: Eli Zaretskii @ 2023-05-18 10:59 UTC (permalink / raw)
  To: Eshel Yaron; +Cc: philipk, emacs-devel

> From: Eshel Yaron <me@eshelyaron.com>
> Cc: philipk@posteo.net,  emacs-devel@gnu.org
> Date: Mon, 15 May 2023 21:50:57 +0300
> 
> >> In short, we need two things: a way to obtain a word's definition and a
> >> way to obtain dictionary matches given some input (for completion).
> >> dictionary.el does these things already, but in way that's too coupled
> >> with its user interface to admit reuse for my purposes.  So the question
> >> is whether to add the needed stuff from Dict to dictionary.el and accept
> >> some code duplication, or try to refactor the parts of dictionary.el
> >> that communicate with the dictionary server to provide a cleaner API.
> >
> > I'd say try the latter if it's reasonably easy; otherwise try the
> > former.
> 
> Alright, I'm attaching a patch that extends dictionary.el with new user
> options that modify the behavior of `dictionary-search`.

Looks reasonable, thanks.

> With this patch, `dictionary-search` behaves like my
> `dict-describe-word` after applying the following customizations:
> 
> --8<---------------cut here---------------start------------->8---
> (setq dictionary-read-dictionary-function
>       #'dictionary-completing-read-dictionary)
> (setq dictionary-read-word-function
>       #'dictionary-completing-read-word)
> (setq dictionary-display-definition-function
>       #'dictionary-display-definition-in-help-buffer)
> --8<---------------cut here---------------end--------------->8---

This looks excessive.  How about adding yet another defcustom, with a
:set function, which will make all these adjustments for users who
want the words displayed in *Help*?



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-18 10:59                   ` Eli Zaretskii
@ 2023-05-18 12:21                     ` Eshel Yaron
  2023-05-18 14:09                       ` Eli Zaretskii
  0 siblings, 1 reply; 42+ messages in thread
From: Eshel Yaron @ 2023-05-18 12:21 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: philipk, emacs-devel

Eli Zaretskii <eliz@gnu.org> writes:

>> From: Eshel Yaron <me@eshelyaron.com>
>> Cc: philipk@posteo.net,  emacs-devel@gnu.org
>> Date: Mon, 15 May 2023 21:50:57 +0300
>> 
>> >> In short, we need two things: a way to obtain a word's definition and a
>> >> way to obtain dictionary matches given some input (for completion).
>> >> dictionary.el does these things already, but in way that's too coupled
>> >> with its user interface to admit reuse for my purposes.  So the question
>> >> is whether to add the needed stuff from Dict to dictionary.el and accept
>> >> some code duplication, or try to refactor the parts of dictionary.el
>> >> that communicate with the dictionary server to provide a cleaner API.
>> >
>> > I'd say try the latter if it's reasonably easy; otherwise try the
>> > former.
>> 
>> Alright, I'm attaching a patch that extends dictionary.el with new user
>> options that modify the behavior of `dictionary-search`.
>
> Looks reasonable, thanks.
>

Thank you for the review.

>> With this patch, `dictionary-search` behaves like my
>> `dict-describe-word` after applying the following customizations:
>> 
>> --8<---------------cut here---------------start------------->8---
>> (setq dictionary-read-dictionary-function
>>       #'dictionary-completing-read-dictionary)
>> (setq dictionary-read-word-function
>>       #'dictionary-completing-read-word)
>> (setq dictionary-display-definition-function
>>       #'dictionary-display-definition-in-help-buffer)
>> --8<---------------cut here---------------end--------------->8---
>
> This looks excessive.  How about adding yet another defcustom, with a
> :set function, which will make all these adjustments for users who
> want the words displayed in *Help*?

I agree setting three options may be a bit much for casual users, but
note that in order to display word definitions in *Help* you only need
to customize the last option, `dictionary-display-definition-function`.
The other two only affect the interactive word and dictionary selection
(mostly adding completion), so I'm not sure it's necessary to couple
them with how the definition ends up being presented.

-- 
Best

Eshel



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-15 18:50                 ` Eshel Yaron
  2023-05-18  7:57                   ` Eshel Yaron
  2023-05-18 10:59                   ` Eli Zaretskii
@ 2023-05-18 12:59                   ` Philip Kaludercic
  2023-05-18 15:37                     ` Eshel Yaron
  2 siblings, 1 reply; 42+ messages in thread
From: Philip Kaludercic @ 2023-05-18 12:59 UTC (permalink / raw)
  To: Eshel Yaron; +Cc: Eli Zaretskii, emacs-devel

Eshel Yaron <me@eshelyaron.com> writes:

> diff --git a/lisp/net/dictionary.el b/lisp/net/dictionary.el
> index ba65225692a..adf1f409f26 100644
> --- a/lisp/net/dictionary.el
> +++ b/lisp/net/dictionary.el
> @@ -38,6 +38,7 @@
>  (require 'custom)
>  (require 'dictionary-connection)
>  (require 'button)
> +(require 'help-mode)
>  
>  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
>  ;; Stuff for customizing.
> @@ -247,6 +248,39 @@ dictionary-coding-systems-for-dictionaries
>                                 )))
>    :version "28.1")
>  
> +(defcustom dictionary-read-word-prompt "Search word"
> +  "Prompt string to use when prompting for a word."
> +  :type 'string
> +  :version "30.1")
> +
> +(defcustom dictionary-display-definition-function nil
> +  "Function to use for displaying dictionary definitions.
> +It is called with three string arguments: the word being defined,
> +the dictionary name, and the full definition."
> +  :type '(choice (const :tag "Dictionary buffer" nil)
> +                 (const :tag "Help buffer"
> +                        dictionary-display-definition-in-help-buffer)
> +                 (function :tag "Custom function"))
> +  :version "30.1")
> +
> +(defcustom dictionary-read-word-function nil
> +  "Function to use for prompting for a word.
> +It is called with no arguments and must return a string."
> +  :type '(choice (const :tag "Default" nil)
> +                 (const :tag "Dictionary-based completion"
> +                        dictionary-completing-read-word)
> +                 (function :tag "Custom function"))
> +  :version "30.1")
> +
> +(defcustom dictionary-read-dictionary-function nil
> +  "Function to use for prompting for a dictionary.
> +It is called with no arguments and must return a string."
> +  :type '(choice (const :tag "Default" nil)
> +                 (const :tag "Choose among server-provided dictionaries"
> +                        dictionary-completing-read-dictionary)
> +                 (function :tag "Custom function"))
> +  :version "30.1")

Would there be a point in implementing the previous, default
implementations as functions here that would be invoked, instead of
relying using nil?

-- 
Philip Kaludercic



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-18 12:21                     ` Eshel Yaron
@ 2023-05-18 14:09                       ` Eli Zaretskii
  2023-05-18 15:51                         ` Eshel Yaron
  0 siblings, 1 reply; 42+ messages in thread
From: Eli Zaretskii @ 2023-05-18 14:09 UTC (permalink / raw)
  To: Eshel Yaron; +Cc: philipk, emacs-devel

> From: Eshel Yaron <me@eshelyaron.com>
> Cc: philipk@posteo.net,  emacs-devel@gnu.org
> Date: Thu, 18 May 2023 15:21:31 +0300
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> >> --8<---------------cut here---------------start------------->8---
> >> (setq dictionary-read-dictionary-function
> >>       #'dictionary-completing-read-dictionary)
> >> (setq dictionary-read-word-function
> >>       #'dictionary-completing-read-word)
> >> (setq dictionary-display-definition-function
> >>       #'dictionary-display-definition-in-help-buffer)
> >> --8<---------------cut here---------------end--------------->8---
> >
> > This looks excessive.  How about adding yet another defcustom, with a
> > :set function, which will make all these adjustments for users who
> > want the words displayed in *Help*?
> 
> I agree setting three options may be a bit much for casual users, but
> note that in order to display word definitions in *Help* you only need
> to customize the last option, `dictionary-display-definition-function`.
> The other two only affect the interactive word and dictionary selection
> (mostly adding completion), so I'm not sure it's necessary to couple
> them with how the definition ends up being presented.

Then why did you add the other options?



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-18 12:59                   ` Philip Kaludercic
@ 2023-05-18 15:37                     ` Eshel Yaron
  2023-05-18 15:58                       ` Philip Kaludercic
  0 siblings, 1 reply; 42+ messages in thread
From: Eshel Yaron @ 2023-05-18 15:37 UTC (permalink / raw)
  To: Philip Kaludercic; +Cc: Eli Zaretskii, emacs-devel

Philip Kaludercic <philipk@posteo.net> writes:

> Would there be a point in implementing the previous, default
> implementations as functions here that would be invoked, instead of
> relying using nil?

I'm not sure, I think these default functions wouldn't be very useful on
their own, so I don't know if it's worth extracting them.  But of course
we can do it if there's some important benefit I'm missing.



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-18 14:09                       ` Eli Zaretskii
@ 2023-05-18 15:51                         ` Eshel Yaron
  2023-05-18 15:58                           ` Eli Zaretskii
  0 siblings, 1 reply; 42+ messages in thread
From: Eshel Yaron @ 2023-05-18 15:51 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: philipk, emacs-devel

Eli Zaretskii <eliz@gnu.org> writes:

>> From: Eshel Yaron <me@eshelyaron.com>
>> Cc: philipk@posteo.net,  emacs-devel@gnu.org
>> Date: Thu, 18 May 2023 15:21:31 +0300
>> 
>> Eli Zaretskii <eliz@gnu.org> writes:
>> 
>> >> --8<---------------cut here---------------start------------->8---
>> >> (setq dictionary-read-dictionary-function
>> >>       #'dictionary-completing-read-dictionary)
>> >> (setq dictionary-read-word-function
>> >>       #'dictionary-completing-read-word)
>> >> (setq dictionary-display-definition-function
>> >>       #'dictionary-display-definition-in-help-buffer)
>> >> --8<---------------cut here---------------end--------------->8---
>> >
>> > This looks excessive.  How about adding yet another defcustom, with a
>> > :set function, which will make all these adjustments for users who
>> > want the words displayed in *Help*?
>> 
>> I agree setting three options may be a bit much for casual users, but
>> note that in order to display word definitions in *Help* you only need
>> to customize the last option, `dictionary-display-definition-function`.
>> The other two only affect the interactive word and dictionary selection
>> (mostly adding completion), so I'm not sure it's necessary to couple
>> them with how the definition ends up being presented.
>
> Then why did you add the other options?

I've added these options in the patch because I want to have minibuffer
completions in `dictionary-search`'s prompts, similarly to
`dict-describe-word`.  That's also why I mentioned all three
customizations in my earlier message: to show how to obtain the behavior
of `dict-describe-word` in dictionary.el using the new user options.

But from the perspective of other dictionary.el users, it may be useful
to customize each of the options but not the necessarily all of them.
That's why I implemented them as separate user options.  Makes sense?


-- 
Best,

Eshel



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-18 15:37                     ` Eshel Yaron
@ 2023-05-18 15:58                       ` Philip Kaludercic
  0 siblings, 0 replies; 42+ messages in thread
From: Philip Kaludercic @ 2023-05-18 15:58 UTC (permalink / raw)
  To: Eshel Yaron; +Cc: Eli Zaretskii, emacs-devel

Eshel Yaron <me@eshelyaron.com> writes:

> Philip Kaludercic <philipk@posteo.net> writes:
>
>> Would there be a point in implementing the previous, default
>> implementations as functions here that would be invoked, instead of
>> relying using nil?
>
> I'm not sure, I think these default functions wouldn't be very useful on
> their own, so I don't know if it's worth extracting them.  But of course
> we can do it if there's some important benefit I'm missing.

I would imagine that if you wanted to extend the default functionality,
e.g. by binding some variable or whatever one might want, having this
available as a function you can just call, would be useful. 

-- 
Philip Kaludercic



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-18 15:51                         ` Eshel Yaron
@ 2023-05-18 15:58                           ` Eli Zaretskii
  2023-05-19  8:34                             ` Eshel Yaron
  0 siblings, 1 reply; 42+ messages in thread
From: Eli Zaretskii @ 2023-05-18 15:58 UTC (permalink / raw)
  To: Eshel Yaron; +Cc: philipk, emacs-devel

> From: Eshel Yaron <me@eshelyaron.com>
> Cc: philipk@posteo.net,  emacs-devel@gnu.org
> Date: Thu, 18 May 2023 18:51:01 +0300
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> >> I agree setting three options may be a bit much for casual users, but
> >> note that in order to display word definitions in *Help* you only need
> >> to customize the last option, `dictionary-display-definition-function`.
> >> The other two only affect the interactive word and dictionary selection
> >> (mostly adding completion), so I'm not sure it's necessary to couple
> >> them with how the definition ends up being presented.
> >
> > Then why did you add the other options?
> 
> I've added these options in the patch because I want to have minibuffer
> completions in `dictionary-search`'s prompts, similarly to
> `dict-describe-word`.  That's also why I mentioned all three
> customizations in my earlier message: to show how to obtain the behavior
> of `dict-describe-word` in dictionary.el using the new user options.
> 
> But from the perspective of other dictionary.el users, it may be useful
> to customize each of the options but not the necessarily all of them.
> That's why I implemented them as separate user options.  Makes sense?

AFAIR, this started from you proposing a package that would behave as
if all 3 options were customized, and saying that you like this
alternative behavior much better, so much so that you felt a new
package is in order.  So I'm asking why not let users who, like you,
will like that much better, to get that behavior, with all its bells
and whistles, by setting just one option?  Wouldn't you personally
like such an option and use it all the time?



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-18 15:58                           ` Eli Zaretskii
@ 2023-05-19  8:34                             ` Eshel Yaron
  2023-05-20 14:19                               ` Eli Zaretskii
  2023-05-20 16:49                               ` Philip Kaludercic
  0 siblings, 2 replies; 42+ messages in thread
From: Eshel Yaron @ 2023-05-19  8:34 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: philipk, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 1573 bytes --]

Eli Zaretskii <eliz@gnu.org> writes:

>> I've added these options in the patch because I want to have minibuffer
>> completions in `dictionary-search`'s prompts, similarly to
>> `dict-describe-word`.  That's also why I mentioned all three
>> customizations in my earlier message: to show how to obtain the behavior
>> of `dict-describe-word` in dictionary.el using the new user options.
>> 
>> But from the perspective of other dictionary.el users, it may be useful
>> to customize each of the options but not the necessarily all of them.
>> That's why I implemented them as separate user options.  Makes sense?
>
> AFAIR, this started from you proposing a package that would behave as
> if all 3 options were customized, and saying that you like this
> alternative behavior much better, so much so that you felt a new
> package is in order.  So I'm asking why not let users who, like you,
> will like that much better, to get that behavior, with all its bells
> and whistles, by setting just one option?  Wouldn't you personally
> like such an option and use it all the time?

Yes, I see what you mean.  I'm attaching an updated patch that
implements your suggestion to add another `defcustom` with an
appropriate :set function.  It's now enough to do:

--8<---------------cut here---------------start------------->8---
(setopt dictionary-search-interface 'help)
--8<---------------cut here---------------end--------------->8---

The updated patch also tries to address Philip's recommendation to
extract the default parts of `dictionary-search` to standalone
functions.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: v2-0001-Add-customization-options-for-dictionary-search.patch --]
[-- Type: text/x-patch, Size: 13723 bytes --]

From 2bbd1767594990357f61d4af467093bf6abb117e Mon Sep 17 00:00:00 2001
From: Eshel Yaron <me@eshelyaron.com>
Date: Mon, 15 May 2023 21:04:21 +0300
Subject: [PATCH v2] Add customization options for dictionary-search

Allow users to customize 'dictionary-search' via several new
customization options.

* lisp/net/dictionary.el (dictionary-define-word)
(dictionary-match-word)
(dictionary-completing-read-word)
(dictionary-dictionaries)
(dictionary-completing-read-dictionary)
(dictionary-display-definition-in-help-buffer): New functions.
(dictionary-read-word-prompt)
(dictionary-display-definition-function)
(dictionary-read-word-function)
(dictionary-read-dictionary-function)
(dictionary-search-interface): New user options.
(dictionary-search): Use them.
(dictionary-read-dictionary-default)
(dictionary-read-word-default): New functions, extracted from
'dictionary-search'.
* etc/NEWS: Announce.
---
 etc/NEWS               |  44 +++++++++
 lisp/net/dictionary.el | 197 +++++++++++++++++++++++++++++++++++++----
 2 files changed, 226 insertions(+), 15 deletions(-)

diff --git a/etc/NEWS b/etc/NEWS
index f1fb70c5fc6..b673ac54ef3 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -333,6 +333,50 @@ instead of:
 *** New ':vc' keyword.
 This keyword enables the user to install packages using 'package-vc'.
 
+** Dictionary
+
+---
+*** New user option 'dictionary-search-interface'.
+Controls how the 'dictionary-search' command prompts for and displays
+dictionary definitions.  Customize this user option to 'help' to have
+'dictionary-search' display definitions in a *Help* buffer and provide
+dictionary-based minibuffer completion for word selection.
+
+---
+*** New user option 'dictionary-read-word-prompt'.
+This allows the user to customize the prompt that is used by
+'dictionary-search' when asking for a word to search in the
+dictionary.
+
+---
+*** New user option 'dictionary-display-definition-function'.
+This allows the user to customize the way in which 'dictionary-search'
+displays word definitions.  If non-nil, this user option should be set
+to a function that displays a word definition obtained from a
+dictionary server.  The new function
+'dictionary-display-definition-in-help-buffer' can be used to display
+the definition in a *Help* buffer, instead of the default *Dictionary*
+buffer.
+
+---
+*** New user option 'dictionary-read-word-function'.
+This allows the user to customize the way in which 'dictionary-search'
+prompts for a word to search in the dictionary.  This user option
+should be set to a function that lets the user select a word and
+returns it as a string.  The new function
+'dictionary-completing-read-word' can be used to prompt with
+completion based on dictionary matches.
+
+---
+*** New user option 'dictionary-read-dictionary-function'.
+This allows the user to customize the way in which 'dictionary-search'
+prompts for a dictionary to search in.  This user option should be set
+to a function that lets the user select a dictionary and returns its
+name as a string.  The new function
+'dictionary-completing-read-dictionary' can be used to prompt with
+completion based on dictionaries that the server supports.
+
+
 \f
 * New Modes and Packages in Emacs 30.1
 
diff --git a/lisp/net/dictionary.el b/lisp/net/dictionary.el
index ba65225692a..fafcd0f2594 100644
--- a/lisp/net/dictionary.el
+++ b/lisp/net/dictionary.el
@@ -38,6 +38,7 @@
 (require 'custom)
 (require 'dictionary-connection)
 (require 'button)
+(require 'help-mode)
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Stuff for customizing.
@@ -247,6 +248,64 @@ dictionary-coding-systems-for-dictionaries
                                )))
   :version "28.1")
 
+(defcustom dictionary-read-word-prompt "Search word"
+  "Prompt string to use when prompting for a word."
+  :type 'string
+  :version "30.1")
+
+(defcustom dictionary-display-definition-function nil
+  "Function to use for displaying dictionary definitions.
+It is called with three string arguments: the word being defined,
+the dictionary name, and the full definition."
+  :type '(choice (const :tag "Dictionary buffer" nil)
+                 (const :tag "Help buffer"
+                        dictionary-display-definition-in-help-buffer)
+                 (function :tag "Custom function"))
+  :version "30.1")
+
+(defcustom dictionary-read-word-function #'dictionary-read-word-default
+  "Function to use for prompting for a word.
+It is called with one string argument, the name of the dictionary to use, and
+must return a string."
+  :type '(choice (const :tag "Default" dictionary-read-word-default)
+                 (const :tag "Dictionary-based completion"
+                        dictionary-completing-read-word)
+                 (function :tag "Custom function"))
+  :version "30.1")
+
+(defcustom dictionary-read-dictionary-function
+  #'dictionary-read-dictionary-default
+  "Function to use for prompting for a dictionary.
+It is called with no arguments and must return a string."
+  :type '(choice (const :tag "Default" dictionary-read-dictionary-default)
+                 (const :tag "Choose among server-provided dictionaries"
+                        dictionary-completing-read-dictionary)
+                 (function :tag "Custom function"))
+  :version "30.1")
+
+(defcustom dictionary-search-interface nil
+  "Controls how `dictionary-search' prompts for words and displays definitions.
+
+When set to `help', `dictionary-search' displays definitions in a *Help* buffer,
+and provides completion for word selection based on dictionary matches.
+
+Otherwise, `dictionary-search' displays definitions in a *Dictionary* buffer."
+  :type '(choice (const :tag "Dictionary buffer" nil)
+                 (const :tag "Help buffer" help))
+  :set (lambda (symbol value)
+         (let ((vals (pcase value
+                       ('help '(dictionary-display-definition-in-help-buffer
+                                dictionary-completing-read-word
+                                dictionary-completing-read-dictionary))
+                       (_     '(nil
+                                dictionary-read-word-default
+                                dictionary-read-dictionary-default)))))
+           (setq dictionary-display-definition-function (nth 0 vals)
+                 dictionary-read-word-function          (nth 1 vals)
+                 dictionary-read-dictionary-function    (nth 2 vals)))
+         (set-default-toplevel-value symbol value))
+  :version "30.1")
+
 (defface dictionary-word-definition-face
 '((((supports (:family "DejaVu Serif")))
    (:family "DejaVu Serif"))
@@ -366,6 +425,8 @@ dictionary-word-history
   '()
   "History list of searched word.")
 
+(defvar dictionary--last-match nil)
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Basic function providing startup actions
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -1139,6 +1200,20 @@ dictionary-search-default
    ((car (get-char-property (point) 'data)))
    (t (current-word t))))
 
+(defun dictionary-read-dictionary-default ()
+  "Prompt for a dictionary name."
+  (read-string (if dictionary-default-dictionary
+		   (format "Dictionary (%s): "
+                           dictionary-default-dictionary)
+		 "Dictionary: ")
+	       nil nil dictionary-default-dictionary))
+
+(defun dictionary-read-word-default (_dictionary)
+  "Prompt for a word to search in the dictionary."
+  (let ((default (dictionary-search-default)))
+    (read-string (format-prompt dictionary-read-word-prompt default)
+                 nil 'dictionary-word-history default)))
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; User callable commands
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -1149,23 +1224,22 @@ dictionary-search
 It presents the selection or word at point as default input and
 allows editing it."
   (interactive
-   (list (let ((default (dictionary-search-default)))
-           (read-string (format-prompt "Search word" default)
-                        nil 'dictionary-word-history default))
-	 (if current-prefix-arg
-	     (read-string (if dictionary-default-dictionary
-			      (format "Dictionary (%s): " dictionary-default-dictionary)
-			    "Dictionary: ")
-			  nil nil dictionary-default-dictionary)
-	   dictionary-default-dictionary)))
-
-  ;; if called by pressing the button
-  (unless word
-    (setq word (read-string "Search word: " nil 'dictionary-word-history)))
-  ;; just in case non-interactively called
+   (let ((dict
+          (if current-prefix-arg
+              (funcall dictionary-read-dictionary-function)
+	    dictionary-default-dictionary)))
+     (list (funcall dictionary-read-word-function dict) dict)))
   (unless dictionary
     (setq dictionary dictionary-default-dictionary))
-  (dictionary-new-search (cons word dictionary)))
+  (if dictionary-display-definition-function
+      (if-let ((definition (dictionary-define-word word dictionary)))
+          (funcall dictionary-display-definition-function word dictionary definition)
+        (user-error "No definition found for \"%s\"" word))
+    ;; if called by pressing the button
+    (unless word
+      (setq word (read-string "Search word: " nil 'dictionary-word-history)))
+    ;; just in case non-interactively called
+    (dictionary-new-search (cons word dictionary))))
 
 ;;;###autoload
 (defun dictionary-lookup-definition ()
@@ -1386,5 +1460,98 @@ dictionary-context-menu
       'dictionary-separator))
   menu)
 
+(defun dictionary-define-word (word dictionary)
+  "Return the definition of WORD in DICTIONARY, or nil if not found."
+  (dictionary-send-command
+   (format "define %s \"%s\"" dictionary word))
+  (when (and (= (read (dictionary-read-reply)) 150)
+             (= (read (dictionary-read-reply)) 151))
+    (dictionary-read-answer)))
+
+(defun dictionary-match-word (word)
+  "Return dictionary matches for WORD as a list of strings."
+  (unless (string-empty-p word)
+    (if (string= (car dictionary--last-match) word)
+        (cdr dictionary--last-match)
+      (dictionary-send-command
+       (format "match %s %s \"%s\""
+               dictionary-default-dictionary
+               dictionary-default-strategy
+               word))
+      (when (and (= (read (dictionary-read-reply)) 152))
+        (with-temp-buffer
+          (insert (dictionary-read-answer))
+          (goto-char (point-min))
+          (let ((result nil))
+            (while (not (eobp))
+              (search-forward " " nil t)
+              (push (read (current-buffer)) result)
+              (search-forward "\n" nil t))
+            (setq result (reverse result))
+            (setq dictionary--last-match (cons word result))
+            result))))))
+
+(defun dictionary-completing-read-word (dictionary)
+  "Prompt for a word with completion based on matches in DICTIONARY."
+  (let* ((completion-ignore-case t)
+         (dictionary-default-dictionary dictionary)
+         (word-at-point (thing-at-point 'word t))
+         (default (dictionary-match-word word-at-point)))
+    (completing-read (format-prompt dictionary-read-word-prompt default)
+                     (completion-table-dynamic #'dictionary-match-word)
+                     nil t nil 'dictionary-word-history default t)))
+
+(defun dictionary-dictionaries ()
+  "Return the list of dictionaries the server supports."
+  (dictionary-send-command "show db")
+  (when (and (= (read (dictionary-read-reply)) 110))
+    (with-temp-buffer
+      (insert (dictionary-read-answer))
+      (goto-char (point-min))
+      (let ((result '(("!" . "First matching dictionary")
+                      ("*" . "All dictionaries"))))
+        (while (not (eobp))
+          (push (cons (buffer-substring
+                       (search-forward "\n" nil t)
+                       (1- (search-forward " " nil t)))
+                      (read (current-buffer)))
+                result))
+        (reverse result)))))
+
+(defun dictionary-completing-read-dictionary ()
+  "Prompt for a dictionary the server supports."
+  (let* ((dicts (dictionary-dictionaries))
+         (len (apply #'max (mapcar #'length (mapcar #'car dicts))))
+         (completion-extra-properties
+          (list :annotation-function
+                (lambda (key)
+                  (concat (make-string (1+ (- len (length key))) ?\s)
+                          (alist-get key dicts nil nil #'string=))))))
+    (completing-read (format-prompt "Select dictionary"
+                                    dictionary-default-dictionary)
+                     dicts nil t nil nil dictionary-default-dictionary)))
+
+(define-button-type 'help-word
+  :supertype 'help-xref
+  'help-function 'dictionary-search
+  'help-echo (purecopy "mouse-2, RET: describe this word"))
+
+(defun dictionary-display-definition-in-help-buffer (word dictionary definition)
+  "Display DEFINITION, the definition of WORD in DICTIONARY."
+  (let ((help-buffer-under-preparation t))
+    (help-setup-xref (list #'dictionary-search word dictionary)
+                     (called-interactively-p 'interactive))
+    (with-help-window (help-buffer)
+      (with-current-buffer (help-buffer)
+        (insert definition)
+        (goto-char (point-min))
+        (while (re-search-forward (rx "{"
+                                      (group-n 1 (* (not (any ?}))))
+                                      "}")
+                                  nil t)
+          (help-xref-button 1 'help-word
+                            (match-string 1)
+                            dictionary))))))
+
 (provide 'dictionary)
 ;;; dictionary.el ends here
-- 
2.40.1


[-- Attachment #3: Type: text/plain, Size: 20 bytes --]


-- 
Thanks,

Eshel

^ permalink raw reply related	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-19  8:34                             ` Eshel Yaron
@ 2023-05-20 14:19                               ` Eli Zaretskii
  2023-05-20 16:49                               ` Philip Kaludercic
  1 sibling, 0 replies; 42+ messages in thread
From: Eli Zaretskii @ 2023-05-20 14:19 UTC (permalink / raw)
  To: Eshel Yaron; +Cc: philipk, emacs-devel

> From: Eshel Yaron <me@eshelyaron.com>
> Cc: philipk@posteo.net,  emacs-devel@gnu.org
> Date: Fri, 19 May 2023 11:34:12 +0300
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> > AFAIR, this started from you proposing a package that would behave as
> > if all 3 options were customized, and saying that you like this
> > alternative behavior much better, so much so that you felt a new
> > package is in order.  So I'm asking why not let users who, like you,
> > will like that much better, to get that behavior, with all its bells
> > and whistles, by setting just one option?  Wouldn't you personally
> > like such an option and use it all the time?
> 
> Yes, I see what you mean.  I'm attaching an updated patch that
> implements your suggestion to add another `defcustom` with an
> appropriate :set function.  It's now enough to do:
> 
> --8<---------------cut here---------------start------------->8---
> (setopt dictionary-search-interface 'help)
> --8<---------------cut here---------------end--------------->8---
> 
> The updated patch also tries to address Philip's recommendation to
> extract the default parts of `dictionary-search` to standalone
> functions.

Thanks, LGTM.  Let's wait for a few days to let others to chime in
with comments.



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-19  8:34                             ` Eshel Yaron
  2023-05-20 14:19                               ` Eli Zaretskii
@ 2023-05-20 16:49                               ` Philip Kaludercic
  2023-05-20 18:27                                 ` Eshel Yaron
  1 sibling, 1 reply; 42+ messages in thread
From: Philip Kaludercic @ 2023-05-20 16:49 UTC (permalink / raw)
  To: Eshel Yaron; +Cc: Eli Zaretskii, emacs-devel

Eshel Yaron <me@eshelyaron.com> writes:

> Eli Zaretskii <eliz@gnu.org> writes:
>
>>> I've added these options in the patch because I want to have minibuffer
>>> completions in `dictionary-search`'s prompts, similarly to
>>> `dict-describe-word`.  That's also why I mentioned all three
>>> customizations in my earlier message: to show how to obtain the behavior
>>> of `dict-describe-word` in dictionary.el using the new user options.
>>> 
>>> But from the perspective of other dictionary.el users, it may be useful
>>> to customize each of the options but not the necessarily all of them.
>>> That's why I implemented them as separate user options.  Makes sense?
>>
>> AFAIR, this started from you proposing a package that would behave as
>> if all 3 options were customized, and saying that you like this
>> alternative behavior much better, so much so that you felt a new
>> package is in order.  So I'm asking why not let users who, like you,
>> will like that much better, to get that behavior, with all its bells
>> and whistles, by setting just one option?  Wouldn't you personally
>> like such an option and use it all the time?
>
> Yes, I see what you mean.  I'm attaching an updated patch that
> implements your suggestion to add another `defcustom` with an
> appropriate :set function.  It's now enough to do:
>
> (setopt dictionary-search-interface 'help)
>
> The updated patch also tries to address Philip's recommendation to
> extract the default parts of `dictionary-search` to standalone
> functions.
>
> From 2bbd1767594990357f61d4af467093bf6abb117e Mon Sep 17 00:00:00 2001
> From: Eshel Yaron <me@eshelyaron.com>
> Date: Mon, 15 May 2023 21:04:21 +0300
> Subject: [PATCH v2] Add customization options for dictionary-search
>
> Allow users to customize 'dictionary-search' via several new
> customization options.
>
> * lisp/net/dictionary.el (dictionary-define-word)
> (dictionary-match-word)
> (dictionary-completing-read-word)
> (dictionary-dictionaries)
> (dictionary-completing-read-dictionary)
> (dictionary-display-definition-in-help-buffer): New functions.
> (dictionary-read-word-prompt)
> (dictionary-display-definition-function)
> (dictionary-read-word-function)
> (dictionary-read-dictionary-function)
> (dictionary-search-interface): New user options.
> (dictionary-search): Use them.
> (dictionary-read-dictionary-default)
> (dictionary-read-word-default): New functions, extracted from
> 'dictionary-search'.

Shouldn't these Changelog entries be folded together?  

* lisp/net/dictionary.el (dictionary-define-word, dictionary-match-word,
dictionary-completing-read-word, dictionary-dictionaries,
dictionary-completing-read-dictionary,
dictionary-display-definition-in-help-buffer): New functions.

> * etc/NEWS: Announce.
> ---
>  etc/NEWS               |  44 +++++++++
>  lisp/net/dictionary.el | 197 +++++++++++++++++++++++++++++++++++++----
>  2 files changed, 226 insertions(+), 15 deletions(-)
>
> diff --git a/etc/NEWS b/etc/NEWS
> index f1fb70c5fc6..b673ac54ef3 100644
> --- a/etc/NEWS
> +++ b/etc/NEWS
> @@ -333,6 +333,50 @@ instead of:
>  *** New ':vc' keyword.
>  This keyword enables the user to install packages using 'package-vc'.
>  
> +** Dictionary
> +
> +---
> +*** New user option 'dictionary-search-interface'.
> +Controls how the 'dictionary-search' command prompts for and displays
> +dictionary definitions.  Customize this user option to 'help' to have
> +'dictionary-search' display definitions in a *Help* buffer and provide
> +dictionary-based minibuffer completion for word selection.
> +
> +---
> +*** New user option 'dictionary-read-word-prompt'.
> +This allows the user to customize the prompt that is used by
> +'dictionary-search' when asking for a word to search in the
> +dictionary.
> +
> +---
> +*** New user option 'dictionary-display-definition-function'.
> +This allows the user to customize the way in which 'dictionary-search'
> +displays word definitions.  If non-nil, this user option should be set
> +to a function that displays a word definition obtained from a
> +dictionary server.  The new function
> +'dictionary-display-definition-in-help-buffer' can be used to display
> +the definition in a *Help* buffer, instead of the default *Dictionary*
> +buffer.
> +
> +---
> +*** New user option 'dictionary-read-word-function'.
> +This allows the user to customize the way in which 'dictionary-search'
> +prompts for a word to search in the dictionary.  This user option
> +should be set to a function that lets the user select a word and
> +returns it as a string.  The new function
> +'dictionary-completing-read-word' can be used to prompt with
> +completion based on dictionary matches.
> +
> +---
> +*** New user option 'dictionary-read-dictionary-function'.
> +This allows the user to customize the way in which 'dictionary-search'
> +prompts for a dictionary to search in.  This user option should be set
> +to a function that lets the user select a dictionary and returns its
> +name as a string.  The new function
> +'dictionary-completing-read-dictionary' can be used to prompt with
> +completion based on dictionaries that the server supports.
> +
> +
>  \f
>  * New Modes and Packages in Emacs 30.1
>  
> diff --git a/lisp/net/dictionary.el b/lisp/net/dictionary.el
> index ba65225692a..fafcd0f2594 100644
> --- a/lisp/net/dictionary.el
> +++ b/lisp/net/dictionary.el
> @@ -38,6 +38,7 @@
>  (require 'custom)
>  (require 'dictionary-connection)
>  (require 'button)
> +(require 'help-mode)
>  
>  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
>  ;; Stuff for customizing.
> @@ -247,6 +248,64 @@ dictionary-coding-systems-for-dictionaries
>                                 )))
>    :version "28.1")
>  
> +(defcustom dictionary-read-word-prompt "Search word"
> +  "Prompt string to use when prompting for a word."
> +  :type 'string
> +  :version "30.1")
> +
> +(defcustom dictionary-display-definition-function nil
> +  "Function to use for displaying dictionary definitions.
> +It is called with three string arguments: the word being defined,
> +the dictionary name, and the full definition."
> +  :type '(choice (const :tag "Dictionary buffer" nil)
> +                 (const :tag "Help buffer"
> +                        dictionary-display-definition-in-help-buffer)
> +                 (function :tag "Custom function"))
> +  :version "30.1")

What is the reason for having this option fallback to nil?  I couldn't
make that out from the patch.  If all the other options offer a
concrete-default function (that you could also call in your own
function), then it seems inconsistent to not provide this here as well.

> +(defcustom dictionary-read-word-function #'dictionary-read-word-default
> +  "Function to use for prompting for a word.
> +It is called with one string argument, the name of the dictionary to use, and
> +must return a string."
> +  :type '(choice (const :tag "Default" dictionary-read-word-default)
> +                 (const :tag "Dictionary-based completion"
> +                        dictionary-completing-read-word)
> +                 (function :tag "Custom function"))
> +  :version "30.1")
> +
> +(defcustom dictionary-read-dictionary-function
> +  #'dictionary-read-dictionary-default
> +  "Function to use for prompting for a dictionary.
> +It is called with no arguments and must return a string."
> +  :type '(choice (const :tag "Default" dictionary-read-dictionary-default)
> +                 (const :tag "Choose among server-provided dictionaries"
> +                        dictionary-completing-read-dictionary)
> +                 (function :tag "Custom function"))
> +  :version "30.1")
> +
> +(defcustom dictionary-search-interface nil
> +  "Controls how `dictionary-search' prompts for words and displays definitions.
> +
> +When set to `help', `dictionary-search' displays definitions in a *Help* buffer,
> +and provides completion for word selection based on dictionary matches.
> +
> +Otherwise, `dictionary-search' displays definitions in a *Dictionary* buffer."
> +  :type '(choice (const :tag "Dictionary buffer" nil)
> +                 (const :tag "Help buffer" help))
> +  :set (lambda (symbol value)
> +         (let ((vals (pcase value
> +                       ('help '(dictionary-display-definition-in-help-buffer
> +                                dictionary-completing-read-word
> +                                dictionary-completing-read-dictionary))
> +                       (_     '(nil
> +                                dictionary-read-word-default
> +                                dictionary-read-dictionary-default)))))
> +           (setq dictionary-display-definition-function (nth 0 vals)
> +                 dictionary-read-word-function          (nth 1 vals)
> +                 dictionary-read-dictionary-function    (nth 2 vals)))

I think you could also make use of seq-setq here?

> +         (set-default-toplevel-value symbol value))
> +  :version "30.1")
> +
>  (defface dictionary-word-definition-face
>  '((((supports (:family "DejaVu Serif")))
>     (:family "DejaVu Serif"))
> @@ -366,6 +425,8 @@ dictionary-word-history
>    '()
>    "History list of searched word.")
>  
> +(defvar dictionary--last-match nil)
> +
>  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
>  ;; Basic function providing startup actions
>  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> @@ -1139,6 +1200,20 @@ dictionary-search-default
>     ((car (get-char-property (point) 'data)))
>     (t (current-word t))))
>  
> +(defun dictionary-read-dictionary-default ()
> +  "Prompt for a dictionary name."
> +  (read-string (if dictionary-default-dictionary
> +		   (format "Dictionary (%s): "
> +                           dictionary-default-dictionary)
> +		 "Dictionary: ")
> +	       nil nil dictionary-default-dictionary))
> +
> +(defun dictionary-read-word-default (_dictionary)
> +  "Prompt for a word to search in the dictionary."
> +  (let ((default (dictionary-search-default)))
> +    (read-string (format-prompt dictionary-read-word-prompt default)
> +                 nil 'dictionary-word-history default)))
> +
>  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
>  ;; User callable commands
>  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> @@ -1149,23 +1224,22 @@ dictionary-search
>  It presents the selection or word at point as default input and
>  allows editing it."
>    (interactive
> -   (list (let ((default (dictionary-search-default)))
> -           (read-string (format-prompt "Search word" default)
> -                        nil 'dictionary-word-history default))
> -	 (if current-prefix-arg
> -	     (read-string (if dictionary-default-dictionary
> -			      (format "Dictionary (%s): " dictionary-default-dictionary)
> -			    "Dictionary: ")
> -			  nil nil dictionary-default-dictionary)
> -	   dictionary-default-dictionary)))
> -
> -  ;; if called by pressing the button
> -  (unless word
> -    (setq word (read-string "Search word: " nil 'dictionary-word-history)))
> -  ;; just in case non-interactively called
> +   (let ((dict
> +          (if current-prefix-arg
> +              (funcall dictionary-read-dictionary-function)
> +	    dictionary-default-dictionary)))
> +     (list (funcall dictionary-read-word-function dict) dict)))
>    (unless dictionary
>      (setq dictionary dictionary-default-dictionary))
> -  (dictionary-new-search (cons word dictionary)))
> +  (if dictionary-display-definition-function
> +      (if-let ((definition (dictionary-define-word word dictionary)))
> +          (funcall dictionary-display-definition-function word dictionary definition)
> +        (user-error "No definition found for \"%s\"" word))
> +    ;; if called by pressing the button
> +    (unless word
> +      (setq word (read-string "Search word: " nil 'dictionary-word-history)))
> +    ;; just in case non-interactively called
> +    (dictionary-new-search (cons word dictionary))))
>  
>  ;;;###autoload
>  (defun dictionary-lookup-definition ()
> @@ -1386,5 +1460,98 @@ dictionary-context-menu
>        'dictionary-separator))
>    menu)
>  
> +(defun dictionary-define-word (word dictionary)
> +  "Return the definition of WORD in DICTIONARY, or nil if not found."
> +  (dictionary-send-command
> +   (format "define %s \"%s\"" dictionary word))
> +  (when (and (= (read (dictionary-read-reply)) 150)
> +             (= (read (dictionary-read-reply)) 151))

I think a memq would be nice here.

> +    (dictionary-read-answer)))
> +
> +(defun dictionary-match-word (word)
> +  "Return dictionary matches for WORD as a list of strings."
> +  (unless (string-empty-p word)
> +    (if (string= (car dictionary--last-match) word)
> +        (cdr dictionary--last-match)
> +      (dictionary-send-command
> +       (format "match %s %s \"%s\""
> +               dictionary-default-dictionary
> +               dictionary-default-strategy
> +               word))
> +      (when (and (= (read (dictionary-read-reply)) 152))
> +        (with-temp-buffer
> +          (insert (dictionary-read-answer))
> +          (goto-char (point-min))
> +          (let ((result nil))
> +            (while (not (eobp))
> +              (search-forward " " nil t)
> +              (push (read (current-buffer)) result)
> +              (search-forward "\n" nil t))
> +            (setq result (reverse result))
> +            (setq dictionary--last-match (cons word result))
> +            result))))))
> +
> +(defun dictionary-completing-read-word (dictionary)
> +  "Prompt for a word with completion based on matches in DICTIONARY."
> +  (let* ((completion-ignore-case t)
> +         (dictionary-default-dictionary dictionary)
> +         (word-at-point (thing-at-point 'word t))
> +         (default (dictionary-match-word word-at-point)))
> +    (completing-read (format-prompt dictionary-read-word-prompt default)
> +                     (completion-table-dynamic #'dictionary-match-word)
> +                     nil t nil 'dictionary-word-history default t)))
> +
> +(defun dictionary-dictionaries ()
> +  "Return the list of dictionaries the server supports."
> +  (dictionary-send-command "show db")
> +  (when (and (= (read (dictionary-read-reply)) 110))
> +    (with-temp-buffer
> +      (insert (dictionary-read-answer))
> +      (goto-char (point-min))
> +      (let ((result '(("!" . "First matching dictionary")
> +                      ("*" . "All dictionaries"))))
> +        (while (not (eobp))
> +          (push (cons (buffer-substring
> +                       (search-forward "\n" nil t)
> +                       (1- (search-forward " " nil t)))
> +                      (read (current-buffer)))
> +                result))
> +        (reverse result)))))
> +
> +(defun dictionary-completing-read-dictionary ()
> +  "Prompt for a dictionary the server supports."
> +  (let* ((dicts (dictionary-dictionaries))
> +         (len (apply #'max (mapcar #'length (mapcar #'car dicts))))
> +         (completion-extra-properties
> +          (list :annotation-function
> +                (lambda (key)
> +                  (concat (make-string (1+ (- len (length key))) ?\s)
> +                          (alist-get key dicts nil nil #'string=))))))
> +    (completing-read (format-prompt "Select dictionary"
> +                                    dictionary-default-dictionary)
> +                     dicts nil t nil nil dictionary-default-dictionary)))
> +
> +(define-button-type 'help-word
> +  :supertype 'help-xref
> +  'help-function 'dictionary-search
> +  'help-echo (purecopy "mouse-2, RET: describe this word"))

Why the purecopy?

> +(defun dictionary-display-definition-in-help-buffer (word dictionary definition)
> +  "Display DEFINITION, the definition of WORD in DICTIONARY."
> +  (let ((help-buffer-under-preparation t))
> +    (help-setup-xref (list #'dictionary-search word dictionary)
> +                     (called-interactively-p 'interactive))
> +    (with-help-window (help-buffer)
> +      (with-current-buffer (help-buffer)
> +        (insert definition)
> +        (goto-char (point-min))
> +        (while (re-search-forward (rx "{"
> +                                      (group-n 1 (* (not (any ?}))))
> +                                      "}")
> +                                  nil t)

Perhaps you could explain what is going on here.  Why is this pattern
significant?

> +          (help-xref-button 1 'help-word
> +                            (match-string 1)
> +                            dictionary))))))
> +
>  (provide 'dictionary)
>  ;;; dictionary.el ends here
> -- 
> 2.40.1



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-20 16:49                               ` Philip Kaludercic
@ 2023-05-20 18:27                                 ` Eshel Yaron
  2023-05-20 19:11                                   ` Philip Kaludercic
  0 siblings, 1 reply; 42+ messages in thread
From: Eshel Yaron @ 2023-05-20 18:27 UTC (permalink / raw)
  To: Philip Kaludercic; +Cc: Eli Zaretskii, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 6196 bytes --]

Hi Philip,

Thanks for your comments, I'm responding to them inline and attaching a
slightly updated patch based on them below.

Philip Kaludercic <philipk@posteo.net> writes:

>> From 2bbd1767594990357f61d4af467093bf6abb117e Mon Sep 17 00:00:00 2001
>> From: Eshel Yaron <me@eshelyaron.com>
>> Date: Mon, 15 May 2023 21:04:21 +0300
>> Subject: [PATCH v2] Add customization options for dictionary-search
>>
>> Allow users to customize 'dictionary-search' via several new
>> customization options.
>>
>> * lisp/net/dictionary.el (dictionary-define-word)
>> (dictionary-match-word)
>> (dictionary-completing-read-word)
>> (dictionary-dictionaries)
>> (dictionary-completing-read-dictionary)
>> (dictionary-display-definition-in-help-buffer): New functions.
>> (dictionary-read-word-prompt)
>> (dictionary-display-definition-function)
>> (dictionary-read-word-function)
>> (dictionary-read-dictionary-function)
>> (dictionary-search-interface): New user options.
>> (dictionary-search): Use them.
>> (dictionary-read-dictionary-default)
>> (dictionary-read-word-default): New functions, extracted from
>> 'dictionary-search'.
>
> Shouldn't these Changelog entries be folded together?  
>
> * lisp/net/dictionary.el (dictionary-define-word, dictionary-match-word,
> dictionary-completing-read-word, dictionary-dictionaries,
> dictionary-completing-read-dictionary,
> dictionary-display-definition-in-help-buffer): New functions.
>

I'm not sure, the way I read the example commit message in CONTRIBUTE is
that opening and closing parentheses should appear on the same line, no?
Anyway I updated the commit message to be a bit more compact.

>> +(defcustom dictionary-display-definition-function nil
>> +  "Function to use for displaying dictionary definitions.
>> +It is called with three string arguments: the word being defined,
>> +the dictionary name, and the full definition."
>> +  :type '(choice (const :tag "Dictionary buffer" nil)
>> +                 (const :tag "Help buffer"
>> +                        dictionary-display-definition-in-help-buffer)
>> +                 (function :tag "Custom function"))
>> +  :version "30.1")
>
> What is the reason for having this option fallback to nil?  I couldn't
> make that out from the patch.  If all the other options offer a
> concrete-default function (that you could also call in your own
> function), then it seems inconsistent to not provide this here as well.
>

The reason is that, unlike the other options, the default path that
`dictionary-search` takes to displaying a definition is highly coupled
with how it obtains the definition, making it difficult to extract into
a standalone function.  That's a refactor I prefer to avoid at this
point.  So, if you set `dictionary-display-definition-function` to a
custom function, we use the new function `dictionary-define-word` to
cleanly obtain the definition and let your custom function display it.
If you use the default (nil) value, we let `dictionary-search` call the
"old" function `dictionary-new-search` that both obtains and displays
the definition.

>> +(defcustom dictionary-search-interface nil
>> +  "Controls how `dictionary-search' prompts for words and displays definitions.
>> +
>> +When set to `help', `dictionary-search' displays definitions in a *Help* buffer,
>> +and provides completion for word selection based on dictionary matches.
>> +
>> +Otherwise, `dictionary-search' displays definitions in a *Dictionary* buffer."
>> +  :type '(choice (const :tag "Dictionary buffer" nil)
>> +                 (const :tag "Help buffer" help))
>> +  :set (lambda (symbol value)
>> +         (let ((vals (pcase value
>> +                       ('help '(dictionary-display-definition-in-help-buffer
>> +                                dictionary-completing-read-word
>> +                                dictionary-completing-read-dictionary))
>> +                       (_     '(nil
>> +                                dictionary-read-word-default
>> +                                dictionary-read-dictionary-default)))))
>> +           (setq dictionary-display-definition-function (nth 0 vals)
>> +                 dictionary-read-word-function          (nth 1 vals)
>> +                 dictionary-read-dictionary-function    (nth 2 vals)))
>
> I think you could also make use of seq-setq here?
>

Done, in the updated patch.

>> +(defun dictionary-define-word (word dictionary)
>> +  "Return the definition of WORD in DICTIONARY, or nil if not found."
>> +  (dictionary-send-command
>> +   (format "define %s \"%s\"" dictionary word))
>> +  (when (and (= (read (dictionary-read-reply)) 150)
>> +             (= (read (dictionary-read-reply)) 151))
>
> I think a memq would be nice here.
>

No, `memq` would be appropriate if we wanted to check that the
expression `(read (dictionary-read-reply))` evaluates to either 150 or
to 151, but here we want to check that it evaluates 150 and then
afterwards that it evaluates to 151.

>> +(define-button-type 'help-word
>> +  :supertype 'help-xref
>> +  'help-function 'dictionary-search
>> +  'help-echo (purecopy "mouse-2, RET: describe this word"))
>
> Why the purecopy?
>

Thanks, I guess that's something I copied from the button definitions in
help-mode.el.  Removed.

>> +(defun dictionary-display-definition-in-help-buffer (word dictionary definition)
>> +  "Display DEFINITION, the definition of WORD in DICTIONARY."
>> +  (let ((help-buffer-under-preparation t))
>> +    (help-setup-xref (list #'dictionary-search word dictionary)
>> +                     (called-interactively-p 'interactive))
>> +    (with-help-window (help-buffer)
>> +      (with-current-buffer (help-buffer)
>> +        (insert definition)
>> +        (goto-char (point-min))
>> +        (while (re-search-forward (rx "{"
>> +                                      (group-n 1 (* (not (any ?}))))
>> +                                      "}")
>> +                                  nil t)
>
> Perhaps you could explain what is going on here.  Why is this pattern
> significant?
>

We want to buttonize references to other definitions in the *Help*
buffer, which appear enclosed in curly braces.  I've added a comment
explaining this.

Updated patch:


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: v3-0001-Add-customization-options-for-dictionary-search.patch --]
[-- Type: text/x-patch, Size: 13821 bytes --]

From 1661dfd141d0ef49367f2312aa28a8b5e68a3caa Mon Sep 17 00:00:00 2001
From: Eshel Yaron <me@eshelyaron.com>
Date: Mon, 15 May 2023 21:04:21 +0300
Subject: [PATCH v3] Add customization options for dictionary-search

Allow users to customize 'dictionary-search' via several new
customization options.

* lisp/net/dictionary.el (dictionary-define-word)
(dictionary-match-word, dictionary-completing-read-word)
(dictionary-dictionaries, dictionary-completing-read-dictionary)
(dictionary-display-definition-in-help-buffer): New functions.
(dictionary-read-word-prompt)
(dictionary-display-definition-function)
(dictionary-read-word-function)
(dictionary-read-dictionary-function)
(dictionary-search-interface): New user options.
(dictionary-search): Use them.
(dictionary-read-dictionary-default)
(dictionary-read-word-default): New functions, extracted from
'dictionary-search'.
* etc/NEWS: Announce.
---
 etc/NEWS               |  44 +++++++++
 lisp/net/dictionary.el | 200 +++++++++++++++++++++++++++++++++++++----
 2 files changed, 229 insertions(+), 15 deletions(-)

diff --git a/etc/NEWS b/etc/NEWS
index 04ef976a8d1..cd176685c14 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -333,6 +333,50 @@ instead of:
 *** New ':vc' keyword.
 This keyword enables the user to install packages using 'package-vc'.
 
+** Dictionary
+
+---
+*** New user option 'dictionary-search-interface'.
+Controls how the 'dictionary-search' command prompts for and displays
+dictionary definitions.  Customize this user option to 'help' to have
+'dictionary-search' display definitions in a *Help* buffer and provide
+dictionary-based minibuffer completion for word selection.
+
+---
+*** New user option 'dictionary-read-word-prompt'.
+This allows the user to customize the prompt that is used by
+'dictionary-search' when asking for a word to search in the
+dictionary.
+
+---
+*** New user option 'dictionary-display-definition-function'.
+This allows the user to customize the way in which 'dictionary-search'
+displays word definitions.  If non-nil, this user option should be set
+to a function that displays a word definition obtained from a
+dictionary server.  The new function
+'dictionary-display-definition-in-help-buffer' can be used to display
+the definition in a *Help* buffer, instead of the default *Dictionary*
+buffer.
+
+---
+*** New user option 'dictionary-read-word-function'.
+This allows the user to customize the way in which 'dictionary-search'
+prompts for a word to search in the dictionary.  This user option
+should be set to a function that lets the user select a word and
+returns it as a string.  The new function
+'dictionary-completing-read-word' can be used to prompt with
+completion based on dictionary matches.
+
+---
+*** New user option 'dictionary-read-dictionary-function'.
+This allows the user to customize the way in which 'dictionary-search'
+prompts for a dictionary to search in.  This user option should be set
+to a function that lets the user select a dictionary and returns its
+name as a string.  The new function
+'dictionary-completing-read-dictionary' can be used to prompt with
+completion based on dictionaries that the server supports.
+
+
 \f
 * New Modes and Packages in Emacs 30.1
 
diff --git a/lisp/net/dictionary.el b/lisp/net/dictionary.el
index ba65225692a..f5116dc28da 100644
--- a/lisp/net/dictionary.el
+++ b/lisp/net/dictionary.el
@@ -38,6 +38,7 @@
 (require 'custom)
 (require 'dictionary-connection)
 (require 'button)
+(require 'help-mode)
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Stuff for customizing.
@@ -247,6 +248,65 @@ dictionary-coding-systems-for-dictionaries
                                )))
   :version "28.1")
 
+(defcustom dictionary-read-word-prompt "Search word"
+  "Prompt string to use when prompting for a word."
+  :type 'string
+  :version "30.1")
+
+(defcustom dictionary-display-definition-function nil
+  "Function to use for displaying dictionary definitions.
+It is called with three string arguments: the word being defined,
+the dictionary name, and the full definition."
+  :type '(choice (const :tag "Dictionary buffer" nil)
+                 (const :tag "Help buffer"
+                        dictionary-display-definition-in-help-buffer)
+                 (function :tag "Custom function"))
+  :version "30.1")
+
+(defcustom dictionary-read-word-function #'dictionary-read-word-default
+  "Function to use for prompting for a word.
+It is called with one string argument, the name of the dictionary to use, and
+must return a string."
+  :type '(choice (const :tag "Default" dictionary-read-word-default)
+                 (const :tag "Dictionary-based completion"
+                        dictionary-completing-read-word)
+                 (function :tag "Custom function"))
+  :version "30.1")
+
+(defcustom dictionary-read-dictionary-function
+  #'dictionary-read-dictionary-default
+  "Function to use for prompting for a dictionary.
+It is called with no arguments and must return a string."
+  :type '(choice (const :tag "Default" dictionary-read-dictionary-default)
+                 (const :tag "Choose among server-provided dictionaries"
+                        dictionary-completing-read-dictionary)
+                 (function :tag "Custom function"))
+  :version "30.1")
+
+(defcustom dictionary-search-interface nil
+  "Controls how `dictionary-search' prompts for words and displays definitions.
+
+When set to `help', `dictionary-search' displays definitions in a *Help* buffer,
+and provides completion for word selection based on dictionary matches.
+
+Otherwise, `dictionary-search' displays definitions in a *Dictionary* buffer."
+  :type '(choice (const :tag "Dictionary buffer" nil)
+                 (const :tag "Help buffer" help))
+  :set (lambda (symbol value)
+         (let ((vals (pcase value
+                       ('help '(dictionary-display-definition-in-help-buffer
+                                dictionary-completing-read-word
+                                dictionary-completing-read-dictionary))
+                       (_     '(nil
+                                dictionary-read-word-default
+                                dictionary-read-dictionary-default)))))
+           (seq-setq (dictionary-display-definition-function
+                      dictionary-read-word-function
+                      dictionary-read-dictionary-function)
+                     vals))
+         (set-default-toplevel-value symbol value))
+  :version "30.1")
+
 (defface dictionary-word-definition-face
 '((((supports (:family "DejaVu Serif")))
    (:family "DejaVu Serif"))
@@ -366,6 +426,8 @@ dictionary-word-history
   '()
   "History list of searched word.")
 
+(defvar dictionary--last-match nil)
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Basic function providing startup actions
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -1139,6 +1201,20 @@ dictionary-search-default
    ((car (get-char-property (point) 'data)))
    (t (current-word t))))
 
+(defun dictionary-read-dictionary-default ()
+  "Prompt for a dictionary name."
+  (read-string (if dictionary-default-dictionary
+		   (format "Dictionary (%s): "
+                           dictionary-default-dictionary)
+		 "Dictionary: ")
+	       nil nil dictionary-default-dictionary))
+
+(defun dictionary-read-word-default (_dictionary)
+  "Prompt for a word to search in the dictionary."
+  (let ((default (dictionary-search-default)))
+    (read-string (format-prompt dictionary-read-word-prompt default)
+                 nil 'dictionary-word-history default)))
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; User callable commands
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -1149,23 +1225,22 @@ dictionary-search
 It presents the selection or word at point as default input and
 allows editing it."
   (interactive
-   (list (let ((default (dictionary-search-default)))
-           (read-string (format-prompt "Search word" default)
-                        nil 'dictionary-word-history default))
-	 (if current-prefix-arg
-	     (read-string (if dictionary-default-dictionary
-			      (format "Dictionary (%s): " dictionary-default-dictionary)
-			    "Dictionary: ")
-			  nil nil dictionary-default-dictionary)
-	   dictionary-default-dictionary)))
-
-  ;; if called by pressing the button
-  (unless word
-    (setq word (read-string "Search word: " nil 'dictionary-word-history)))
-  ;; just in case non-interactively called
+   (let ((dict
+          (if current-prefix-arg
+              (funcall dictionary-read-dictionary-function)
+	    dictionary-default-dictionary)))
+     (list (funcall dictionary-read-word-function dict) dict)))
   (unless dictionary
     (setq dictionary dictionary-default-dictionary))
-  (dictionary-new-search (cons word dictionary)))
+  (if dictionary-display-definition-function
+      (if-let ((definition (dictionary-define-word word dictionary)))
+          (funcall dictionary-display-definition-function word dictionary definition)
+        (user-error "No definition found for \"%s\"" word))
+    ;; if called by pressing the button
+    (unless word
+      (setq word (read-string "Search word: " nil 'dictionary-word-history)))
+    ;; just in case non-interactively called
+    (dictionary-new-search (cons word dictionary))))
 
 ;;;###autoload
 (defun dictionary-lookup-definition ()
@@ -1386,5 +1461,100 @@ dictionary-context-menu
       'dictionary-separator))
   menu)
 
+(defun dictionary-define-word (word dictionary)
+  "Return the definition of WORD in DICTIONARY, or nil if not found."
+  (dictionary-send-command
+   (format "define %s \"%s\"" dictionary word))
+  (when (and (= (read (dictionary-read-reply)) 150)
+             (= (read (dictionary-read-reply)) 151))
+    (dictionary-read-answer)))
+
+(defun dictionary-match-word (word)
+  "Return dictionary matches for WORD as a list of strings."
+  (unless (string-empty-p word)
+    (if (string= (car dictionary--last-match) word)
+        (cdr dictionary--last-match)
+      (dictionary-send-command
+       (format "match %s %s \"%s\""
+               dictionary-default-dictionary
+               dictionary-default-strategy
+               word))
+      (when (and (= (read (dictionary-read-reply)) 152))
+        (with-temp-buffer
+          (insert (dictionary-read-answer))
+          (goto-char (point-min))
+          (let ((result nil))
+            (while (not (eobp))
+              (search-forward " " nil t)
+              (push (read (current-buffer)) result)
+              (search-forward "\n" nil t))
+            (setq result (reverse result))
+            (setq dictionary--last-match (cons word result))
+            result))))))
+
+(defun dictionary-completing-read-word (dictionary)
+  "Prompt for a word with completion based on matches in DICTIONARY."
+  (let* ((completion-ignore-case t)
+         (dictionary-default-dictionary dictionary)
+         (word-at-point (thing-at-point 'word t))
+         (default (dictionary-match-word word-at-point)))
+    (completing-read (format-prompt dictionary-read-word-prompt default)
+                     (completion-table-dynamic #'dictionary-match-word)
+                     nil t nil 'dictionary-word-history default t)))
+
+(defun dictionary-dictionaries ()
+  "Return the list of dictionaries the server supports."
+  (dictionary-send-command "show db")
+  (when (and (= (read (dictionary-read-reply)) 110))
+    (with-temp-buffer
+      (insert (dictionary-read-answer))
+      (goto-char (point-min))
+      (let ((result '(("!" . "First matching dictionary")
+                      ("*" . "All dictionaries"))))
+        (while (not (eobp))
+          (push (cons (buffer-substring
+                       (search-forward "\n" nil t)
+                       (1- (search-forward " " nil t)))
+                      (read (current-buffer)))
+                result))
+        (reverse result)))))
+
+(defun dictionary-completing-read-dictionary ()
+  "Prompt for a dictionary the server supports."
+  (let* ((dicts (dictionary-dictionaries))
+         (len (apply #'max (mapcar #'length (mapcar #'car dicts))))
+         (completion-extra-properties
+          (list :annotation-function
+                (lambda (key)
+                  (concat (make-string (1+ (- len (length key))) ?\s)
+                          (alist-get key dicts nil nil #'string=))))))
+    (completing-read (format-prompt "Select dictionary"
+                                    dictionary-default-dictionary)
+                     dicts nil t nil nil dictionary-default-dictionary)))
+
+(define-button-type 'help-word
+  :supertype 'help-xref
+  'help-function 'dictionary-search
+  'help-echo "mouse-2, RET: describe this word")
+
+(defun dictionary-display-definition-in-help-buffer (word dictionary definition)
+  "Display DEFINITION, the definition of WORD in DICTIONARY."
+  (let ((help-buffer-under-preparation t))
+    (help-setup-xref (list #'dictionary-search word dictionary)
+                     (called-interactively-p 'interactive))
+    (with-help-window (help-buffer)
+      (with-current-buffer (help-buffer)
+        (insert definition)
+        ;; Buttonize references to other definitions.  These appear as
+        ;; words enclosed with curly braces.
+        (goto-char (point-min))
+        (while (re-search-forward (rx "{"
+                                      (group-n 1 (* (not (any ?}))))
+                                      "}")
+                                  nil t)
+          (help-xref-button 1 'help-word
+                            (match-string 1)
+                            dictionary))))))
+
 (provide 'dictionary)
 ;;; dictionary.el ends here
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-20 18:27                                 ` Eshel Yaron
@ 2023-05-20 19:11                                   ` Philip Kaludercic
  2023-05-21  6:52                                     ` Eshel Yaron
  0 siblings, 1 reply; 42+ messages in thread
From: Philip Kaludercic @ 2023-05-20 19:11 UTC (permalink / raw)
  To: Eshel Yaron; +Cc: Eli Zaretskii, emacs-devel

Eshel Yaron <me@eshelyaron.com> writes:

>>> +(defcustom dictionary-display-definition-function nil
>>> +  "Function to use for displaying dictionary definitions.
>>> +It is called with three string arguments: the word being defined,
>>> +the dictionary name, and the full definition."
>>> +  :type '(choice (const :tag "Dictionary buffer" nil)
>>> +                 (const :tag "Help buffer"
>>> +                        dictionary-display-definition-in-help-buffer)
>>> +                 (function :tag "Custom function"))
>>> +  :version "30.1")
>>
>> What is the reason for having this option fallback to nil?  I couldn't
>> make that out from the patch.  If all the other options offer a
>> concrete-default function (that you could also call in your own
>> function), then it seems inconsistent to not provide this here as well.
>
> The reason is that, unlike the other options, the default path that
> `dictionary-search` takes to displaying a definition is highly coupled
> with how it obtains the definition, making it difficult to extract into
> a standalone function.  That's a refactor I prefer to avoid at this
> point.  So, if you set `dictionary-display-definition-function` to a
> custom function, we use the new function `dictionary-define-word` to
> cleanly obtain the definition and let your custom function display it.
> If you use the default (nil) value, we let `dictionary-search` call the
> "old" function `dictionary-new-search` that both obtains and displays
> the definition.

OK, I am not familiar with the code and I get that it could take too
much effort to refactor this properly right now.

>>> +(defun dictionary-define-word (word dictionary)
>>> +  "Return the definition of WORD in DICTIONARY, or nil if not found."
>>> +  (dictionary-send-command
>>> +   (format "define %s \"%s\"" dictionary word))
>>> +  (when (and (= (read (dictionary-read-reply)) 150)
>>> +             (= (read (dictionary-read-reply)) 151))
>>
>> I think a memq would be nice here.
>>
>
> No, `memq` would be appropriate if we wanted to check that the
> expression `(read (dictionary-read-reply))` evaluates to either 150 or
> to 151, but here we want to check that it evaluates 150 and then
> afterwards that it evaluates to 151.

Whoops, misread that as and `or' and forgot about side-effects.

>>> +(defun dictionary-display-definition-in-help-buffer (word dictionary definition)
>>> +  "Display DEFINITION, the definition of WORD in DICTIONARY."
>>> +  (let ((help-buffer-under-preparation t))
>>> +    (help-setup-xref (list #'dictionary-search word dictionary)
>>> +                     (called-interactively-p 'interactive))
>>> +    (with-help-window (help-buffer)
>>> +      (with-current-buffer (help-buffer)
>>> +        (insert definition)
>>> +        (goto-char (point-min))
>>> +        (while (re-search-forward (rx "{"
>>> +                                      (group-n 1 (* (not (any ?}))))
>>> +                                      "}")
>>> +                                  nil t)
>>
>> Perhaps you could explain what is going on here.  Why is this pattern
>> significant?
>
> We want to buttonize references to other definitions in the *Help*
> buffer, which appear enclosed in curly braces.  I've added a comment
> explaining this.

So the protocol always wraps other definitions in curly braces?



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-20 19:11                                   ` Philip Kaludercic
@ 2023-05-21  6:52                                     ` Eshel Yaron
  2023-05-25  9:52                                       ` Eshel Yaron
  0 siblings, 1 reply; 42+ messages in thread
From: Eshel Yaron @ 2023-05-21  6:52 UTC (permalink / raw)
  To: Philip Kaludercic; +Cc: Eli Zaretskii, emacs-devel

Philip Kaludercic <philipk@posteo.net> writes:

> Eshel Yaron <me@eshelyaron.com> writes:
>
>> We want to buttonize references to other definitions in the *Help*
>> buffer, which appear enclosed in curly braces.  I've added a comment
>> explaining this.
>
> So the protocol always wraps other definitions in curly braces?

AFAICT, yes, references to other definitions are enclosed in curly
braces.

-- 
Best,

Eshel



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-21  6:52                                     ` Eshel Yaron
@ 2023-05-25  9:52                                       ` Eshel Yaron
  2023-05-25 19:10                                         ` Philip Kaludercic
                                                           ` (2 more replies)
  0 siblings, 3 replies; 42+ messages in thread
From: Eshel Yaron @ 2023-05-25  9:52 UTC (permalink / raw)
  To: emacs-devel; +Cc: Philip Kaludercic, Eli Zaretskii

[-- Attachment #1: Type: text/plain, Size: 618 bytes --]

Hi,

I'm attaching a slightly updated patch to dictionary.el.  The only
change wrt to my previous patch is that `dictionary-match-word` now uses
the new `external-completion-table` from Emacs 29 instead of
`completion-table-dynamic` to allow leveraging arbitrary matching
strategies that the dictionary server provides.

For example, we can now set `dictionary-default-strategy` to the
"soundex" matching strategy that dict.org provides to get completion
candidates that sound similar to the minibuffer input (such as "tail",
"tale" and "tell").

I've also rebased onto master branch to avoid conflicts in etc/NEWS.



[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: v4-0001-Add-customization-options-for-dictionary-search.patch --]
[-- Type: text/x-patch, Size: 14118 bytes --]

From 749743aa703a98352cb12ad84c04c971b22ea44c Mon Sep 17 00:00:00 2001
From: Eshel Yaron <me@eshelyaron.com>
Date: Mon, 15 May 2023 21:04:21 +0300
Subject: [PATCH v4] Add customization options for dictionary-search

Allow users to customize 'dictionary-search' via several new
customization options.

* lisp/net/dictionary.el (dictionary-define-word)
(dictionary-match-word, dictionary-completing-read-word)
(dictionary-dictionaries, dictionary-completing-read-dictionary)
(dictionary-display-definition-in-help-buffer): New functions.
(dictionary-read-word-prompt)
(dictionary-display-definition-function)
(dictionary-read-word-function)
(dictionary-read-dictionary-function)
(dictionary-search-interface): New user options.
(dictionary-search): Use them.
(dictionary-read-dictionary-default)
(dictionary-read-word-default): New functions, extracted from
'dictionary-search'.
* etc/NEWS: Announce.
---
 etc/NEWS               |  45 +++++++++
 lisp/net/dictionary.el | 203 ++++++++++++++++++++++++++++++++++++++---
 2 files changed, 233 insertions(+), 15 deletions(-)

diff --git a/etc/NEWS b/etc/NEWS
index 7729dbc79fa..07fc2fab774 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -342,6 +342,51 @@ The new Rmail commands 'rmail-mailing-list-post',
 'rmail-mailing-list-archive allow to, respectively, post to,
 unsubscribe from, request help about, and browse the archives, of the
 mailing list from which the current email message was delivered.
+
+** Dictionary
+
+---
+*** New user option 'dictionary-search-interface'.
+Controls how the 'dictionary-search' command prompts for and displays
+dictionary definitions.  Customize this user option to 'help' to have
+'dictionary-search' display definitions in a *Help* buffer and provide
+dictionary-based minibuffer completion for word selection.
+
+---
+*** New user option 'dictionary-read-word-prompt'.
+This allows the user to customize the prompt that is used by
+'dictionary-search' when asking for a word to search in the
+dictionary.
+
+---
+*** New user option 'dictionary-display-definition-function'.
+This allows the user to customize the way in which 'dictionary-search'
+displays word definitions.  If non-nil, this user option should be set
+to a function that displays a word definition obtained from a
+dictionary server.  The new function
+'dictionary-display-definition-in-help-buffer' can be used to display
+the definition in a *Help* buffer, instead of the default *Dictionary*
+buffer.
+
+---
+*** New user option 'dictionary-read-word-function'.
+This allows the user to customize the way in which 'dictionary-search'
+prompts for a word to search in the dictionary.  This user option
+should be set to a function that lets the user select a word and
+returns it as a string.  The new function
+'dictionary-completing-read-word' can be used to prompt with
+completion based on dictionary matches.
+
+---
+*** New user option 'dictionary-read-dictionary-function'.
+This allows the user to customize the way in which 'dictionary-search'
+prompts for a dictionary to search in.  This user option should be set
+to a function that lets the user select a dictionary and returns its
+name as a string.  The new function
+'dictionary-completing-read-dictionary' can be used to prompt with
+completion based on dictionaries that the server supports.
+
+
 \f
 * New Modes and Packages in Emacs 30.1
 
diff --git a/lisp/net/dictionary.el b/lisp/net/dictionary.el
index ba65225692a..8d81b3ec9d8 100644
--- a/lisp/net/dictionary.el
+++ b/lisp/net/dictionary.el
@@ -38,6 +38,8 @@
 (require 'custom)
 (require 'dictionary-connection)
 (require 'button)
+(require 'help-mode)
+(require 'external-completion)
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Stuff for customizing.
@@ -247,6 +249,65 @@ dictionary-coding-systems-for-dictionaries
                                )))
   :version "28.1")
 
+(defcustom dictionary-read-word-prompt "Search word"
+  "Prompt string to use when prompting for a word."
+  :type 'string
+  :version "30.1")
+
+(defcustom dictionary-display-definition-function nil
+  "Function to use for displaying dictionary definitions.
+It is called with three string arguments: the word being defined,
+the dictionary name, and the full definition."
+  :type '(choice (const :tag "Dictionary buffer" nil)
+                 (const :tag "Help buffer"
+                        dictionary-display-definition-in-help-buffer)
+                 (function :tag "Custom function"))
+  :version "30.1")
+
+(defcustom dictionary-read-word-function #'dictionary-read-word-default
+  "Function to use for prompting for a word.
+It is called with one string argument, the name of the dictionary to use, and
+must return a string."
+  :type '(choice (const :tag "Default" dictionary-read-word-default)
+                 (const :tag "Dictionary-based completion"
+                        dictionary-completing-read-word)
+                 (function :tag "Custom function"))
+  :version "30.1")
+
+(defcustom dictionary-read-dictionary-function
+  #'dictionary-read-dictionary-default
+  "Function to use for prompting for a dictionary.
+It is called with no arguments and must return a string."
+  :type '(choice (const :tag "Default" dictionary-read-dictionary-default)
+                 (const :tag "Choose among server-provided dictionaries"
+                        dictionary-completing-read-dictionary)
+                 (function :tag "Custom function"))
+  :version "30.1")
+
+(defcustom dictionary-search-interface nil
+  "Controls how `dictionary-search' prompts for words and displays definitions.
+
+When set to `help', `dictionary-search' displays definitions in a *Help* buffer,
+and provides completion for word selection based on dictionary matches.
+
+Otherwise, `dictionary-search' displays definitions in a *Dictionary* buffer."
+  :type '(choice (const :tag "Dictionary buffer" nil)
+                 (const :tag "Help buffer" help))
+  :set (lambda (symbol value)
+         (let ((vals (pcase value
+                       ('help '(dictionary-display-definition-in-help-buffer
+                                dictionary-completing-read-word
+                                dictionary-completing-read-dictionary))
+                       (_     '(nil
+                                dictionary-read-word-default
+                                dictionary-read-dictionary-default)))))
+           (seq-setq (dictionary-display-definition-function
+                      dictionary-read-word-function
+                      dictionary-read-dictionary-function)
+                     vals))
+         (set-default-toplevel-value symbol value))
+  :version "30.1")
+
 (defface dictionary-word-definition-face
 '((((supports (:family "DejaVu Serif")))
    (:family "DejaVu Serif"))
@@ -366,6 +427,8 @@ dictionary-word-history
   '()
   "History list of searched word.")
 
+(defvar dictionary--last-match nil)
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Basic function providing startup actions
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -1139,6 +1202,20 @@ dictionary-search-default
    ((car (get-char-property (point) 'data)))
    (t (current-word t))))
 
+(defun dictionary-read-dictionary-default ()
+  "Prompt for a dictionary name."
+  (read-string (if dictionary-default-dictionary
+		   (format "Dictionary (%s): "
+                           dictionary-default-dictionary)
+		 "Dictionary: ")
+	       nil nil dictionary-default-dictionary))
+
+(defun dictionary-read-word-default (_dictionary)
+  "Prompt for a word to search in the dictionary."
+  (let ((default (dictionary-search-default)))
+    (read-string (format-prompt dictionary-read-word-prompt default)
+                 nil 'dictionary-word-history default)))
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; User callable commands
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -1149,23 +1226,22 @@ dictionary-search
 It presents the selection or word at point as default input and
 allows editing it."
   (interactive
-   (list (let ((default (dictionary-search-default)))
-           (read-string (format-prompt "Search word" default)
-                        nil 'dictionary-word-history default))
-	 (if current-prefix-arg
-	     (read-string (if dictionary-default-dictionary
-			      (format "Dictionary (%s): " dictionary-default-dictionary)
-			    "Dictionary: ")
-			  nil nil dictionary-default-dictionary)
-	   dictionary-default-dictionary)))
-
-  ;; if called by pressing the button
-  (unless word
-    (setq word (read-string "Search word: " nil 'dictionary-word-history)))
-  ;; just in case non-interactively called
+   (let ((dict
+          (if current-prefix-arg
+              (funcall dictionary-read-dictionary-function)
+	    dictionary-default-dictionary)))
+     (list (funcall dictionary-read-word-function dict) dict)))
   (unless dictionary
     (setq dictionary dictionary-default-dictionary))
-  (dictionary-new-search (cons word dictionary)))
+  (if dictionary-display-definition-function
+      (if-let ((definition (dictionary-define-word word dictionary)))
+          (funcall dictionary-display-definition-function word dictionary definition)
+        (user-error "No definition found for \"%s\"" word))
+    ;; if called by pressing the button
+    (unless word
+      (setq word (read-string "Search word: " nil 'dictionary-word-history)))
+    ;; just in case non-interactively called
+    (dictionary-new-search (cons word dictionary))))
 
 ;;;###autoload
 (defun dictionary-lookup-definition ()
@@ -1386,5 +1462,102 @@ dictionary-context-menu
       'dictionary-separator))
   menu)
 
+(defun dictionary-define-word (word dictionary)
+  "Return the definition of WORD in DICTIONARY, or nil if not found."
+  (dictionary-send-command
+   (format "define %s \"%s\"" dictionary word))
+  (when (and (= (read (dictionary-read-reply)) 150)
+             (= (read (dictionary-read-reply)) 151))
+    (dictionary-read-answer)))
+
+(defun dictionary-match-word (word &rest _)
+  "Return dictionary matches for WORD as a list of strings.
+Further arguments are currently ignored."
+  (unless (string-empty-p word)
+    (if (string= (car dictionary--last-match) word)
+        (cdr dictionary--last-match)
+      (dictionary-send-command
+       (format "match %s %s \"%s\""
+               dictionary-default-dictionary
+               dictionary-default-strategy
+               word))
+      (when (and (= (read (dictionary-read-reply)) 152))
+        (with-temp-buffer
+          (insert (dictionary-read-answer))
+          (goto-char (point-min))
+          (let ((result nil))
+            (while (not (eobp))
+              (search-forward " " nil t)
+              (push (read (current-buffer)) result)
+              (search-forward "\n" nil t))
+            (setq result (reverse result))
+            (setq dictionary--last-match (cons word result))
+            result))))))
+
+(defun dictionary-completing-read-word (dictionary)
+  "Prompt for a word with completion based on matches in DICTIONARY."
+  (let* ((completion-ignore-case t)
+         (dictionary-default-dictionary dictionary)
+         (word-at-point (thing-at-point 'word t))
+         (default (dictionary-match-word word-at-point)))
+    (completing-read (format-prompt dictionary-read-word-prompt default)
+                     (external-completion-table 'dictionary-definition
+                                                #'dictionary-match-word)
+                     nil t nil 'dictionary-word-history default t)))
+
+(defun dictionary-dictionaries ()
+  "Return the list of dictionaries the server supports."
+  (dictionary-send-command "show db")
+  (when (and (= (read (dictionary-read-reply)) 110))
+    (with-temp-buffer
+      (insert (dictionary-read-answer))
+      (goto-char (point-min))
+      (let ((result '(("!" . "First matching dictionary")
+                      ("*" . "All dictionaries"))))
+        (while (not (eobp))
+          (push (cons (buffer-substring
+                       (search-forward "\n" nil t)
+                       (1- (search-forward " " nil t)))
+                      (read (current-buffer)))
+                result))
+        (reverse result)))))
+
+(defun dictionary-completing-read-dictionary ()
+  "Prompt for a dictionary the server supports."
+  (let* ((dicts (dictionary-dictionaries))
+         (len (apply #'max (mapcar #'length (mapcar #'car dicts))))
+         (completion-extra-properties
+          (list :annotation-function
+                (lambda (key)
+                  (concat (make-string (1+ (- len (length key))) ?\s)
+                          (alist-get key dicts nil nil #'string=))))))
+    (completing-read (format-prompt "Select dictionary"
+                                    dictionary-default-dictionary)
+                     dicts nil t nil nil dictionary-default-dictionary)))
+
+(define-button-type 'help-word
+  :supertype 'help-xref
+  'help-function 'dictionary-search
+  'help-echo "mouse-2, RET: describe this word")
+
+(defun dictionary-display-definition-in-help-buffer (word dictionary definition)
+  "Display DEFINITION, the definition of WORD in DICTIONARY."
+  (let ((help-buffer-under-preparation t))
+    (help-setup-xref (list #'dictionary-search word dictionary)
+                     (called-interactively-p 'interactive))
+    (with-help-window (help-buffer)
+      (with-current-buffer (help-buffer)
+        (insert definition)
+        ;; Buttonize references to other definitions.  These appear as
+        ;; words enclosed with curly braces.
+        (goto-char (point-min))
+        (while (re-search-forward (rx "{"
+                                      (group-n 1 (* (not (any ?}))))
+                                      "}")
+                                  nil t)
+          (help-xref-button 1 'help-word
+                            (match-string 1)
+                            dictionary))))))
+
 (provide 'dictionary)
 ;;; dictionary.el ends here
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-25  9:52                                       ` Eshel Yaron
@ 2023-05-25 19:10                                         ` Philip Kaludercic
  2023-05-26  9:16                                         ` Eli Zaretskii
  2023-05-26 11:36                                         ` Rudolf Adamkovič
  2 siblings, 0 replies; 42+ messages in thread
From: Philip Kaludercic @ 2023-05-25 19:10 UTC (permalink / raw)
  To: Eshel Yaron; +Cc: emacs-devel, Eli Zaretskii

Eshel Yaron <me@eshelyaron.com> writes:

> Hi,
>
> I'm attaching a slightly updated patch to dictionary.el.  The only
> change wrt to my previous patch is that `dictionary-match-word` now uses
> the new `external-completion-table` from Emacs 29 instead of
> `completion-table-dynamic` to allow leveraging arbitrary matching
> strategies that the dictionary server provides.
>
> For example, we can now set `dictionary-default-strategy` to the
> "soundex" matching strategy that dict.org provides to get completion
> candidates that sound similar to the minibuffer input (such as "tail",
> "tale" and "tell").
>
> I've also rebased onto master branch to avoid conflicts in etc/NEWS.
>
>
> From 749743aa703a98352cb12ad84c04c971b22ea44c Mon Sep 17 00:00:00 2001
> From: Eshel Yaron <me@eshelyaron.com>
> Date: Mon, 15 May 2023 21:04:21 +0300
> Subject: [PATCH v4] Add customization options for dictionary-search
>
> Allow users to customize 'dictionary-search' via several new
> customization options.

LGTM.



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-25  9:52                                       ` Eshel Yaron
  2023-05-25 19:10                                         ` Philip Kaludercic
@ 2023-05-26  9:16                                         ` Eli Zaretskii
  2023-05-26 11:36                                         ` Rudolf Adamkovič
  2 siblings, 0 replies; 42+ messages in thread
From: Eli Zaretskii @ 2023-05-26  9:16 UTC (permalink / raw)
  To: Eshel Yaron; +Cc: emacs-devel, philipk

> From: Eshel Yaron <me@eshelyaron.com>
> Cc: Philip Kaludercic <philipk@posteo.net>, Eli Zaretskii <eliz@gnu.org>
> Date: Thu, 25 May 2023 12:52:55 +0300
> 
> I'm attaching a slightly updated patch to dictionary.el.  The only
> change wrt to my previous patch is that `dictionary-match-word` now uses
> the new `external-completion-table` from Emacs 29 instead of
> `completion-table-dynamic` to allow leveraging arbitrary matching
> strategies that the dictionary server provides.
> 
> For example, we can now set `dictionary-default-strategy` to the
> "soundex" matching strategy that dict.org provides to get completion
> candidates that sound similar to the minibuffer input (such as "tail",
> "tale" and "tell").
> 
> I've also rebased onto master branch to avoid conflicts in etc/NEWS.

Thanks, installed on the master branch.



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-25  9:52                                       ` Eshel Yaron
  2023-05-25 19:10                                         ` Philip Kaludercic
  2023-05-26  9:16                                         ` Eli Zaretskii
@ 2023-05-26 11:36                                         ` Rudolf Adamkovič
  2023-05-26 12:26                                           ` Eshel Yaron
  2 siblings, 1 reply; 42+ messages in thread
From: Rudolf Adamkovič @ 2023-05-26 11:36 UTC (permalink / raw)
  To: Eshel Yaron, emacs-devel; +Cc: Philip Kaludercic, Eli Zaretskii

Eshel Yaron <me@eshelyaron.com> writes:

> I'm attaching a slightly updated patch to dictionary.el.

Thank you for working on this feature.

QUESTION 1.

Is it expected that 'dictionary-lookup-definition' still uses the old
interface, even thought I set

(with-eval-after-load 'dictionary
  (setopt dictionary-search-interface 'help))

QUESTION 2.

With

(with-eval-after-load 'dictionary
  (setopt dictionary-server "dict.org"))

when I have

dictionary<POINT>

and type 'M-x dictionary-search RET', I get

Search word (default Ditionary): <POINT>

Notice the default word "Ditionary" [sic].

Further, when I continue by manually typing 'dictionary M-RET' (in
Vertico), Emacs says "[Match required]" and does nothing.

Rudy
-- 
"Great minds discuss ideas; average minds discuss events; small minds discuss
people."
--- Anna Eleanor Roosevelt (1884-1962)

Rudolf Adamkovič <salutis@me.com> [he/him]
Studenohorská 25
84103 Bratislava
Slovakia



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [ELPA] New package: dict
  2023-05-26 11:36                                         ` Rudolf Adamkovič
@ 2023-05-26 12:26                                           ` Eshel Yaron
  0 siblings, 0 replies; 42+ messages in thread
From: Eshel Yaron @ 2023-05-26 12:26 UTC (permalink / raw)
  To: Rudolf Adamkovič; +Cc: emacs-devel, Philip Kaludercic, Eli Zaretskii

Hi,

Rudolf Adamkovič <salutis@me.com> writes:

> QUESTION 1.
>
> Is it expected that 'dictionary-lookup-definition' still uses the old
> interface, even thought I set
>
> (with-eval-after-load 'dictionary
>   (setopt dictionary-search-interface 'help))

Yes, `dictionary-search-interface` only affects `dictionary-search`.

It shouldn't be too hard to have it also affect
`dictionary-lookup-definition` though, would that be helpful?

Note that now you can also have `dictionary-search` use the word at
point without prompting, as `dictionary-lookup-definition` does, by
setting `dictionary-read-word-function` to something like:

--8<---------------cut here---------------start------------->8---
(lambda (&rest _) (thing-at-point 'word))
--8<---------------cut here---------------end--------------->8---

> QUESTION 2.
>
> With
>
> (with-eval-after-load 'dictionary
>   (setopt dictionary-server "dict.org"))
>
> when I have
>
> dictionary<POINT>
>
> and type 'M-x dictionary-search RET', I get
>
> Search word (default Ditionary): <POINT>
>
> Notice the default word "Ditionary" [sic].
>
> Further, when I continue by manually typing 'dictionary M-RET' (in
> Vertico), Emacs says "[Match required]" and does nothing.

That's interesting, AFAICT this is essentially a problem with the
defaults of the dict.org server: when using its default matching
strategy, the only match it provides for "dictionary" is "ditionary",
and vice versa.  The main problem is that in this case the word we're
matching ("dictionary") is not returned as a match, although it is
defined.

If you set `dictionary-default-strategy` to something other than the
default "." (which means "let the server choose"), maybe something like
"prefix", then this oddity is avoided.

But since this is currently the default setting I wonder what'd be the
best way to address this issue.  We can change the call to
`completing-read` such that it doesn't require a match, so you could
always input a word regardless of the completion candidates.  Another
option would be to change the default for `dictionary-default-strategy`
to something more useful.  Any other ideas?

-- 
Thanks,

Eshel



^ permalink raw reply	[flat|nested] 42+ messages in thread

end of thread, other threads:[~2023-05-26 12:26 UTC | newest]

Thread overview: 42+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-05-11 13:22 [ELPA] New package: dict Eshel Yaron
2023-05-11 13:59 ` Eli Zaretskii
2023-05-11 14:14   ` Philip Kaludercic
2023-05-11 17:56     ` Eshel Yaron
2023-05-11 18:16       ` Eli Zaretskii
2023-05-11 18:29       ` Philip Kaludercic
2023-05-12 13:17         ` Eshel Yaron
2023-05-12 13:44           ` Eli Zaretskii
2023-05-14  6:41             ` Eshel Yaron
2023-05-14  9:14               ` Eli Zaretskii
2023-05-15 18:50                 ` Eshel Yaron
2023-05-18  7:57                   ` Eshel Yaron
2023-05-18  8:32                     ` Eli Zaretskii
2023-05-18 10:59                   ` Eli Zaretskii
2023-05-18 12:21                     ` Eshel Yaron
2023-05-18 14:09                       ` Eli Zaretskii
2023-05-18 15:51                         ` Eshel Yaron
2023-05-18 15:58                           ` Eli Zaretskii
2023-05-19  8:34                             ` Eshel Yaron
2023-05-20 14:19                               ` Eli Zaretskii
2023-05-20 16:49                               ` Philip Kaludercic
2023-05-20 18:27                                 ` Eshel Yaron
2023-05-20 19:11                                   ` Philip Kaludercic
2023-05-21  6:52                                     ` Eshel Yaron
2023-05-25  9:52                                       ` Eshel Yaron
2023-05-25 19:10                                         ` Philip Kaludercic
2023-05-26  9:16                                         ` Eli Zaretskii
2023-05-26 11:36                                         ` Rudolf Adamkovič
2023-05-26 12:26                                           ` Eshel Yaron
2023-05-18 12:59                   ` Philip Kaludercic
2023-05-18 15:37                     ` Eshel Yaron
2023-05-18 15:58                       ` Philip Kaludercic
2023-05-14 16:06               ` Stephen Leake
2023-05-15 18:58                 ` Eshel Yaron
2023-05-11 14:18 ` Philip Kaludercic
2023-05-11 18:00   ` Eshel Yaron
2023-05-11 18:31     ` Philip Kaludercic
2023-05-12 13:32       ` Eshel Yaron
2023-05-16 19:38         ` Philip Kaludercic
2023-05-17  2:25           ` Eli Zaretskii
2023-05-13 22:30     ` Richard Stallman
2023-05-14  6:48       ` Eshel Yaron

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).