Пример #1
0
static int coladvance2(
    pos_T *pos,
    bool addspaces,                /* change the text to achieve our goal? */
    bool finetune,                 /* change char offset for the exact column */
    colnr_T wcol                   /* column to move to */
)
{
  int idx;
  char_u      *ptr;
  char_u      *line;
  colnr_T col = 0;
  int csize = 0;
  int one_more;
  int head = 0;

  one_more = (State & INSERT)
             || restart_edit != NUL
             || (VIsual_active && *p_sel != 'o')
             || ((ve_flags & VE_ONEMORE) && wcol < MAXCOL);
  line = ml_get_buf(curbuf, pos->lnum, false);

  if (wcol >= MAXCOL) {
    idx = (int)STRLEN(line) - 1 + one_more;
    col = wcol;

    if ((addspaces || finetune) && !VIsual_active) {
      curwin->w_curswant = linetabsize(line) + one_more;
      if (curwin->w_curswant > 0)
        --curwin->w_curswant;
    }
  } else {
    int width = curwin->w_width - win_col_off(curwin);

    if (finetune
        && curwin->w_p_wrap
        && curwin->w_width != 0
        && wcol >= (colnr_T)width) {
      csize = linetabsize(line);
      if (csize > 0)
        csize--;

      if (wcol / width > (colnr_T)csize / width
          && ((State & INSERT) == 0 || (int)wcol > csize + 1)) {
        /* In case of line wrapping don't move the cursor beyond the
         * right screen edge.  In Insert mode allow going just beyond
         * the last character (like what happens when typing and
         * reaching the right window edge). */
        wcol = (csize / width + 1) * width - 1;
      }
    }

    ptr = line;
    while (col <= wcol && *ptr != NUL) {
      /* Count a tab for what it's worth (if list mode not on) */
      csize = win_lbr_chartabsize(curwin, line, ptr, col, &head);
      MB_PTR_ADV(ptr);
      col += csize;
    }
    idx = (int)(ptr - line);
    /*
     * Handle all the special cases.  The virtual_active() check
     * is needed to ensure that a virtual position off the end of
     * a line has the correct indexing.  The one_more comparison
     * replaces an explicit add of one_more later on.
     */
    if (col > wcol || (!virtual_active() && one_more == 0)) {
      idx -= 1;
      /* Don't count the chars from 'showbreak'. */
      csize -= head;
      col -= csize;
    }

    if (virtual_active()
        && addspaces
        && ((col != wcol && col != wcol + 1) || csize > 1)) {
      /* 'virtualedit' is set: The difference between wcol and col is
       * filled with spaces. */

      if (line[idx] == NUL) {
        /* Append spaces */
        int correct = wcol - col;
        char_u *newline = xmallocz((size_t)(idx + correct));
        memcpy(newline, line, (size_t)idx);
        memset(newline + idx, ' ', (size_t)correct);

        ml_replace(pos->lnum, newline, false);
        changed_bytes(pos->lnum, (colnr_T)idx);
        idx += correct;
        col = wcol;
      } else {
        /* Break a tab */
        int linelen = (int)STRLEN(line);
        int correct = wcol - col - csize + 1;             /* negative!! */
        char_u  *newline;

        if (-correct > csize)
          return FAIL;

        newline = xmallocz((size_t)(linelen - 1 + csize));
        // Copy first idx chars
        memcpy(newline, line, (size_t)idx);
        // Replace idx'th char with csize spaces
        memset(newline + idx, ' ', (size_t)csize);
        // Copy the rest of the line
        memcpy(newline + idx + csize, line + idx + 1,
               (size_t)(linelen - idx - 1));

        ml_replace(pos->lnum, newline, false);
        changed_bytes(pos->lnum, idx);
        idx += (csize - 1 + correct);
        col += correct;
      }
    }
  }

  if (idx < 0)
    pos->col = 0;
  else
    pos->col = idx;

  pos->coladd = 0;

  if (finetune) {
    if (wcol == MAXCOL) {
      /* The width of the last character is used to set coladd. */
      if (!one_more) {
        colnr_T scol, ecol;

        getvcol(curwin, pos, &scol, NULL, &ecol);
        pos->coladd = ecol - scol;
      }
    } else {
      int b = (int)wcol - (int)col;

      /* The difference between wcol and col is used to set coladd. */
      if (b > 0 && b < (MAXCOL - 2 * curwin->w_width))
        pos->coladd = b;

      col += b;
    }
  }

  // Prevent from moving onto a trail byte.
  if (has_mbyte) {
    mark_mb_adjustpos(curbuf, pos);
  }

  if (col < wcol)
    return FAIL;
  return OK;
}
Пример #2
0
// Compute the position in the buffer line from the posn on the screen in
// window "win".
// Returns true if the position is below the last line.
bool mouse_comp_pos(win_T *win, int *rowp, int *colp, linenr_T *lnump)
{
  int col = *colp;
  int row = *rowp;
  linenr_T lnum;
  bool retval = false;
  int off;
  int count;

  if (win->w_p_rl)
    col = win->w_width - 1 - col;

  lnum = win->w_topline;

  while (row > 0) {
    // Don't include filler lines in "count"
    if (win->w_p_diff
        && !hasFoldingWin(win, lnum, NULL, NULL, true, NULL)) {
      if (lnum == win->w_topline) {
        row -= win->w_topfill;
      } else {
        row -= diff_check_fill(win, lnum);
      }
      count = plines_win_nofill(win, lnum, true);
    } else {
      count = plines_win(win, lnum, true);
    }

    if (count > row) {
      break;            // Position is in this buffer line.
    }

    (void)hasFoldingWin(win, lnum, NULL, &lnum, true, NULL);

    if (lnum == win->w_buffer->b_ml.ml_line_count) {
      retval = true;
      break;                    // past end of file
    }
    row -= count;
    ++lnum;
  }

  if (!retval) {
    // Compute the column without wrapping.
    off = win_col_off(win) - win_col_off2(win);
    if (col < off)
      col = off;
    col += row * (win->w_width - off);
    // add skip column (for long wrapping line)
    col += win->w_skipcol;
  }

  if (!win->w_p_wrap) {
    col += win->w_leftcol;
  }

  // skip line number and fold column in front of the line
  col -= win_col_off(win);
  if (col < 0) {
    col = 0;
  }

  *colp = col;
  *rowp = row;
  *lnump = lnum;
  return retval;
}
Пример #3
0
// Adjust the clicked column position if there are concealed characters
// before the current column.  But only when it's absolutely necessary.
static int mouse_adjust_click(win_T *wp, int row, int col)
{
  if (!(wp->w_p_cole > 0 && curbuf->b_p_smc > 0
        && wp->w_leftcol < curbuf->b_p_smc && conceal_cursor_line(wp))) {
    return col;
  }

  int end = (colnr_T)STRLEN(ml_get(wp->w_cursor.lnum));
  int vend = getviscol2(end, 0);

  if (col >= vend) {
    return col;
  }

  int i = wp->w_leftcol;

  if (row > 0) {
    i += row * (wp->w_width - win_col_off(wp) - win_col_off2(wp)
                - wp->w_leftcol) + wp->w_skipcol;
  }

  int start_col = i;
  int matchid;
  int last_matchid;
  int bcol = end - (vend - col);

  while (i < bcol) {
    matchid = syn_get_concealed_id(wp, wp->w_cursor.lnum, i);

    if (matchid != 0) {
      if (wp->w_p_cole == 3) {
        bcol++;
      } else {
        if (row > 0 && i == start_col) {
          // Check if the current concealed character is actually part of
          // the previous wrapped row's conceal group.
          last_matchid = syn_get_concealed_id(wp, wp->w_cursor.lnum,
                                              i - 1);
          if (last_matchid == matchid) {
            bcol++;
          }
        } else if (wp->w_p_cole == 1
                   || (wp->w_p_cole == 2
                       && (lcs_conceal != NUL
                           || syn_get_sub_char() != NUL))) {
          // At least one placeholder character will be displayed.
          bcol--;
        }

        last_matchid = matchid;

        // Adjust for concealed text that spans more than one character.
        do {
          i++;
          bcol++;
          matchid = syn_get_concealed_id(wp, wp->w_cursor.lnum, i);
        } while (last_matchid == matchid);

        continue;
      }
    }

    i++;
  }

  return getviscol2(bcol, 0);
}
Пример #4
0
/// Adjusts the clicked column position when 'conceallevel' > 0
static int mouse_adjust_click(win_T *wp, int row, int col)
{
  if (!(wp->w_p_cole > 0 && curbuf->b_p_smc > 0
        && wp->w_leftcol < curbuf->b_p_smc && conceal_cursor_line(wp))) {
    return col;
  }

  // `col` is the position within the current line that is highlighted by the
  // cursor without consideration for concealed characters.  The current line is
  // scanned *up to* `col`, nudging it left or right when concealed characters
  // are encountered.
  //
  // chartabsize() is used to keep track of the virtual column position relative
  // to the line's bytes.  For example: if col == 9 and the line starts with a
  // tab that's 8 columns wide, we would want the cursor to be highlighting the
  // second byte, not the ninth.

  linenr_T lnum = wp->w_cursor.lnum;
  char_u *line = ml_get(lnum);
  char_u *ptr = line;
  char_u *ptr_end = line;
  char_u *ptr_row_offset = line;  // Where we begin adjusting `ptr_end`

  // Find the offset where scanning should begin.
  int offset = wp->w_leftcol;
  if (row > 0) {
    offset += row * (wp->w_width - win_col_off(wp) - win_col_off2(wp) -
                     wp->w_leftcol + wp->w_skipcol);
  }

  int vcol;

  if (offset) {
    // Skip everything up to an offset since nvim takes care of displaying the
    // correct portion of the line when horizontally scrolling.
    // When 'wrap' is enabled, only the row (of the wrapped line) needs to be
    // checked for concealed characters.
    vcol = 0;
    while (vcol < offset && *ptr != NUL) {
      vcol += chartabsize(ptr, vcol);
      ptr += utfc_ptr2len(ptr);
    }

    ptr_row_offset = ptr;
  }

  // Align `ptr_end` with `col`
  vcol = offset;
  ptr_end = ptr_row_offset;
  while (vcol < col && *ptr_end != NUL) {
    vcol += chartabsize(ptr_end, vcol);
    ptr_end += utfc_ptr2len(ptr_end);
  }

  int matchid;
  int prev_matchid;
  int nudge = 0;
  int cwidth = 0;

  vcol = offset;

#define incr() nudge++; ptr_end += utfc_ptr2len(ptr_end)
#define decr() nudge--; ptr_end -= utfc_ptr2len(ptr_end)

  while (ptr < ptr_end && *ptr != NUL) {
    cwidth = chartabsize(ptr, vcol);
    vcol += cwidth;
    if (cwidth > 1 && *ptr == '\t' && nudge > 0) {
      // A tab will "absorb" any previous adjustments.
      cwidth = MIN(cwidth, nudge);
      while (cwidth > 0) {
        decr();
        cwidth--;
      }
    }

    matchid = syn_get_concealed_id(wp, lnum, (colnr_T)(ptr - line));
    if (matchid != 0) {
      if (wp->w_p_cole == 3) {
        incr();
      } else {
        if (!(row > 0 && ptr == ptr_row_offset)
            && (wp->w_p_cole == 1 || (wp->w_p_cole == 2
                                      && (lcs_conceal != NUL
                                          || syn_get_sub_char() != NUL)))) {
          // At least one placeholder character will be displayed.
          decr();
        }

        prev_matchid = matchid;

        while (prev_matchid == matchid && *ptr != NUL) {
          incr();
          ptr += utfc_ptr2len(ptr);
          matchid = syn_get_concealed_id(wp, lnum, (colnr_T)(ptr - line));
        }

        continue;
      }
    }

    ptr += utfc_ptr2len(ptr);
  }

  return col + nudge;
}