all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: Stefan Monnier <monnier@iro.umontreal.ca>
To: emacs-devel@gnu.org
Subject: Re: new-flex-completion-style
Date: Tue, 12 Feb 2019 09:08:03 -0500	[thread overview]
Message-ID: <jwvimxpqh2m.fsf-monnier+emacs@gnu.org> (raw)
In-Reply-To: 87lg2mynrg.fsf@gmail.com

>> W.r.t the UI sorting minibuffer.el has 2 different UIs with 2 different
>> sorting behaviors: there's the *Completions* buffer where results are
>> sorted alphabetically, and there's the force-complete cycling which
>> sorts by most-recently seen (using the minibuffer history variable) and
>> by length.
> Tangent: When using icomplete (who else here uses icomplete?), this is
> (the length) not good at all for switching buffers.

Not sure if it's related to icomplete.  Maybe the length-heuristic is
just not good for buffer names.  It was mostly motivated by experience
with M-x where I do believe that there is a correlation between command
name length and frequency of use of that command.

I think this length heuristic also works reasonably well in several
other circumstances (e.g. file names).

[ I'm clearly talking about the TAB-cycling use case, but I can't think
  of a good reason why the icomplete-mode should be very different.  ]

> I want it to behave like ido, where the natural order of buffer-list
> is preserved when the buffer can't be found in the
> minibuffer-history-variable.

How 'bout we change the buffer name completion table so it specifies its
own cycle-sort-function which uses buffer-list, then.  It seems like it
would be a clear win (the buffer-list order is a much better heuristic
than the length).

> The only problem is that completion-style doesn't have a point to
> plug-in sorting yet.

That's right.

> So I thought good place to start is to place hints
> in the completion-candidates.

It's probably a good idea, yes.

>> Still, in a case such as lisp/ecomplete.el where the completion table
>> provides its own sorting based on recent-usage-frequency, how should
>> this sorting be combined with that of flex?  I can see arguments in
>> favor of saying that the flex-weight should be ignored in favor of the
>> usage-frequency.
> ecomplete has its own UI in ecomplete-display-matches?

It also offers a completion-table (which I use via
a completion-at-point-function).

> My view of the matter is: completion table provides its sorting which
> _can_ be overriden by completion style's sorting which _can_ be
> overriden by completion UI's sorting.  AFAIU this can be done by writing
> comparison functions that return nil if the current sorting should be
> agnostic to both elements.

Writing the function is of course the easy part. 
The problem is where/how to insert this function.

>> I'd like to move towards a completion-style API that uses cl-generic.
>> E.g. introduce generic functions like `completion-style-try-completion`
>> which would be like `completion-try-completion` but takes an additional
>> `style` argument and dispatches based on it (replacing the dispatch
>> based on completion-style-alist).
>
> This is a good change, but it's not absolutely necessary to what I am
> proposing right now.

Definitely.  I just wanted to explain that the design to the current
solution can be done with this other change in mind.

>>>     * lisp/minibuffer.el (minibuffer-completion-help): Use
>>>     completion-style-sort-order and compeltion-style-annotation
>>                                       ^^^^^^^^^^
>>                                       completion
>>>     properties.
>>>     (completion-pcm--hilit-commonality): Propertize completion with
>>>     'completion-pcm-commonality-score.
>>>     (completion-flx-all-completions): Porpertize completion with
>>                                         ^^^^^^^^^^
>>                                         Propertize
> Thanks.

Duh!  I meant to add some idiotic scolding about those typos but got
side tracked by the annotations issue.  Sorry.  I promise to be more
firm next time.

>>>     completion-style-sort-order and completion-style-annotation.
>> Regarding annotations, I think being able to `concat` at the end is
>> too limited.  If you take your example from sly, we'd like the "15%"
>> annotations to be right-aligned and I don't see an easy way to do that
>> with the facility you introduce.
> I don't see the problem fully,

Hmm... I guess in the completion-style case, you could indeed look at
all the returned completions to compute the max-length and do some
right-alignment based on that.  For some reason, I feel like it'd be
better done elsewhere, tho (e.g. maybe company would rather right-align
based on the max-length of the *displayed* completions rather than
based on the max-length of all the completions).

> but probably I'd rather remove the annotation completely for now,
> until we have a better of how where we want to place it.  As Dmitry
> suggested, the flex score annotation is mostly a gimmick, we shouldn't
> add it until we have a good idea of how it should work.

Indeed, this annotation issue is orthogonal, so it can be kept for later.

>> So I'd encourage you to come up with a more flexible annotation system
>> that allows prepending annotations as well as right-alignment (and
>> ideally combinations of those, with several columns, ...).
>
> I'd prefer small things that can be added
> incrementally.

So do I.

> What do you suggest?

Nothing so far.

> So to summarize, I propose to add (1) the fafa9ec commit introducing
> flex completion and (2) a new commit extracted from 2c7577558 which adds
> the flex scoring calculation to each match, but doesn't do anything with
> it yet.  Deal?

Fine by me.  I'd call the score property `completion-score` because
I don't see any reason why it should be specific to the completion-style
(you could even have `flex` combine its score with a `completion-score`
property previously set by the completion-table, and then have the
front end combine that with its own scoring).

I think you can also make minibuffer-completion-help sort according to
that `completion-score`.

Regarding the code, see comments below.


        Stefan


> +          (setq completions
> +                (sort completions
> +                      (lambda (a b)
> +                        (let ((va (get-text-property 0 'completion-style-sort-order a))
> +                              (vb (get-text-property 0 'completion-style-sort-order b)))
> +                          (if (and va vb) (< va vb) va)))))

This will signal an error when one of the completions is the empty string :-(

> @@ -3056,22 +3067,41 @@ PATTERN is as returned by `completion-pcm--string->pattern'."
>           (let* ((pos (if point-idx (match-beginning point-idx) (match-end 0)))
>                  (md (match-data))
>                  (start (pop md))
> -                (end (pop md)))
> +                (end (pop md))
> +                (len (length str))
> +                (score-numerator 0)
> +                (score-denominator 0)
> +                (aux 0)
> +                (update-score
> +                 (lambda (a b)
> +                   "Update score variables given match range (A B)."
> +                   (setq
> +                    score-numerator   (+ score-numerator (- b a))
> +                    score-denominator (+ score-denominator (expt (- a aux) 1.5))
> +                    aux              b))))

I don't understand this scoring algorithm: please add a comment
explaining it (and give a meaningful name to `aux`).

> +           (funcall update-score 0 start)
>             (while md
> -             (put-text-property start (pop md)
> +             (funcall update-score start (car md))
> +             (put-text-property start
> +                                (pop md)

The extra line-break after `start` seems spurious.

> +           (put-text-property
> +            0 1 'completion-pcm-commonality-score
> +            (/ score-numerator (* len (1+ score-denominator)) 1.0) str))

This will signal an error when `str` is the empty string :-(

BTW, maybe PCM could also use this scoring for sorting (i.e. we could
set `completion-score` directly here)

> +           (let ((score (get-text-property 0 'completion-pcm-commonality-score comp)))
> +             (put-text-property 0 1 'completion-style-sort-order (- score) comp)

This will signal an error when `comp` is the empty string :-(




  parent reply	other threads:[~2019-02-12 14:08 UTC|newest]

Thread overview: 71+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <20190202232827.27331.87300@vcs0.savannah.gnu.org>
     [not found] ` <20190202232828.4AE452159A@vcs0.savannah.gnu.org>
2019-02-06  3:11   ` [Emacs-diffs] scratch/new-flex-completion-style 2c75775 2/2: Score, sort and annotate flex-style completions according to match tightness Dmitry Gutov
2019-02-06 10:09     ` João Távora
2019-02-06 18:54       ` Dmitry Gutov
2019-02-06 19:47         ` João Távora
2019-02-12  0:25           ` Dmitry Gutov
2019-02-12 13:19             ` Stefan Monnier
2019-02-12 22:55               ` Dmitry Gutov
2019-02-13 16:00                 ` Stefan Monnier
2019-02-14  1:33                   ` Dmitry Gutov
2019-02-19 16:10                     ` Stefan Monnier
2019-02-24  0:03                       ` Dmitry Gutov
2019-02-27 17:12                         ` Stefan Monnier
2019-03-11  0:17                           ` Dmitry Gutov
2019-03-11  1:15                             ` Stefan Monnier
2019-03-11 22:54                               ` Dmitry Gutov
2019-03-12  1:10                                 ` Drew Adams
2019-03-12 22:25                                   ` Dmitry Gutov
2019-03-12 23:12                                     ` Drew Adams
2019-03-11  8:47                             ` João Távora
2019-03-11 22:57                               ` Dmitry Gutov
2019-02-12 17:21             ` João Távora
2019-02-12 23:47               ` Dmitry Gutov
2019-02-11 21:10   ` new-flex-completion-style (was: [Emacs-diffs] scratch/ 2c75775 2/2: Score, sort and annotate flex-style completions according to match tightness) Stefan Monnier
2019-02-11 22:16     ` new-flex-completion-style João Távora
2019-02-11 23:02       ` new-flex-completion-style Dmitry Gutov
2019-02-11 23:11         ` new-flex-completion-style João Távora
2019-02-12  0:10           ` new-flex-completion-style Dmitry Gutov
2019-02-12  0:16       ` new-flex-completion-style Óscar Fuentes
2019-02-12 22:04         ` new-flex-completion-style João Távora
2019-02-13  0:28           ` new-flex-completion-style Óscar Fuentes
2019-02-13 11:20             ` new-flex-completion-style João Távora
2019-02-13 14:23               ` new-flex-completion-style Óscar Fuentes
2019-02-13 14:38                 ` new-flex-completion-style Drew Adams
2019-02-13 15:24               ` new-flex-completion-style Stefan Monnier
2019-02-13 15:33                 ` new-flex-completion-style Drew Adams
2019-02-13 15:40                 ` new-flex-completion-style Óscar Fuentes
2019-02-13 17:34                   ` new-flex-completion-style Daniel Pittman
2019-02-12 14:08       ` Stefan Monnier [this message]
2019-02-12 22:17         ` new-flex-completion-style João Távora
2019-02-13 17:29           ` new-flex-completion-style João Távora
2019-02-13 18:54             ` new-flex-completion-style Stefan Monnier
2019-02-13 19:13               ` new-flex-completion-style João Távora
2019-02-14 13:36                 ` new-flex-completion-style Stefan Monnier
2019-02-14 13:55                   ` new-flex-completion-style João Távora
2019-02-14 14:59                     ` new-flex-completion-style João Távora
2019-02-14 15:28                       ` new-flex-completion-style Óscar Fuentes
2019-02-14 15:44                         ` new-flex-completion-style Drew Adams
2019-02-14 16:21                         ` new-flex-completion-style João Távora
2019-02-14 15:35                       ` new-flex-completion-style Daniel Pittman
2019-02-14 16:12                         ` new-flex-completion-style João Távora
2019-02-14 16:16                           ` new-flex-completion-style João Távora
2019-02-14 16:34                         ` new-flex-completion-style Drew Adams
2019-02-14 17:03                           ` new-flex-completion-style João Távora
2019-02-14 17:49                             ` new-flex-completion-style Drew Adams
2019-02-14 18:30                               ` new-flex-completion-style João Távora
2019-02-14 19:20                                 ` new-flex-completion-style Drew Adams
2019-02-14 20:54                                   ` new-flex-completion-style João Távora
2019-02-14 22:03                                     ` new-flex-completion-style Drew Adams
2019-02-14 22:06                                       ` new-flex-completion-style João Távora
2019-02-14 22:22                                       ` new-flex-completion-style Stefan Monnier
2019-02-15  0:54                                         ` new-flex-completion-style Drew Adams
2019-02-15  4:50                                           ` new-flex-completion-style Stefan Monnier
2019-02-15  5:52                                             ` new-flex-completion-style Dmitry Gutov
2019-02-15  6:32                                             ` new-flex-completion-style Drew Adams
2019-02-18 20:46         ` new-flex-completion-style João Távora
2019-02-18 23:35           ` new-flex-completion-style Stefan Monnier
2019-02-19  9:16             ` new-flex-completion-style João Távora
2019-02-19 12:54               ` new-flex-completion-style Stefan Monnier
2019-02-19 13:01                 ` new-flex-completion-style João Távora
2019-02-19 13:32                   ` new-flex-completion-style Stefan Monnier
2019-02-11 22:57     ` new-flex-completion-style (was: [Emacs-diffs] scratch/ 2c75775 2/2: Score, sort and annotate flex-style completions according to match tightness) Drew Adams

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=jwvimxpqh2m.fsf-monnier+emacs@gnu.org \
    --to=monnier@iro.umontreal.ca \
    --cc=emacs-devel@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this external index

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

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.