[Top][All Lists]

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

Problems with move_it_in_display_line_to X when tabs exist.

From: Keith David Bershatsky
Subject: Problems with move_it_in_display_line_to X when tabs exist.
Date: Tue, 28 Nov 2017 22:12:35 -0800

I have reached a road block calculating X and HPOS when dealing with tabs while 
working on feature requests 17684 (crosshairs) and 22873 (multiple fake 

DETAILS:  Native line numbers are visible.  No overlays are present.  No 
special text properties are present.

GOAL:  The goal is to move IT from it.first_visible_x to it.last_visible_x on 
the line containing POINT and place fake cursors on each tab, adjustable 
tab-width, and/or character.  As I move IT over the line containing POINT, I 
want to reliably obtain X and HPOS.  This works well if there are no tabs.  
And, it works well if there are just a couple of tabs with a tab-width of 2.  
At some point, however, it stops working when there are more than just a couple 
of tabs on the same line, especially when they are mixed somewhere within the 
middle of the line.  I am using draw_window_cursor to create multiple fake 
cursors (with the underscore shape) on the entire current line, to create a 
horizontal ruler spanning the window-body-width.

I can see that X and/or HPOS are wrong when tabs are present on the current 
line because I get superimposed letters and double of the same word slightly 
off to the left and/or the right of where the word should be.

HYPOTHESIS:  I would venture to say that what is displayed on screen does _not_ 
coincide with what IT reports when running move_it_in_display_line_to.

IDEAS:  Erase the entire current line and redraw it so that what is displayed 
on screen matches exactly what IT reports when running 

Any additional ideas or thoughts on how to deal with tabs in this scenario 
would be greatly appreciated.


  while (true)
      flavor = (it.c != '\t') ? Qmc_glyph : Qmc_glyph_tab;
      if (hscl)
          relative_x = it.current_x - (hscl_first_hpos * frame_char_width);
          hpos = it.hpos - hscl_first_hpos;
            relative_x = it.current_x - first_x;
            hpos = it.hpos;
      if (header_line_height > 0)
        vpos = it.vpos + 1;
          vpos = it.vpos;
      bool lpw_reached_p = ((hscl
                             && it.current_x >= hscl_first_x + lnum_pixel_width)
                            || (!hscl
                                && it.current_x >= first_x + lnum_pixel_width));
      bool final_loop_p = (ITERATOR_AT_END_OF_LINE_P (&it)
                           || FETCH_BYTE (IT_BYTEPOS (it)) == '\n'
                           || rc == MOVE_POS_MATCH_OR_ZV);
      bool tab_invisible_p = (it.c == '\t');
      bool tab_visible_p = (it.c != '\t'
                            && FETCH_BYTE (IT_BYTEPOS (it)) == '\t');
      bool real_fake_cursor_p = (opoint_x == relative_x
                                 && opoint_y == it.current_y
                                 && opoint_hpos == hpos
                                 && opoint_vpos == vpos);
      if (!real_fake_cursor_p
          && lpw_reached_p
          && !tab_invisible_p)
        draw_fake_cursor (w, relative_x, it.current_y, hpos, vpos,
                          HBAR_CURSOR, cursor_width,
                          foreground, color_vector (w, it.face_id),
                          flavor, IT_CHARPOS (it), &result);
      if (!real_fake_cursor_p
          && lpw_reached_p
          && tab_invisible_p)
          int i, count = it.pixel_width / frame_char_width;
          for (i = 0; i < count; i++)
              draw_fake_cursor (w, relative_x, it.current_y, hpos, vpos,
                                HBAR_CURSOR, cursor_width,
                                foreground, color_vector (w, it.face_id),
                                flavor, IT_CHARPOS (it), &result);
              relative_x = relative_x + frame_char_width;
      if (final_loop_p)
      rc = mc_move_it_in_display_line (w, &it, it.current_x + it.pixel_width);
      if (rc == MOVE_LINE_CONTINUED)
      relative_x = (hscl)
                   ? it.current_x - (hscl_first_hpos * frame_char_width)
                   : it.current_x - first_x;
      if (relative_x + frame_char_width >= text_area_width)

mc_move_it_in_display_line (struct window *w, struct it *it, int target_x)
  if (IT_CHARPOS (*it) == ZV)
    return MOVE_POS_MATCH_OR_ZV;
  struct it saved_it;
  void *saved_data = bidi_shelve_cache ();
  enum move_it_result rc = MOVE_X_REACHED;
  int new_x, prev_x;
  /* When `auto-hscroll-mode' is set to `current-line` and we are horizontal 
  a long line that approaches or exceeds an `it.current.x` of approximately 
1000, `rc`
  will erroneously return early with a MOVE_LINE_TRUNCATED indicator without 
  forwards until IT reaches the target_x.  As a workaround, ignore 
  while (it->current_x + it->pixel_width <= target_x
         && (rc == MOVE_X_REACHED
             || rc == MOVE_LINE_TRUNCATED
             || (it->line_wrap == WORD_WRAP
                 && rc == MOVE_POS_MATCH_OR_ZV)))
      SAVE_IT (saved_it, *it, saved_data);
      new_x = it->current_x + it->pixel_width;
      if (new_x == it->current_x)
      rc = move_it_in_display_line_to (it, ZV, new_x, MOVE_TO_POS | MOVE_TO_X);
      if (ITERATOR_AT_END_OF_LINE_P (it)
          || FETCH_BYTE (IT_BYTEPOS (*it)) == '\n'
          /* #28936:  `move_it_in_display_line_to' returns MOVE_POS_MATCH_OR_ZV
          before reaching ZV when the latter is at the end of the line AND 
          is non-nil:  abcdefg[ZV].  The workaround is to add an extra check 
          IT_CHARPOS and comparing it to ZV. */
          || (rc == MOVE_POS_MATCH_OR_ZV
              && IT_CHARPOS (*it) == ZV))
  /* When word-wrap is on, TO_X may lie past the end of a wrapped line.
  Then it->current is the character on the next line, so backtrack to the
  space before the wrap point.  */
  if (it->line_wrap == WORD_WRAP
      && rc == MOVE_LINE_CONTINUED)
      prev_x = max (it->current_x - 1, 0);
      RESTORE_IT (it, &saved_it, saved_data);
      move_it_in_display_line_to (it, -1, prev_x, MOVE_TO_X);
  bidi_unshelve_cache (saved_data, true);
  /* Workaround for bug #28936 -- correct the erroneous MOVE_POS_MATCH_OR_ZV. */
  if (it->current_x == target_x
      && rc == MOVE_POS_MATCH_OR_ZV
      && IT_CHARPOS (*it) != ZV)
    rc = MOVE_X_REACHED;
  return rc;

reply via email to

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