diff options
Diffstat (limited to 'src/nvim/ex_cmds.c')
-rw-r--r-- | src/nvim/ex_cmds.c | 113 |
1 files changed, 80 insertions, 33 deletions
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 854faf5377..349c7d6280 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -358,6 +358,7 @@ static int linelen(int *has_tab) static char_u *sortbuf1; static char_u *sortbuf2; +static int sort_lc; ///< sort using locale static int sort_ic; ///< ignore case static int sort_nr; ///< sort on number static int sort_rx; ///< sort on regex instead of skipping it @@ -381,6 +382,13 @@ typedef struct { } st_u; } sorti_T; +static int string_compare(const void *s1, const void *s2) FUNC_ATTR_NONNULL_ALL +{ + if (sort_lc) { + return strcoll((char *)s1, (char *)s2); + } + return sort_ic ? STRICMP(s1, s2) : STRCMP(s1, s2); +} static int sort_compare(const void *s1, const void *s2) { @@ -424,8 +432,7 @@ static int sort_compare(const void *s1, const void *s2) l2.st_u.line.end_col_nr - l2.st_u.line.start_col_nr + 1); sortbuf2[l2.st_u.line.end_col_nr - l2.st_u.line.start_col_nr] = NUL; - result = sort_ic ? STRICMP(sortbuf1, sortbuf2) - : STRCMP(sortbuf1, sortbuf2); + result = string_compare(sortbuf1, sortbuf2); } /* If two lines have the same value, preserve the original line order. */ @@ -466,7 +473,7 @@ void ex_sort(exarg_T *eap) regmatch.regprog = NULL; sorti_T *nrs = xmalloc(count * sizeof(sorti_T)); - sort_abort = sort_ic = sort_rx = sort_nr = sort_flt = 0; + sort_abort = sort_ic = sort_lc = sort_rx = sort_nr = sort_flt = 0; size_t format_found = 0; bool change_occurred = false; // Buffer contents changed. @@ -474,6 +481,8 @@ void ex_sort(exarg_T *eap) if (ascii_iswhite(*p)) { } else if (*p == 'i') { sort_ic = true; + } else if (*p == 'l') { + sort_lc = true; } else if (*p == 'r') { sort_rx = true; } else if (*p == 'n') { @@ -645,8 +654,7 @@ void ex_sort(exarg_T *eap) s = ml_get(get_lnum); size_t bytelen = STRLEN(s) + 1; // include EOL in bytelen old_count += bytelen; - if (!unique || i == 0 - || (sort_ic ? STRICMP(s, sortbuf1) : STRCMP(s, sortbuf1)) != 0) { + if (!unique || i == 0 || string_compare(s, sortbuf1) != 0) { // Copy the line into a buffer, it may become invalid in // ml_append(). And it's needed for "unique". STRCPY(sortbuf1, s); @@ -712,14 +720,15 @@ void ex_retab(exarg_T *eap) long len; long col; long vcol; - long start_col = 0; /* For start of white-space string */ - long start_vcol = 0; /* For start of white-space string */ - int temp; + long start_col = 0; // For start of white-space string + long start_vcol = 0; // For start of white-space string long old_len; char_u *ptr; - char_u *new_line = (char_u *)1; /* init to non-NULL */ - int did_undo; /* called u_save for current line */ - int new_ts; + char_u *new_line = (char_u *)1; // init to non-NULL + int did_undo; // called u_save for current line + long *new_vts_array = NULL; + char_u *new_ts_str; // string value of tab argument + int save_list; linenr_T first_line = 0; /* first changed line */ linenr_T last_line = 0; /* last changed line */ @@ -727,14 +736,24 @@ void ex_retab(exarg_T *eap) save_list = curwin->w_p_list; curwin->w_p_list = 0; /* don't want list mode here */ - new_ts = getdigits_int(&(eap->arg), false, -1); - if (new_ts < 0) { - EMSG(_(e_positive)); + new_ts_str = eap->arg; + if (!tabstop_set(eap->arg, &new_vts_array)) { return; } - if (new_ts == 0) - new_ts = curbuf->b_p_ts; - for (lnum = eap->line1; !got_int && lnum <= eap->line2; ++lnum) { + while (ascii_isdigit(*(eap->arg)) || *(eap->arg) == ',') { + (eap->arg)++; + } + + // This ensures that either new_vts_array and new_ts_str are freshly + // allocated, or new_vts_array points to an existing array and new_ts_str + // is null. + if (new_vts_array == NULL) { + new_vts_array = curbuf->b_p_vts_array; + new_ts_str = NULL; + } else { + new_ts_str = vim_strnsave(new_ts_str, eap->arg - new_ts_str); + } + for (lnum = eap->line1; !got_int && lnum <= eap->line2; lnum++) { ptr = ml_get(lnum); col = 0; vcol = 0; @@ -758,13 +777,12 @@ void ex_retab(exarg_T *eap) len = num_spaces = vcol - start_vcol; num_tabs = 0; if (!curbuf->b_p_et) { - temp = new_ts - (start_vcol % new_ts); - if (num_spaces >= temp) { - num_spaces -= temp; - num_tabs++; - } - num_tabs += num_spaces / new_ts; - num_spaces -= (num_spaces / new_ts) * new_ts; + int t, s; + + tabstop_fromto(start_vcol, vcol, + curbuf->b_p_ts, new_vts_array, &t, &s); + num_tabs = t; + num_spaces = s; } if (curbuf->b_p_et || got_tab || (num_spaces + num_tabs < len)) { @@ -780,7 +798,8 @@ void ex_retab(exarg_T *eap) /* len is actual number of white characters used */ len = num_spaces + num_tabs; old_len = (long)STRLEN(ptr); - new_line = xmalloc(old_len - col + start_col + len + 1); + long new_len = old_len - col + start_col + len + 1; + new_line = xmalloc(new_len); if (start_col > 0) memmove(new_line, ptr, (size_t)start_col); @@ -793,6 +812,8 @@ void ex_retab(exarg_T *eap) if (ml_replace(lnum, new_line, false) == OK) { // "new_line" may have been copied new_line = curbuf->b_ml.ml_line_ptr; + extmark_splice_cols(curbuf, lnum - 1, 0, (colnr_T)old_len, + (colnr_T)new_len - 1, kExtmarkUndo); } if (first_line == 0) { first_line = lnum; @@ -817,15 +838,42 @@ void ex_retab(exarg_T *eap) if (got_int) EMSG(_(e_interr)); - if (curbuf->b_p_ts != new_ts) + // If a single value was given then it can be considered equal to + // either the value of 'tabstop' or the value of 'vartabstop'. + if (tabstop_count(curbuf->b_p_vts_array) == 0 + && tabstop_count(new_vts_array) == 1 + && curbuf->b_p_ts == tabstop_first(new_vts_array)) { + // not changed + } else if (tabstop_count(curbuf->b_p_vts_array) > 0 + && tabstop_eq(curbuf->b_p_vts_array, new_vts_array)) { + // not changed + } else { redraw_curbuf_later(NOT_VALID); + } if (first_line != 0) { changed_lines(first_line, 0, last_line + 1, 0L, true); } curwin->w_p_list = save_list; /* restore 'list' */ - curbuf->b_p_ts = new_ts; + if (new_ts_str != NULL) { // set the new tabstop + // If 'vartabstop' is in use or if the value given to retab has more + // than one tabstop then update 'vartabstop'. + long *old_vts_ary = curbuf->b_p_vts_array; + + if (tabstop_count(old_vts_ary) > 0 || tabstop_count(new_vts_array) > 1) { + set_string_option_direct("vts", -1, new_ts_str, + OPT_FREE | OPT_LOCAL, 0); + curbuf->b_p_vts_array = new_vts_array; + xfree(old_vts_ary); + } else { + // 'vartabstop' wasn't in use and a single value was given to + // retab then update 'tabstop'. + curbuf->b_p_ts = tabstop_first(new_vts_array); + xfree(new_vts_array); + } + xfree(new_ts_str); + } coladvance(curwin->w_curswant); u_clearline(); @@ -928,12 +976,6 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest) mark_adjust_nofold(last_line - num_lines + 1, last_line, -(last_line - dest - extra), 0L, kExtmarkNOOP); - // extmarks are handled separately - extmark_move_region(curbuf, line1-1, 0, start_byte, - line2-line1+1, 0, extent_byte, - dest+line_off, 0, dest_byte+byte_off, - kExtmarkUndo); - changed_lines(last_line - num_lines + 1, 0, last_line + 1, -extra, false); // send update regarding the new lines that were added @@ -955,6 +997,11 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest) smsg(_("%" PRId64 " lines moved"), (int64_t)num_lines); } + extmark_move_region(curbuf, line1-1, 0, start_byte, + line2-line1+1, 0, extent_byte, + dest+line_off, 0, dest_byte+byte_off, + kExtmarkUndo); + /* * Leave the cursor on the last of the moved lines. */ |