unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#50459: 28.0.50; Python shell completion is incompatible with flex, orderless, etc.
@ 2021-09-07 17:52 Augusto Stoffel
  2021-09-08 17:44 ` Augusto Stoffel
                   ` (2 more replies)
  0 siblings, 3 replies; 26+ messages in thread
From: Augusto Stoffel @ 2021-09-07 17:52 UTC (permalink / raw)
  To: 50459

If I start a Python shell on Emacs -Q and type, say

```
x = []
x.c<tab>
```

then I see, as expected,

```
Possible completions are:
x.clear
x.copy
x.count
```

Now, if I (setq completion-styles '(flex)), then no completions as
reported in the same situation.  Same thing with the `orderless' or
`substring' completion styles.

Moreover, the same observation holds for native completion on or off.





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

* bug#50459: 28.0.50; Python shell completion is incompatible with flex, orderless, etc.
  2021-09-07 17:52 bug#50459: 28.0.50; Python shell completion is incompatible with flex, orderless, etc Augusto Stoffel
@ 2021-09-08 17:44 ` Augusto Stoffel
  2021-09-09  7:11   ` Michael Albinus
  2021-09-09  7:30 ` Gregory Heytings
  2021-09-10 19:08 ` bug#50459: 28.0.50; [PATCH] " Augusto Stoffel
  2 siblings, 1 reply; 26+ messages in thread
From: Augusto Stoffel @ 2021-09-08 17:44 UTC (permalink / raw)
  To: 50459

On Tue,  7 Sep 2021 at 19:52, Augusto Stoffel <arstoffel@gmail.com> wrote:

> If I start a Python shell on Emacs -Q and type, say
>
> ```
> x = []
> x.c<tab>
> ```
>
> then I see, as expected,
>
> ```
> Possible completions are:
> x.clear
> x.copy
> x.count
> ```
>
> Now, if I (setq completion-styles '(flex)), then no completions as
> reported in the same situation.  Same thing with the `orderless' or
> `substring' completion styles.
>
> Moreover, the same observation holds for native completion on or off.

On closer inspection (and discussion with the orderless people), the
completion-at-point function in pyhton.el conforms to the completion API.

The issue lies in the fancier completion styles, which always send the
empty string as the STRING argument to any completion table.

There's a workaround for this, which I could provide, but this doesn't
seem advisable.





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

* bug#50459: 28.0.50; Python shell completion is incompatible with flex, orderless, etc.
  2021-09-08 17:44 ` Augusto Stoffel
@ 2021-09-09  7:11   ` Michael Albinus
  2021-09-09  7:32     ` Gregory Heytings
  0 siblings, 1 reply; 26+ messages in thread
From: Michael Albinus @ 2021-09-09  7:11 UTC (permalink / raw)
  To: Augusto Stoffel; +Cc: 50459

Augusto Stoffel <arstoffel@gmail.com> writes:

Hi Augusto,

> On closer inspection (and discussion with the orderless people), the
> completion-at-point function in pyhton.el conforms to the completion API.
>
> The issue lies in the fancier completion styles, which always send the
> empty string as the STRING argument to any completion table.

FTR, a similar issue has been discussed recently for remote file names
in bug#50387.

Best regards, Michael.





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

* bug#50459: 28.0.50; Python shell completion is incompatible with flex, orderless, etc.
  2021-09-07 17:52 bug#50459: 28.0.50; Python shell completion is incompatible with flex, orderless, etc Augusto Stoffel
  2021-09-08 17:44 ` Augusto Stoffel
@ 2021-09-09  7:30 ` Gregory Heytings
  2021-09-09  7:40   ` Augusto Stoffel
  2021-09-10 19:08 ` bug#50459: 28.0.50; [PATCH] " Augusto Stoffel
  2 siblings, 1 reply; 26+ messages in thread
From: Gregory Heytings @ 2021-09-09  7:30 UTC (permalink / raw)
  To: Augusto Stoffel; +Cc: 50459


>
> Now, if I (setq completion-styles '(flex)), then no completions as 
> reported in the same situation.  Same thing with the `orderless' or 
> `substring' completion styles.
>

You shouldn't use (setq completion-styles '(flex)), you should use 
(add-to-list 'completion-styles 'flex).  Otherwise the default completion 
styles are not used anymore.





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

* bug#50459: 28.0.50; Python shell completion is incompatible with flex, orderless, etc.
  2021-09-09  7:11   ` Michael Albinus
@ 2021-09-09  7:32     ` Gregory Heytings
  0 siblings, 0 replies; 26+ messages in thread
From: Gregory Heytings @ 2021-09-09  7:32 UTC (permalink / raw)
  To: Michael Albinus; +Cc: Augusto Stoffel, 50459


>> The issue lies in the fancier completion styles, which always send the 
>> empty string as the STRING argument to any completion table.
>
> FTR, a similar issue has been discussed recently for remote file names 
> in bug#50387.
>

Absolutely not.  With (add-to-list 'completion-styles 'substring) or 
(add-to-list 'completion-styles 'flex), completion works as expected in 
Python shells, and not in Tramp.





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

* bug#50459: 28.0.50; Python shell completion is incompatible with flex, orderless, etc.
  2021-09-09  7:30 ` Gregory Heytings
@ 2021-09-09  7:40   ` Augusto Stoffel
  2021-09-09  7:49     ` Gregory Heytings
  0 siblings, 1 reply; 26+ messages in thread
From: Augusto Stoffel @ 2021-09-09  7:40 UTC (permalink / raw)
  To: Gregory Heytings; +Cc: 50459

On Thu,  9 Sep 2021 at 07:30, Gregory Heytings <gregory@heytings.org> wrote:

> You shouldn't use (setq completion-styles '(flex)), you should use
> (add-to-list 'completion-styles 'flex).  Otherwise the default
> completion styles are not used anymore.

This doesn't change the issue described in the subject line.  I would
still not see any flex completions if I did what you suggest.

Granted, completion wouldn't be totally broken.  But I don't mind
letting the brokenness manifest itself.  Therefore I use
(setq completion-styles '(orderless)).





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

* bug#50459: 28.0.50; Python shell completion is incompatible with flex, orderless, etc.
  2021-09-09  7:40   ` Augusto Stoffel
@ 2021-09-09  7:49     ` Gregory Heytings
  2021-09-09  8:45       ` Augusto Stoffel
  0 siblings, 1 reply; 26+ messages in thread
From: Gregory Heytings @ 2021-09-09  7:49 UTC (permalink / raw)
  To: Augusto Stoffel; +Cc: 50459


>> You shouldn't use (setq completion-styles '(flex)), you should use 
>> (add-to-list 'completion-styles 'flex).  Otherwise the default 
>> completion styles are not used anymore.
>
> This doesn't change the issue described in the subject line.  I would 
> still not see any flex completions if I did what you suggest.
>

Because the flex completion mechanism returns no completions, and the next 
completion mechanism is called.  What kind of flex completions would you 
expect to see after x.t TAB in your example?

>
> Granted, completion wouldn't be totally broken.  But I don't mind 
> letting the brokenness manifest itself.  Therefore I use (setq 
> completion-styles '(orderless)).
>

It's not broken, it works as designed.  Instead of asking each user of the 
completion mechanism to implement a specific function for substring / flex 
completion, these mechanisms tell them "please return all possible 
completions, I'll do the filtering job for you".





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

* bug#50459: 28.0.50; Python shell completion is incompatible with flex, orderless, etc.
  2021-09-09  7:49     ` Gregory Heytings
@ 2021-09-09  8:45       ` Augusto Stoffel
  2021-09-09  8:50         ` Gregory Heytings
  0 siblings, 1 reply; 26+ messages in thread
From: Augusto Stoffel @ 2021-09-09  8:45 UTC (permalink / raw)
  To: Gregory Heytings; +Cc: 50459

On Thu,  9 Sep 2021 at 07:49, Gregory Heytings <gregory@heytings.org> wrote:

>>> You shouldn't use (setq completion-styles '(flex)), you should use
>>> (add-to-list 'completion-styles 'flex).  Otherwise the default
>>> completion styles are not used anymore.
>>
>> This doesn't change the issue described in the subject line.  I
>> would still not see any flex completions if I did what you suggest.
>>
>
> Because the flex completion mechanism returns no completions, and the
> next completion mechanism is called.  What kind of flex completions
> would you expect to see after x.t TAB in your example?

For sure 'x.count' should be a candidate, just like in Elisp 'set' shows
up as a possible completion after typing '(t TAB'.

Whether or not your example should allow 'fix.it' as a completion is up
to debate.

>
>>
>> Granted, completion wouldn't be totally broken.  But I don't mind
>> letting the brokenness manifest itself.  Therefore I use (setq
>> completion-styles '(orderless)).
>>
>
> It's not broken, it works as designed.  Instead of asking each user of
> the completion mechanism to implement a specific function for
> substring / flex completion, these mechanisms tell them "please return
> all possible completions, I'll do the filtering job for you".

Right, this is not a problem with the flex style, it's a problem with
the Python completion table.  More specifically, with its notion of "all
completions".





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

* bug#50459: 28.0.50; Python shell completion is incompatible with flex, orderless, etc.
  2021-09-09  8:45       ` Augusto Stoffel
@ 2021-09-09  8:50         ` Gregory Heytings
  2021-09-09 16:46           ` Augusto Stoffel
  0 siblings, 1 reply; 26+ messages in thread
From: Gregory Heytings @ 2021-09-09  8:50 UTC (permalink / raw)
  To: Augusto Stoffel; +Cc: 50459


>> It's not broken, it works as designed.  Instead of asking each user of 
>> the completion mechanism to implement a specific function for substring 
>> / flex completion, these mechanisms tell them "please return all 
>> possible completions, I'll do the filtering job for you".
>
> Right, this is not a problem with the flex style, it's a problem with 
> the Python completion table.  More specifically, with its notion of "all 
> completions".
>

Exactly.





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

* bug#50459: 28.0.50; Python shell completion is incompatible with flex, orderless, etc.
  2021-09-09  8:50         ` Gregory Heytings
@ 2021-09-09 16:46           ` Augusto Stoffel
  2021-09-10 11:37             ` Lars Ingebrigtsen
  2021-09-10 13:32             ` Dmitry Gutov
  0 siblings, 2 replies; 26+ messages in thread
From: Augusto Stoffel @ 2021-09-09 16:46 UTC (permalink / raw)
  To: 50459; +Cc: Gregory Heytings, Michael Albinus

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

After more discussions elsewhere [1], I noticed another problem with
the dynamic completion table from python.el.

Each call to the completion table requires communication with the
inferior process.  If called frequently enough, the comint input
filters can get confused, and some garbage gets printed to the shell.
If the inferior is running over Tramp, the problem gets amplified.

Now, this is not likely to cause much trouble when calling
`completion-at-point' manually, but it is a problem with any of
continuously-updating completion UIs like Company or Corfu.

To alleviate this, the completion-at-point function could implement some
sort of caching.  The difficult question is when to invalidate the
cache.  I've attached one possiblility as a draft patch.  If the
approach seems reasonable, then I'll format it properly.

As a side effect, the patch also solves the original issue described in
this ticket.

Please let me know what you think.

[1] https://github.com/oantolin/orderless/issues/79


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: python-capf.diff --]
[-- Type: text/x-patch, Size: 1471 bytes --]

diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index 4f222b4cf5..3239722981 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -3841,6 +3841,8 @@ python-shell-completion-get-completions
         (split-string completions
                       "^'\\|^\"\\|;\\|'$\\|\"$" t)))))
 
+(defvar-local python-shell--capf-cache nil)
+
 (defun python-shell-completion-at-point (&optional process)
   "Function for `completion-at-point-functions' in `inferior-python-mode'.
 Optional argument PROCESS forces completions to be retrieved
@@ -3895,11 +3897,13 @@ python-shell-completion-at-point
                        #'ignore
                      #'python-shell-completion-get-completions))
                   (t #'python-shell-completion-native-get-completions)))))
-    (list start end
-          (completion-table-dynamic
-           (apply-partially
-            completion-fn
-            process import-statement)))))
+    (let  ((re (or (car python-shell--capf-cache) regexp-unmatchable))
+           (prefix (buffer-substring-no-properties start end)))
+      (unless (string-match re prefix)
+        (setq python-shell--capf-cache
+              (cons (concat "\\`" (regexp-quote prefix) "\\(?:\\sw\\|\\s_\\)*\\'")
+                    (funcall completion-fn process import-statement prefix)))))
+    (list start end (cdr python-shell--capf-cache))))
 
 (define-obsolete-function-alias
   'python-shell-completion-complete-at-point

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

* bug#50459: 28.0.50; Python shell completion is incompatible with flex, orderless, etc.
  2021-09-09 16:46           ` Augusto Stoffel
@ 2021-09-10 11:37             ` Lars Ingebrigtsen
  2021-09-10 11:50               ` Augusto Stoffel
  2021-09-10 13:32             ` Dmitry Gutov
  1 sibling, 1 reply; 26+ messages in thread
From: Lars Ingebrigtsen @ 2021-09-10 11:37 UTC (permalink / raw)
  To: Augusto Stoffel; +Cc: 50459, Gregory Heytings, Michael Albinus

Augusto Stoffel <arstoffel@gmail.com> writes:

> To alleviate this, the completion-at-point function could implement some
> sort of caching.  The difficult question is when to invalidate the
> cache.  I've attached one possiblility as a draft patch.  If the
> approach seems reasonable, then I'll format it properly.

Would it be possible to do caching at a lower level instead of in
python-mode?

> As a side effect, the patch also solves the original issue described in
> this ticket.

[...]

> -    (list start end
> -          (completion-table-dynamic
> -           (apply-partially
> -            completion-fn
> -            process import-statement)))))
> +    (let  ((re (or (car python-shell--capf-cache) regexp-unmatchable))
> +           (prefix (buffer-substring-no-properties start end)))
> +      (unless (string-match re prefix)
> +        (setq python-shell--capf-cache
> +              (cons (concat "\\`" (regexp-quote prefix) "\\(?:\\sw\\|\\s_\\)*\\'")
> +                    (funcall completion-fn process import-statement prefix)))))
> +    (list start end (cdr python-shell--capf-cache))))

I'm not sure I understand this patch -- it's not using
`completion-table-dynamic' at all now?  (But my understanding of the
completion functions in Emacs is pretty lacking.)

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





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

* bug#50459: 28.0.50; Python shell completion is incompatible with flex, orderless, etc.
  2021-09-10 11:37             ` Lars Ingebrigtsen
@ 2021-09-10 11:50               ` Augusto Stoffel
  2021-09-10 13:14                 ` João Távora
  2021-09-11 12:09                 ` Lars Ingebrigtsen
  0 siblings, 2 replies; 26+ messages in thread
From: Augusto Stoffel @ 2021-09-10 11:50 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: 50459, Gregory Heytings, Michael Albinus, joaotavora

On Fri, 10 Sep 2021 at 13:37, Lars Ingebrigtsen <larsi@gnus.org> wrote:

> Augusto Stoffel <arstoffel@gmail.com> writes:
>
>> To alleviate this, the completion-at-point function could implement some
>> sort of caching.  The difficult question is when to invalidate the
>> cache.  I've attached one possiblility as a draft patch.  If the
>> approach seems reasonable, then I'll format it properly.
>
> Would it be possible to do caching at a lower level instead of in
> python-mode?

I'm not an expert in this either, but I think the caching mechanism
would be pretty particular to the circumstances of each completion
table, so it indeed belongs here.  Maybe João can say more?

Since this comint-based completion is not super smart (it's not
context-dependent at all), the rather naive caching invalidation used
here seems sufficient to me.

>
>> As a side effect, the patch also solves the original issue described in
>> this ticket.
>
> [...]
>
>> -    (list start end
>> -          (completion-table-dynamic
>> -           (apply-partially
>> -            completion-fn
>> -            process import-statement)))))
>> +    (let  ((re (or (car python-shell--capf-cache) regexp-unmatchable))
>> +           (prefix (buffer-substring-no-properties start end)))
>> +      (unless (string-match re prefix)
>> +        (setq python-shell--capf-cache
>> + (cons (concat "\\`" (regexp-quote prefix)
>> "\\(?:\\sw\\|\\s_\\)*\\'")
>> + (funcall completion-fn process import-statement prefix)))))
>> +    (list start end (cdr python-shell--capf-cache))))
>
> I'm not sure I understand this patch -- it's not using
> `completion-table-dynamic' at all now?  (But my understanding of the
> completion functions in Emacs is pretty lacking.)

That's true: the logic here is that the completions are computed
eagerly, and then cached until still valid.  So if you type

  fo<tab>o.bar.baz

the inferior process is contacted 3 times: after the <tab>, and after
each dot.  Before, a lazy table was returned, but the inferior would be
contacted after each character anyway (if using Company or similar).





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

* bug#50459: 28.0.50; Python shell completion is incompatible with flex, orderless, etc.
  2021-09-10 11:50               ` Augusto Stoffel
@ 2021-09-10 13:14                 ` João Távora
  2021-09-10 13:28                   ` Dmitry Gutov
  2021-09-11 12:09                 ` Lars Ingebrigtsen
  1 sibling, 1 reply; 26+ messages in thread
From: João Távora @ 2021-09-10 13:14 UTC (permalink / raw)
  To: Augusto Stoffel
  Cc: 50459, Lars Ingebrigtsen, Michael Albinus, Gregory Heytings

Augusto Stoffel <arstoffel@gmail.com> writes:

> On Fri, 10 Sep 2021 at 13:37, Lars Ingebrigtsen <larsi@gnus.org> wrote:
>
>> Augusto Stoffel <arstoffel@gmail.com> writes:
>>
>>> To alleviate this, the completion-at-point function could implement some
>>> sort of caching.  The difficult question is when to invalidate the
>>> cache.  I've attached one possiblility as a draft patch.  If the
>>> approach seems reasonable, then I'll format it properly.
>>
>> Would it be possible to do caching at a lower level instead of in
>> python-mode?
>
> I'm not an expert in this either, but I think the caching mechanism
> would be pretty particular to the circumstances of each completion
> table, so it indeed belongs here.  Maybe João can say more?

I'm sorry, I'm quite overloaded lately and can't read this long thread.
I've been participating in a few discussions about this and all I can
add here are generic comments, like the intepretation that I make from
the docstring of completion-at-point-functions

    Special hook to find the completion table for the entity at point.
    Each function on this hook is called in turn without any argument and
    should return either nil, meaning it is not applicable at point,
    or a function of no arguments to perform completion (discouraged),
    or a list of the form (START END COLLECTION . PROPS), where:
     START and END delimit the entity to complete and should include point,
                           ^^^^^^^^^^^^^^^^^^^^^^     
     COLLECTION is the completion table to use to complete the entity, and
                                                  ^^^^^^^^^^^^^^^^^^^
     PROPS is a property list for additional information.

As I've underlined, it's _that_ entity, not some other entity that the
"backend" aka "capf" should complete.  So:

a) while the entity is "the same" (START and END are the same and POINT
   is somewhere in between) then the backend can do caching inside
   COLLECTION (Eglot does caching between calls to try-completion,
   all-completions, and others, for example).

b) if the entity changes because the buffer has been changed, by any
   means -- including the means of an completion UI -- then the
   completion UI should re-invoke the capf to get a the new entity to
   complete and the new COLLECTION to complete it.  Emacs's default
   completion UIs do this, and so does Company, if I'm not mistaken.  If
   the backend is super smart and can be faster about responding to this
   new capf invocation validly given the previous respose that's fine.
   But my point is this other caching is much more difficult to do
   accurately because of buffer changes and assumptions about the
   filtering strategy.  For example, a cache that assumes that adding a
   character to the end of entity will always produce a subset of
   previously obtained completions will fail if the completion style is
   some kind of "regexp-based" thing, or if that character is '.', for
   example But it might work decently in some situations.

Anyway, another generic point that I've been trying to make is that
filtering/completion-styling should be done as close to the source of
completions as possible.  In Elisp this is easy to do (completions are
basically lists of strings or the big cheap-to-access obarray).  If the
source of the completions is removed from Emacs by some latency, the
experience is never going to be as good as Elisp.

- If you want to fully honour `completion-styles` which is an Elisp
  facility, you need to know most complete set of completions possible at
  all necessary times.  That's going to be slow (but read my final
  paragraph).

- If you're OK with letting the server do the filtering and the
  highlighting, you can make a "backend" style like I did for SLY, for
  example.  It's going to be faster, but `completion-styles` won't be
  honoured.  That's doesn't mean you give up 100% on "flex".  In SLY,
  there is flex implemented on the Common Lisp side, and for Eglot, many
  LSP server do their own flex matching.

In any case, it is generally possible to design responsive backends
systems that let the user interact with Emacs while the "slow requests"
are ongoing, by having these backends cancel themselves when input is
available.  This uses while-no-input and sit-for.  See jsonrpc.el's
jsonrpc-request for an example.  I've been using these kinds of systems
very successfully over the past 4-5 years with SLY, Eglot as backends
and Company UI as a frontend.

Hope this helped,
João





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

* bug#50459: 28.0.50; Python shell completion is incompatible with flex, orderless, etc.
  2021-09-10 13:14                 ` João Távora
@ 2021-09-10 13:28                   ` Dmitry Gutov
  2021-09-10 14:06                     ` João Távora
  0 siblings, 1 reply; 26+ messages in thread
From: Dmitry Gutov @ 2021-09-10 13:28 UTC (permalink / raw)
  To: João Távora, Augusto Stoffel
  Cc: 50459, Lars Ingebrigtsen, Michael Albinus, Gregory Heytings

On 10.09.2021 16:14, João Távora wrote:
> - If you're OK with letting the server do the filtering and the
>    highlighting, you can make a "backend" style like I did for SLY, for
>    example.  It's going to be faster, but `completion-styles` won't be
>    honoured.  That's doesn't mean you give up 100% on "flex".  In SLY,
>    there is flex implemented on the Common Lisp side, and for Eglot, many
>    LSP server do their own flex matching.

You can't really do that with python-shell completion. Nor do you need 
do: the basic pcmpl mechanism should work just fine with it, and for 
performance the completion table just needs some smarter caching.





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

* bug#50459: 28.0.50; Python shell completion is incompatible with flex, orderless, etc.
  2021-09-09 16:46           ` Augusto Stoffel
  2021-09-10 11:37             ` Lars Ingebrigtsen
@ 2021-09-10 13:32             ` Dmitry Gutov
  1 sibling, 0 replies; 26+ messages in thread
From: Dmitry Gutov @ 2021-09-10 13:32 UTC (permalink / raw)
  To: Augusto Stoffel, 50459; +Cc: Gregory Heytings, Michael Albinus

On 09.09.2021 19:46, Augusto Stoffel wrote:
> To alleviate this, the completion-at-point function could implement some
> sort of caching.  The difficult question is when to invalidate the
> cache.  I've attached one possiblility as a draft patch.  If the
> approach seems reasonable, then I'll format it properly.

It's much simpler than what we talked about, but given that 
python-shell-completion-at-point doesn't really look past the current 
line, your approach should work fine.

I'm not very familiar with the code, so I cannot approve the exact 
patch, though, sorry.

As a bonus, though, maybe add the position of prompt on the shell-buffer 
to the invalidation key? Like, if a user imports some new lib in there, 
that can bring in new completions.





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

* bug#50459: 28.0.50; Python shell completion is incompatible with flex, orderless, etc.
  2021-09-10 13:28                   ` Dmitry Gutov
@ 2021-09-10 14:06                     ` João Távora
  2021-09-10 14:22                       ` Dmitry Gutov
  0 siblings, 1 reply; 26+ messages in thread
From: João Távora @ 2021-09-10 14:06 UTC (permalink / raw)
  To: Dmitry Gutov
  Cc: Augusto Stoffel, Lars Ingebrigtsen, Michael Albinus, 50459,
	Gregory Heytings

On Fri, Sep 10, 2021 at 2:28 PM Dmitry Gutov <dgutov@yandex.ru> wrote:
>
> On 10.09.2021 16:14, João Távora wrote:
> > - If you're OK with letting the server do the filtering and the
> >    highlighting, you can make a "backend" style like I did for SLY, for
> >    example.  It's going to be faster, but `completion-styles` won't be
> >    honoured.  That's doesn't mean you give up 100% on "flex".  In SLY,
> >    there is flex implemented on the Common Lisp side, and for Eglot, many
> >    LSP server do their own flex matching.
>
> You can't really do that with python-shell completion.

Probably not unless you write some python, no.  I don't see that
as being that dirty.

> Nor do you need
> do: the basic pcmpl mechanism should work just fine with it, and for
> performance the completion table just needs some smarter caching.

Yes, as I said in b), with "sufficiently smart caching" (and infinite
memory space) you can do everything, indeed.  It's one of the
famous "two hard problems" though, so good luck.

João Távora





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

* bug#50459: 28.0.50; Python shell completion is incompatible with flex, orderless, etc.
  2021-09-10 14:06                     ` João Távora
@ 2021-09-10 14:22                       ` Dmitry Gutov
  2021-09-10 14:39                         ` João Távora
  0 siblings, 1 reply; 26+ messages in thread
From: Dmitry Gutov @ 2021-09-10 14:22 UTC (permalink / raw)
  To: João Távora
  Cc: Augusto Stoffel, Lars Ingebrigtsen, Michael Albinus, 50459,
	Gregory Heytings

On 10.09.2021 17:06, João Távora wrote:
> On Fri, Sep 10, 2021 at 2:28 PM Dmitry Gutov <dgutov@yandex.ru> wrote:
>>
>> On 10.09.2021 16:14, João Távora wrote:
>>> - If you're OK with letting the server do the filtering and the
>>>     highlighting, you can make a "backend" style like I did for SLY, for
>>>     example.  It's going to be faster, but `completion-styles` won't be
>>>     honoured.  That's doesn't mean you give up 100% on "flex".  In SLY,
>>>     there is flex implemented on the Common Lisp side, and for Eglot, many
>>>     LSP server do their own flex matching.
>>
>> You can't really do that with python-shell completion.
> 
> Probably not unless you write some python, no.  I don't see that
> as being that dirty.

I didn't say it was dirty, just not very fitting for the current 
approach: when you do completion by piping code for evaluation through 
inferior shell, you generally like that code to be simple. And 
reimplementing every completion style in Python seems like anything but.

>> Nor do you need
>> do: the basic pcmpl mechanism should work just fine with it, and for
>> performance the completion table just needs some smarter caching.
> 
> Yes, as I said in b), with "sufficiently smart caching" (and infinite
> memory space) you can do everything, indeed.  It's one of the
> famous "two hard problems" though, so good luck.

Completion backends do caching anyways, whether it's on the Emacs side, 
or somewhere inside a language server.

Since completion logic is defined on "our" side here (despite being 
written in Python), caching logic can reside here too.





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

* bug#50459: 28.0.50; Python shell completion is incompatible with flex, orderless, etc.
  2021-09-10 14:22                       ` Dmitry Gutov
@ 2021-09-10 14:39                         ` João Távora
  2021-09-10 14:43                           ` Dmitry Gutov
  0 siblings, 1 reply; 26+ messages in thread
From: João Távora @ 2021-09-10 14:39 UTC (permalink / raw)
  To: Dmitry Gutov
  Cc: Augusto Stoffel, Lars Ingebrigtsen, Michael Albinus, 50459,
	Gregory Heytings

On Fri, Sep 10, 2021 at 3:22 PM Dmitry Gutov <dgutov@yandex.ru> wrote:
>
> On 10.09.2021 17:06, João Távora wrote:
> > On Fri, Sep 10, 2021 at 2:28 PM Dmitry Gutov <dgutov@yandex.ru> wrote:
> >>
> >> On 10.09.2021 16:14, João Távora wrote:
> >>> - If you're OK with letting the server do the filtering and the
> >>>     highlighting, you can make a "backend" style like I did for SLY, for
> >>>     example.  It's going to be faster, but `completion-styles` won't be
> >>>     honoured.  That's doesn't mean you give up 100% on "flex".  In SLY,
> >>>     there is flex implemented on the Common Lisp side, and for Eglot, many
> >>>     LSP server do their own flex matching.
> >>
> >> You can't really do that with python-shell completion.
> >
> > Probably not unless you write some python, no.  I don't see that
> > as being that dirty.
>
> I didn't say it was dirty, just not very fitting for the current
> approach: when you do completion by piping code for evaluation through
> inferior shell, you generally like that code to be simple. And
> reimplementing every completion style in Python seems like anything but.

I was just volunteering an opinion on how to solve _most_ of the problem
(hence I wrote "don't give up 100%") Never did I suggest to implement
"every completion style".  SLY implements only two in Common Lisp.
They're pretty sufficient for most users it seems.  Most language servers
seem to implement flex, some only prefix, some may be configurable
I suppose.

> Completion backends do caching anyways, whether it's on the Emacs side,
> or somewhere inside a language server.

There are many types of caching, as I tried to explain.
Inter-capf-invocation caching (if you can understand what I mean)
is possible, but is probably harder to get right than the "intra" version.
I'm really just stating the obvious: the more removed you are from
the source of truth, the harder it becomes to cache. But also, it's
true that are definitely valuable, if implemented correctly or if a
degree of inaccuracy is tolerated. Fast and accurate is hard.

João Távora





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

* bug#50459: 28.0.50; Python shell completion is incompatible with flex, orderless, etc.
  2021-09-10 14:39                         ` João Távora
@ 2021-09-10 14:43                           ` Dmitry Gutov
  2021-09-10 19:27                             ` Augusto Stoffel
  0 siblings, 1 reply; 26+ messages in thread
From: Dmitry Gutov @ 2021-09-10 14:43 UTC (permalink / raw)
  To: João Távora
  Cc: Augusto Stoffel, Lars Ingebrigtsen, Michael Albinus, 50459,
	Gregory Heytings

On 10.09.2021 17:39, João Távora wrote:
>> Completion backends do caching anyways, whether it's on the Emacs side,
>> or somewhere inside a language server.
> There are many types of caching, as I tried to explain.
> Inter-capf-invocation caching (if you can understand what I mean)
> is possible, but is probably harder to get right than the "intra" version.

The proposed patch provides the "intra" version.





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

* bug#50459: 28.0.50; [PATCH] Python shell completion is incompatible with flex, orderless, etc.
  2021-09-07 17:52 bug#50459: 28.0.50; Python shell completion is incompatible with flex, orderless, etc Augusto Stoffel
  2021-09-08 17:44 ` Augusto Stoffel
  2021-09-09  7:30 ` Gregory Heytings
@ 2021-09-10 19:08 ` Augusto Stoffel
  2021-09-11 12:50   ` Lars Ingebrigtsen
  2 siblings, 1 reply; 26+ messages in thread
From: Augusto Stoffel @ 2021-09-10 19:08 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: 50459, Gregory Heytings, Michael Albinus

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

Okay, I've attached a patch which seems to work fine.

On Fri, 10 Sep 2021 at 16:32, Dmitry Gutov <dgutov@yandex.ru> wrote:

> On 09.09.2021 19:46, Augusto Stoffel wrote:
>> To alleviate this, the completion-at-point function could implement some
>> sort of caching.  The difficult question is when to invalidate the
>> cache.  I've attached one possiblility as a draft patch.  If the
>> approach seems reasonable, then I'll format it properly.
>
> It's much simpler than what we talked about, but given that
> python-shell-completion-at-point doesn't really look past the current
> line, your approach should work fine.

Yes, and you're right --- I've did it that way because this
comint-based completion basically only works for globals anyway.

>
> I'm not very familiar with the code, so I cannot approve the exact
> patch, though, sorry.
>
> As a bonus, though, maybe add the position of prompt on the
> shell-buffer to the invalidation key? Like, if a user imports some new
> lib in there, that can bring in new completions.

Good idea.  I've added this to the patch.  It still won't show the new
completions until the user evaluates the import, but this is the best
you can get by querying an interpreter for the completions.

I've also changed a bit the way the "native completion" setup code is
sent, so that it doesn't print a message directly in the shell buffer
(there is still an echo area message).


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Implement-caching-for-python-shell-completion-at-poi.patch --]
[-- Type: text/x-patch, Size: 5953 bytes --]

From 3f27a63fe5be884464a6a68407e0b6990186c4a6 Mon Sep 17 00:00:00 2001
From: Augusto Stoffel <arstoffel@gmail.com>
Date: Fri, 10 Sep 2021 20:44:10 +0200
Subject: [PATCH] Implement caching for 'python-shell-completion-at-point'

* lisp/progmodes/python.el (python-shell-completion-at-point): cache
results, since computing them involves talking with the inferior
process and, potentially, network communications
(python-shell--capf-cache): new variable, for cache
(python-shell-completion-get-completions,
python-shell-completion-native-get-completions): 'import' argument is
not needed anymore.
(python-shell-completion-native-setup,
python-shell-completion-native-try): pass the setup code
synchronously, to avoid printing a message in the shell.
---
 lisp/progmodes/python.el | 59 ++++++++++++++++++++--------------------
 1 file changed, 30 insertions(+), 29 deletions(-)

diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index 2eef52de0c..e71a8102df 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -3577,13 +3577,12 @@ python-shell-completion-native-try
          python-shell-completion-native-try-output-timeout))
     (python-shell-completion-native-get-completions
      (get-buffer-process (current-buffer))
-     nil "_")))
+     "_")))
 
 (defun python-shell-completion-native-setup ()
   "Try to setup native completion, return non-nil on success."
-  (let ((process (python-shell-get-process)))
-    (with-current-buffer (process-buffer process)
-      (python-shell-send-string "
+  (let* ((process (python-shell-get-process))
+         (output (python-shell-send-string-no-output "
 def __PYTHON_EL_native_completion_setup():
     try:
         import readline
@@ -3693,14 +3692,10 @@ python-shell-completion-native-setup
         print ('python.el: native completion setup failed, %s: %s'
                % sys.exc_info()[:2])
 
-__PYTHON_EL_native_completion_setup()" process)
-      (when (and
-             (python-shell-accept-process-output
-              process python-shell-completion-native-try-output-timeout)
-             (save-excursion
-               (re-search-backward
-                (regexp-quote "python.el: native completion setup loaded") nil t 1)))
-        (python-shell-completion-native-try)))))
+__PYTHON_EL_native_completion_setup()" process)))
+    (when (string-match-p "python\\.el: native completion setup loaded"
+                          output)
+      (python-shell-completion-native-try))))
 
 (defun python-shell-completion-native-turn-off (&optional msg)
   "Turn off shell native completions.
@@ -3760,13 +3755,10 @@ python-shell-completion-native-toggle
       (python-shell-completion-native-turn-on msg))
     python-shell-completion-native-enable))
 
-(defun python-shell-completion-native-get-completions (process import input)
-  "Get completions using native readline for PROCESS.
-When IMPORT is non-nil takes precedence over INPUT for
-completion."
+(defun python-shell-completion-native-get-completions (process input)
+  "Get completions of INPUT using native readline for PROCESS."
   (with-current-buffer (process-buffer process)
-    (let* ((input (or import input))
-           (original-filter-fn (process-filter process))
+    (let* ((original-filter-fn (process-filter process))
            (redirect-buffer (get-buffer-create
                              python-shell-completion-native-redirect-buffer))
            (trigger "\t")
@@ -3818,11 +3810,8 @@ python-shell-completion-native-get-completions
                  :test #'string=))))
         (set-process-filter process original-filter-fn)))))
 
-(defun python-shell-completion-get-completions (process import input)
-  "Do completion at point using PROCESS for IMPORT or INPUT.
-When IMPORT is non-nil takes precedence over INPUT for
-completion."
-  (setq input (or import input))
+(defun python-shell-completion-get-completions (process input)
+  "Get completions of INPUT using PROCESS."
   (with-current-buffer (process-buffer process)
     (let ((completions
            (python-util-strip-string
@@ -3836,6 +3825,9 @@ python-shell-completion-get-completions
         (split-string completions
                       "^'\\|^\"\\|;\\|'$\\|\"$" t)))))
 
+(defvar-local python-shell--capf-cache nil
+  "Variable to store cached completions and invalidation keys.")
+
 (defun python-shell-completion-at-point (&optional process)
   "Function for `completion-at-point-functions' in `inferior-python-mode'.
 Optional argument PROCESS forces completions to be retrieved
@@ -3889,12 +3881,21 @@ python-shell-completion-at-point
                        ;; it during a multiline statement (Bug#28051).
                        #'ignore
                      #'python-shell-completion-get-completions))
-                  (t #'python-shell-completion-native-get-completions)))))
-    (list start end
-          (completion-table-dynamic
-           (apply-partially
-            completion-fn
-            process import-statement)))))
+                  (t #'python-shell-completion-native-get-completions))))
+         (prev-prompt (car python-shell--capf-cache))
+         (re (or (cadr python-shell--capf-cache) regexp-unmatchable))
+         (prefix (buffer-substring-no-properties start end)))
+    ;; To invalidate the cache, we check if the prompt position or the
+    ;; completion prefix changed.
+    (unless (and (equal prev-prompt (car prompt-boundaries))
+                 (string-match re prefix))
+      (setq python-shell--capf-cache
+            `(,(car prompt-boundaries)
+              ,(if (string-empty-p prefix)
+                   regexp-unmatchable
+                 (concat "\\`" (regexp-quote prefix) "\\(?:\\sw\\|\\s_\\)*\\'"))
+              ,@(funcall completion-fn process (or import-statement prefix)))))
+    (list start end (cddr python-shell--capf-cache))))
 
 (define-obsolete-function-alias
   'python-shell-completion-complete-at-point
-- 
2.31.1


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

* bug#50459: 28.0.50; Python shell completion is incompatible with flex, orderless, etc.
  2021-09-10 14:43                           ` Dmitry Gutov
@ 2021-09-10 19:27                             ` Augusto Stoffel
  2021-09-10 20:08                               ` João Távora
  0 siblings, 1 reply; 26+ messages in thread
From: Augusto Stoffel @ 2021-09-10 19:27 UTC (permalink / raw)
  To: Dmitry Gutov
  Cc: Michael Albinus, Lars Ingebrigtsen, 50459, Gregory Heytings,
	João Távora

On Fri, 10 Sep 2021 at 17:43, Dmitry Gutov <dgutov@yandex.ru> wrote:

> On 10.09.2021 17:39, João Távora wrote:
>>> Completion backends do caching anyways, whether it's on the Emacs side,
>>> or somewhere inside a language server.
>> There are many types of caching, as I tried to explain.
>> Inter-capf-invocation caching (if you can understand what I mean)
>> is possible, but is probably harder to get right than the "intra" version.
>
> The proposed patch provides the "intra" version.

I just wanted to emphasize that the approach of evaluating code and
asking an interpreter for completions is obviously a dead end.

I guess it is still the best available at the moment for the REPL, so it
makes sense to ensure it's reasonably correct and doesn't hang your
comint.  But further optimizations are not really worth the effort.

The LSP stuff is much more interesting, and there the caching question
is pretty hairy...





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

* bug#50459: 28.0.50; Python shell completion is incompatible with flex, orderless, etc.
  2021-09-10 19:27                             ` Augusto Stoffel
@ 2021-09-10 20:08                               ` João Távora
  0 siblings, 0 replies; 26+ messages in thread
From: João Távora @ 2021-09-10 20:08 UTC (permalink / raw)
  To: Augusto Stoffel
  Cc: Michael Albinus, Lars Ingebrigtsen, 50459, Gregory Heytings,
	Dmitry Gutov

On Fri, Sep 10, 2021 at 8:27 PM Augusto Stoffel <arstoffel@gmail.com> wrote:
>
> On Fri, 10 Sep 2021 at 17:43, Dmitry Gutov <dgutov@yandex.ru> wrote:
>
> > On 10.09.2021 17:39, João Távora wrote:
> >>> Completion backends do caching anyways, whether it's on the Emacs side,
> >>> or somewhere inside a language server.
> >> There are many types of caching, as I tried to explain.
> >> Inter-capf-invocation caching (if you can understand what I mean)
> >> is possible, but is probably harder to get right than the "intra" version.
> >
> > The proposed patch provides the "intra" version.
>
> I just wanted to emphasize that the approach of evaluating code and
> asking an interpreter for completions is obviously a dead end.

I wouldn't put it that strongly, but for sure not as easy to leverage as a
ready to use LSP server.  That's the promise of LSP, at least.  Also,
in my experience, I've found that completions are just one aspect
of IDEs, and perhaps not even the most important.  "Find definition"
and diagnostics are perhaps more important for me.

So yak-shaving and obsessing over optimizations to this reasonably
hard problem (implementing responsive and fast UIs with arbitrarily
sophisticated filtering styles over data that is some tenths of seconds
away) might not be worth it. OTOH, yak-shaving is what Emacs is
about, in some measure ,and if someone shaves the yak for me, I'll
gladly take a shaved yak.

João





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

* bug#50459: 28.0.50; Python shell completion is incompatible with flex, orderless, etc.
  2021-09-10 11:50               ` Augusto Stoffel
  2021-09-10 13:14                 ` João Távora
@ 2021-09-11 12:09                 ` Lars Ingebrigtsen
  2021-09-11 12:34                   ` Augusto Stoffel
  1 sibling, 1 reply; 26+ messages in thread
From: Lars Ingebrigtsen @ 2021-09-11 12:09 UTC (permalink / raw)
  To: Augusto Stoffel; +Cc: 50459, Gregory Heytings, Michael Albinus, joaotavora

Augusto Stoffel <arstoffel@gmail.com> writes:

> That's true: the logic here is that the completions are computed
> eagerly, and then cached until still valid.  So if you type
>
>   fo<tab>o.bar.baz
>
> the inferior process is contacted 3 times: after the <tab>, and after
> each dot.  Before, a lazy table was returned, but the inferior would be
> contacted after each character anyway (if using Company or similar).

Ah, I see, then that sounds like a definite improvement.  My other
question is then how the cache is flushed...

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





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

* bug#50459: 28.0.50; Python shell completion is incompatible with flex, orderless, etc.
  2021-09-11 12:09                 ` Lars Ingebrigtsen
@ 2021-09-11 12:34                   ` Augusto Stoffel
  2021-09-11 12:36                     ` Lars Ingebrigtsen
  0 siblings, 1 reply; 26+ messages in thread
From: Augusto Stoffel @ 2021-09-11 12:34 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: 50459, Gregory Heytings, Michael Albinus, joaotavora

On Sat, 11 Sep 2021 at 14:09, Lars Ingebrigtsen <larsi@gnus.org> wrote:

> Augusto Stoffel <arstoffel@gmail.com> writes:
>
>> That's true: the logic here is that the completions are computed
>> eagerly, and then cached until still valid.  So if you type
>>
>>   fo<tab>o.bar.baz
>>
>> the inferior process is contacted 3 times: after the <tab>, and after
>> each dot.  Before, a lazy table was returned, but the inferior would be
>> contacted after each character anyway (if using Company or similar).
>
> Ah, I see, then that sounds like a definite improvement.  My other
> question is then how the cache is flushed...

The cache will be flushed, at the earliest, when a new call to
'python-shell-completion-at-point' is made.  And the criterium is the
following:

- If the prompt moved, then the cache is flushed.
- If the current completion prefix (the text between 'start' and 'end')
  is not identical to the original completion prefix, except for the
  addition of some word or symbol characters at the end, then the cache
  is flushed.

That's it in a nutshell.  I can give more details if you want.





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

* bug#50459: 28.0.50; Python shell completion is incompatible with flex, orderless, etc.
  2021-09-11 12:34                   ` Augusto Stoffel
@ 2021-09-11 12:36                     ` Lars Ingebrigtsen
  0 siblings, 0 replies; 26+ messages in thread
From: Lars Ingebrigtsen @ 2021-09-11 12:36 UTC (permalink / raw)
  To: Augusto Stoffel; +Cc: 50459, Gregory Heytings, Michael Albinus, joaotavora

Augusto Stoffel <arstoffel@gmail.com> writes:

> The cache will be flushed, at the earliest, when a new call to
> 'python-shell-completion-at-point' is made.  And the criterium is the
> following:
>
> - If the prompt moved, then the cache is flushed.
> - If the current completion prefix (the text between 'start' and 'end')
>   is not identical to the original completion prefix, except for the
>   addition of some word or symbol characters at the end, then the cache
>   is flushed.

Ah, I got the last bit, but I missed the first part.  Well, then I think
this sounds like a good approach?

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





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

* bug#50459: 28.0.50; [PATCH] Python shell completion is incompatible with flex, orderless, etc.
  2021-09-10 19:08 ` bug#50459: 28.0.50; [PATCH] " Augusto Stoffel
@ 2021-09-11 12:50   ` Lars Ingebrigtsen
  0 siblings, 0 replies; 26+ messages in thread
From: Lars Ingebrigtsen @ 2021-09-11 12:50 UTC (permalink / raw)
  To: Augusto Stoffel; +Cc: Michael Albinus, Gregory Heytings, 50459, Dmitry Gutov

Augusto Stoffel <arstoffel@gmail.com> writes:

> Good idea.  I've added this to the patch.  It still won't show the new
> completions until the user evaluates the import, but this is the best
> you can get by querying an interpreter for the completions.
>
> I've also changed a bit the way the "native completion" setup code is
> sent, so that it doesn't print a message directly in the shell buffer
> (there is still an echo area message).

Looks good to me; pushed to Emacs 28 now.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





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

end of thread, other threads:[~2021-09-11 12:50 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-09-07 17:52 bug#50459: 28.0.50; Python shell completion is incompatible with flex, orderless, etc Augusto Stoffel
2021-09-08 17:44 ` Augusto Stoffel
2021-09-09  7:11   ` Michael Albinus
2021-09-09  7:32     ` Gregory Heytings
2021-09-09  7:30 ` Gregory Heytings
2021-09-09  7:40   ` Augusto Stoffel
2021-09-09  7:49     ` Gregory Heytings
2021-09-09  8:45       ` Augusto Stoffel
2021-09-09  8:50         ` Gregory Heytings
2021-09-09 16:46           ` Augusto Stoffel
2021-09-10 11:37             ` Lars Ingebrigtsen
2021-09-10 11:50               ` Augusto Stoffel
2021-09-10 13:14                 ` João Távora
2021-09-10 13:28                   ` Dmitry Gutov
2021-09-10 14:06                     ` João Távora
2021-09-10 14:22                       ` Dmitry Gutov
2021-09-10 14:39                         ` João Távora
2021-09-10 14:43                           ` Dmitry Gutov
2021-09-10 19:27                             ` Augusto Stoffel
2021-09-10 20:08                               ` João Távora
2021-09-11 12:09                 ` Lars Ingebrigtsen
2021-09-11 12:34                   ` Augusto Stoffel
2021-09-11 12:36                     ` Lars Ingebrigtsen
2021-09-10 13:32             ` Dmitry Gutov
2021-09-10 19:08 ` bug#50459: 28.0.50; [PATCH] " Augusto Stoffel
2021-09-11 12:50   ` Lars Ingebrigtsen

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).