Subject: bug#6830: widget-complete bad completions in :type 'file

From: Eli Zaretskii <[email-masked]>
Date: Fri, 24 Feb 2012 21:35:15 +0200

> From: Glenn Morris <[email-masked]>
> Date: Wed, 22 Feb 2012 16:33:56 -0500
> 
> Chong Yidong wrote:
> 
> > If I enter "~/aaa" in the widget field and there is no file starting
> > with "aaa" in my home directory, M-TAB does nothing except for
> > displaying "No match" in the echo area.
> >
> > This is with the latest trunk, on GNU/Linux.
> 
> I also cannot reproduce this.
> If no-one can reproduce this using stock Emacs on MS Windows, I suggest
> closing this.

Please don't close it.  IIUC (and I'm not at all sure, as the
complexity of wid-edit.el and minibuffer.el is above my pay-grade),
the fact that it works on GNU/Linux is sheer luck.

What seems to happen is this:

 . widget-complete calls completion-in-region, which in turn calls
   minibuffer-complete, after let-binding the necessary variables:

    (let ((minibuffer-completion-table collection)
          (minibuffer-completion-predicate predicate)
          (ol (make-overlay start end nil nil t)))
      (overlay-put ol 'field 'completion)
      (when completion-in-region-mode-predicate
        (completion-in-region-mode 1)
        (setq completion-in-region--data
            (list (current-buffer) start end collection)))
      (unwind-protect
          (call-interactively 'minibuffer-complete)

 . minibuffer-complete calls completion--do-completion, which does
   this at its very beginning:

    (let* ((beg (field-beginning))
	   (end (field-end))
	   (string (buffer-substring beg end))
	   (md (completion--field-metadata beg))

   On GNU/Linux, field-beginning is correctly computed to be at the
   beginning of the field, and thus buffer-substring correctly
   extracts whatever you typed into the field, and that substring is
   thereafter correctly completed.

   In contrast, on Windows, field-beginning returns the position of
   point, so if point is at the end of whatever you typed (as it
   usually is when one hits M-TAB), buffer-substring extracts an empty
   string, which is then "completed" to the files in the
   default-directory.

The difference between the two system is, so it seems, that
find_field, which is the workhorse of field-beginning, looks at
overlays at point and before point which have the `field' property.
The problem is that we have 2 such overlays before point: one whose
`field' value is `completion' (as can be seen above, this overlay is
put there by completion-in-region), and another whose `field' value is
identical to the `field' text property at point.  Both of these
overlays have nil as their priority, so when
get_char_property_and_overlay sorts the overlays by priority, the
resulting order is arbitrary.  On GNU/Linux, the first overlay in the
sorted array happens to be the one whose `field' value is equal to the
text property, so find_field works.  On MS-Windows, the first overlay
is the one whose value is `completion', so find_field decides that the
field begins and ends at the same position.  The rest, as they say, is
history.

I hope that this analysis (if it is correct) will allow someone
smarter than myself to figure out how to fix this.