emacs-pretest-bug
[Top][All Lists]
Advanced

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

Re: Display problems with 'before-string in overlay


From: Lennart Borgman (gmail)
Subject: Re: Display problems with 'before-string in overlay
Date: Thu, 12 Apr 2007 21:15:29 +0200
User-agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.10) Gecko/20070221 Thunderbird/1.5.0.10 Mnenhy/0.7.5.666

Chong Yidong wrote:
address@hidden (Kim F. Storm) writes:

IIRC, the original problem I tried to solve is shown by this test-case:

(progn
  (switch-to-buffer (get-buffer-create "*test*"))
  (erase-buffer)
  (insert ".\n<\n.\n>\n")
  (goto-char (point-min))
  (let ((ov (make-overlay 4 7)))
      (overlay-put ov 'display "Ax\nyB"))
  (goto-char (point-max)))

With my change, moving the cursor places it on the 'A'.
Without my change, moving the cursor places it on the 'y'.
So my change may be incorrect - but it _does_ solve a real problem.

OK, now I see the problem.

I believe the underlying fault is not in cursor_row_p, but in
set_cursor_from_row, on xdisp.c:11948:

  pos = string_buffer_position (w, string, string_before_pos);
  /* If STRING is from overlay, LAST_POS == 0.  We skip such glyphs
     because we always put cursor after overlay strings.  */
  while (pos == 0 && glyph < stop)
    {
      string = glyph->object;

The assumption made in the comment is not correct:
string_buffer_position returns non-zero values for overlay strings
with the `display' property.  In xdisp.c:4446:

  prop = Fget_char_property (pos, Qdisplay, Qnil);
  if (!NILP (prop) && display_prop_string_p (prop, string))
    found = 1;

This suggests that the way to fix this is to change
string_buffer_position to do what that says.  However, it is dangerous
to change string_buffer_position right now, because it's called from
several places in xdisp.c.  Changing its behavior runs a serious risk
of introducing subtle bugs.

I tested another way that perhaps is in line with Kim's original intent. Since I do not know this code I had to guess put I put it here so you can comment:

static int
cursor_row_p (w, row)
     struct window *w;
     struct glyph_row *row;
{
  int cursor_row_p = 1;

  if (PT == MATRIX_ROW_END_CHARPOS (row))
    {
      /* If the row ends with a newline from a string, we don't want
         the cursor there, but we still want it at the start of the
         string if the string starts in this row.
         If the row is continued it doesn't end in a newline.  */
      fprintf (stderr, "cont=%d, start.string_pos=%d, %d, end=%d, %d\n",
               row->continued_p,
               CHARPOS (row->start.string_pos),
               row->start.pos.charpos,
               CHARPOS (row->end.string_pos),
               row->end.pos.charpos);
      if (CHARPOS (row->end.string_pos) >= 0)
        cursor_row_p = (row->continued_p
                        ||
                        (
                         /* If an overlay string starts on this glyph
                            line, then put the cursor here, but only
                            if not on the first buffer line and there
                            are no characters there.  */
                         ((CHARPOS (row->start.string_pos)) == -1)
                         &&
                         ((CHARPOS (row->end.string_pos)) > -1)
                         &&
                         (row->start.pos.charpos > 1)
                         ));
      else if (MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row))
        {
          /* If the row ends in middle of a real character,
             and the line is continued, we want the cursor here.
             That's because MATRIX_ROW_END_CHARPOS would equal
             PT if PT is before the character.  */
          if (!row->ends_in_ellipsis_p)
            cursor_row_p = row->continued_p;
          else
          /* If the row ends in an ellipsis, then
             MATRIX_ROW_END_CHARPOS will equal point after the invisible text.
             We want that position to be displayed after the ellipsis.  */
            cursor_row_p = 0;
        }
      /* If the row ends at ZV, display the cursor at the end of that
         row instead of at the start of the row below.  */
      else if (row->ends_at_zv_p)
        cursor_row_p = 1;
      else
        cursor_row_p = 0;
    }

  return cursor_row_p;
}

This works for me and for Kim's test case as far as I can see. However as can be seen from the fprintf output with my test case it starts looping when I go to the first character and then press left arrow.

Thus, I think this issue should be left alone for the Emacs 22.1.  It
is easy to work around the affected corner case, by using text
properties or a display property rather an overlay with a
before-string.  After 22.1, I can take a look at fixing this along the
lines discussed above.


Could you please tell me how then? I want to display text at the top of a buffer, but I do not want to change the users text in the buffer.




reply via email to

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