diff options
author | Josh Rahm <joshuarahm@gmail.com> | 2025-02-05 23:09:29 +0000 |
---|---|---|
committer | Josh Rahm <joshuarahm@gmail.com> | 2025-02-05 23:09:29 +0000 |
commit | d5f194ce780c95821a855aca3c19426576d28ae0 (patch) | |
tree | d45f461b19f9118ad2bb1f440a7a08973ad18832 /src/nvim/ops.c | |
parent | c5d770d311841ea5230426cc4c868e8db27300a8 (diff) | |
parent | 44740e561fc93afe3ebecfd3618bda2d2abeafb0 (diff) | |
download | rneovim-d5f194ce780c95821a855aca3c19426576d28ae0.tar.gz rneovim-d5f194ce780c95821a855aca3c19426576d28ae0.tar.bz2 rneovim-d5f194ce780c95821a855aca3c19426576d28ae0.zip |
Diffstat (limited to 'src/nvim/ops.c')
-rw-r--r-- | src/nvim/ops.c | 188 |
1 files changed, 153 insertions, 35 deletions
diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 7dd3f665ba..2f45d862c3 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -29,6 +29,7 @@ #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/userfunc.h" +#include "nvim/eval/typval_defs.h" #include "nvim/ex_cmds2.h" #include "nvim/ex_cmds_defs.h" #include "nvim/ex_getln.h" @@ -41,7 +42,6 @@ #include "nvim/getchar_defs.h" #include "nvim/gettext_defs.h" #include "nvim/globals.h" -#include "nvim/highlight.h" #include "nvim/highlight_defs.h" #include "nvim/indent.h" #include "nvim/indent_c.h" @@ -49,6 +49,7 @@ #include "nvim/macros_defs.h" #include "nvim/mark.h" #include "nvim/mark_defs.h" +#include "nvim/math.h" #include "nvim/mbyte.h" #include "nvim/mbyte_defs.h" #include "nvim/memline.h" @@ -78,6 +79,7 @@ #include "nvim/vim_defs.h" #include "nvim/window.h" #include "nvim/yankmap.h" +#include "nvim/window.h" struct yank_registers { yankmap_T inner; @@ -274,7 +276,7 @@ void op_shift(oparg_T *oap, bool curs_top, int amount) vim_snprintf(IObuff, IOSIZE, NGETTEXT(msg_line_single, msg_line_plural, oap->line_count), (int64_t)oap->line_count, op, amount); - msg_hl_keep(IObuff, 0, true, false); + msg_keep(IObuff, 0, true, false); } if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0) { @@ -290,21 +292,53 @@ void op_shift(oparg_T *oap, bool curs_top, int amount) changed_lines(curbuf, oap->start.lnum, 0, oap->end.lnum + 1, 0, true); } -/// Shift the current line one shiftwidth left (if left != 0) or right -/// leaves cursor on first blank in the line. -/// -/// @param call_changed_bytes call changed_bytes() -void shift_line(bool left, bool round, int amount, int call_changed_bytes) +/// Return the tabstop width at the index of the variable tabstop array. If an +/// index greater than the length of the array is given, the last tabstop width +/// in the array is returned. +static int get_vts(const int *vts_array, int index) { - int sw_val = get_sw_value_indent(curbuf, left); - if (sw_val == 0) { - sw_val = 1; // shouldn't happen, just in case + int ts; + + if (index < 1) { + ts = 0; + } else if (index <= vts_array[0]) { + ts = vts_array[index]; + } else { + ts = vts_array[vts_array[0]]; + } + + return ts; +} + +/// Return the sum of all the tabstops through the index-th. +static int get_vts_sum(const int *vts_array, int index) +{ + int sum = 0; + int i; + + // Perform the summation for indeces within the actual array. + for (i = 1; i <= index && i <= vts_array[0]; i++) { + sum += vts_array[i]; } - int count = get_indent(); // get current indent + + // Add topstops whose indeces exceed the actual array. + if (i <= index) { + sum += vts_array[vts_array[0]] * (index - vts_array[0]); + } + + return sum; +} + +/// @param left true if shift is to the left +/// @param count true if new indent is to be to a tabstop +/// @param amount number of shifts +static int64_t get_new_sw_indent(bool left, bool round, int64_t amount, int64_t sw_val) +{ + int64_t count = get_indent(); // get current indent if (round) { // round off indent - int i = count / sw_val; // number of 'shiftwidth' rounded down - int j = count % sw_val; // extra spaces + int64_t i = trim_to_int(count / sw_val); // number of 'shiftwidth' rounded down + int64_t j = trim_to_int(count % sw_val); // extra spaces if (j && left) { // first remove extra spaces amount--; } @@ -322,11 +356,94 @@ void shift_line(bool left, bool round, int amount, int call_changed_bytes) } } + return count; +} + +/// @param left true if shift is to the left +/// @param count true if new indent is to be to a tabstop +/// @param amount number of shifts +static int64_t get_new_vts_indent(bool left, bool round, int amount, int *vts_array) +{ + int64_t indent = get_indent(); + int vtsi = 0; + int vts_indent = 0; + int ts = 0; // Silence uninitialized variable warning. + + // Find the tabstop at or to the left of the current indent. + while (vts_indent <= indent) { + vtsi++; + ts = get_vts(vts_array, vtsi); + vts_indent += ts; + } + vts_indent -= ts; + vtsi--; + + // Extra indent spaces to the right of the tabstop + int64_t offset = indent - vts_indent; + + if (round) { + if (left) { + if (offset == 0) { + indent = get_vts_sum(vts_array, vtsi - amount); + } else { + indent = get_vts_sum(vts_array, vtsi - (amount - 1)); + } + } else { + indent = get_vts_sum(vts_array, vtsi + amount); + } + } else { + if (left) { + if (amount > vtsi) { + indent = 0; + } else { + indent = get_vts_sum(vts_array, vtsi - amount) + offset; + } + } else { + indent = get_vts_sum(vts_array, vtsi + amount) + offset; + } + } + + return indent; +} + +/// Shift the current line 'amount' shiftwidth(s) left (if 'left' is true) or +/// right. +/// +/// The rules for choosing a shiftwidth are: If 'shiftwidth' is non-zero, use +/// 'shiftwidth'; else if 'vartabstop' is not empty, use 'vartabstop'; else use +/// 'tabstop'. The Vim documentation says nothing about 'softtabstop' or +/// 'varsofttabstop' affecting the shiftwidth, and neither affects the +/// shiftwidth in current versions of Vim, so they are not considered here. +/// +/// @param left true if shift is to the left +/// @param count true if new indent is to be to a tabstop +/// @param amount number of shifts +/// @param call_changed_bytes call changed_bytes() +void shift_line(bool left, bool round, int amount, int call_changed_bytes) +{ + int64_t count; + int64_t sw_val = curbuf->b_p_sw; + int64_t ts_val = curbuf->b_p_ts; + int *vts_array = curbuf->b_p_vts_array; + + if (sw_val != 0) { + // 'shiftwidth' is not zero; use it as the shift size. + count = get_new_sw_indent(left, round, amount, sw_val); + } else if ((vts_array == NULL) || (vts_array[0] == 0)) { + // 'shiftwidth' is zero and 'vartabstop' is empty; use 'tabstop' as the + // shift size. + count = get_new_sw_indent(left, round, amount, ts_val); + } else { + // 'shiftwidth' is zero and 'vartabstop' is defined; use 'vartabstop' + // to determine the new indent. + count = get_new_vts_indent(left, round, amount, vts_array); + } + // Set new indent if (State & VREPLACE_FLAG) { - change_indent(INDENT_SET, count, false, call_changed_bytes); + change_indent(INDENT_SET, trim_to_int(count), false, call_changed_bytes); } else { - set_indent(count, call_changed_bytes ? SIN_CHANGED : 0); + set_indent(trim_to_int(count), call_changed_bytes ? SIN_CHANGED : 0); } } @@ -2468,7 +2585,7 @@ void op_insert(oparg_T *oap, int count1) if (u_save_cursor() == FAIL) { return; } - curwin->w_ve_flags = VE_ALL; + curwin->w_ve_flags = kOptVeFlagAll; coladvance_force(oap->op_type == OP_APPEND ? oap->end_vcol + 1 : getviscol()); if (oap->op_type == OP_APPEND) { @@ -3231,7 +3348,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) eol = (*(cursor_pos + utfc_ptr2len(cursor_pos)) == NUL); } - bool ve_allows = (cur_ve_flags == VE_ALL || cur_ve_flags == VE_ONEMORE); + bool ve_allows = (cur_ve_flags == kOptVeFlagAll || cur_ve_flags == kOptVeFlagOnemore); bool eof = curbuf->b_ml.ml_line_count == curwin->w_cursor.lnum && one_past_line; if (ve_allows || !(eol || eof)) { @@ -3419,7 +3536,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) goto end; } - if (cur_ve_flags == VE_ALL && y_type == kMTCharWise) { + if (cur_ve_flags == kOptVeFlagAll && y_type == kMTCharWise) { if (gchar_cursor() == TAB) { int viscol = getviscol(); OptInt ts = curbuf->b_p_ts; @@ -3448,7 +3565,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) colnr_T endcol2 = 0; if (dir == FORWARD && c != NUL) { - if (cur_ve_flags == VE_ALL) { + if (cur_ve_flags == kOptVeFlagAll) { getvcol(curwin, &curwin->w_cursor, &col, NULL, &endcol2); } else { getvcol(curwin, &curwin->w_cursor, NULL, NULL, &col); @@ -3462,7 +3579,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) } col += curwin->w_cursor.coladd; - if (cur_ve_flags == VE_ALL + if (cur_ve_flags == kOptVeFlagAll && (curwin->w_cursor.coladd > 0 || endcol2 == curwin->w_cursor.col)) { if (dir == FORWARD && c == NUL) { col++; @@ -3922,7 +4039,7 @@ error: // Make sure the cursor is not after the NUL. int len = get_cursor_line_len(); if (curwin->w_cursor.col > len) { - if (cur_ve_flags == VE_ALL) { + if (cur_ve_flags == kOptVeFlagAll) { curwin->w_cursor.coladd = curwin->w_cursor.col - len; } curwin->w_cursor.col = len; @@ -3958,7 +4075,7 @@ void adjust_cursor_eol(void) const bool adj_cursor = (curwin->w_cursor.col > 0 && gchar_cursor() == NUL - && (cur_ve_flags & VE_ONEMORE) == 0 + && (cur_ve_flags & kOptVeFlagOnemore) == 0 && !(restart_edit || (State & MODE_INSERT))); if (!adj_cursor) { return; @@ -3967,7 +4084,7 @@ void adjust_cursor_eol(void) // Put the cursor on the last character in the line. dec_cursor(); - if (cur_ve_flags == VE_ALL) { + if (cur_ve_flags == kOptVeFlagAll) { colnr_T scol, ecol; // Coladd is set to the width of the last character. @@ -4596,6 +4713,7 @@ void charwise_block_prep(pos_T start, pos_T end, struct block_def *bdp, linenr_T colnr_T endcol = MAXCOL; colnr_T cs, ce; char *p = ml_get(lnum); + int plen = ml_get_len(lnum); bdp->startspaces = 0; bdp->endspaces = 0; @@ -4645,7 +4763,7 @@ void charwise_block_prep(pos_T start, pos_T end, struct block_def *bdp, linenr_T bdp->textlen = endcol - startcol + inclusive; } bdp->textcol = startcol; - bdp->textstart = p + startcol; + bdp->textstart = startcol <= plen ? p + startcol : p; } /// Handle the add/subtract operator. @@ -6446,7 +6564,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) case OP_DELETE: VIsual_reselect = false; // don't reselect now if (empty_region_error) { - vim_beep(BO_OPER); + vim_beep(kOptBoFlagOperator); CancelRedo(); } else { op_delete(oap); @@ -6462,7 +6580,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) case OP_YANK: if (empty_region_error) { if (!gui_yank) { - vim_beep(BO_OPER); + vim_beep(kOptBoFlagOperator); CancelRedo(); } } else { @@ -6476,7 +6594,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) case OP_CHANGE: VIsual_reselect = false; // don't reselect now if (empty_region_error) { - vim_beep(BO_OPER); + vim_beep(kOptBoFlagOperator); CancelRedo(); } else { // This is a new edit command, not a restart. Need to @@ -6539,7 +6657,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) case OP_LOWER: case OP_ROT13: if (empty_region_error) { - vim_beep(BO_OPER); + vim_beep(kOptBoFlagOperator); CancelRedo(); } else { op_tilde(oap); @@ -6581,7 +6699,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) case OP_APPEND: VIsual_reselect = false; // don't reselect now if (empty_region_error) { - vim_beep(BO_OPER); + vim_beep(kOptBoFlagOperator); CancelRedo(); } else { // This is a new edit command, not a restart. Need to @@ -6616,7 +6734,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) case OP_REPLACE: VIsual_reselect = false; // don't reselect now if (empty_region_error) { - vim_beep(BO_OPER); + vim_beep(kOptBoFlagOperator); CancelRedo(); } else { // Restore linebreak, so that when the user edits it looks as before. @@ -6654,7 +6772,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) case OP_NR_ADD: case OP_NR_SUB: if (empty_region_error) { - vim_beep(BO_OPER); + vim_beep(kOptBoFlagOperator); CancelRedo(); } else { VIsual_active = true; @@ -6714,7 +6832,7 @@ static yankreg_T *adjust_clipboard_name(int *name, bool quiet, bool writing) yankreg_T *target = NULL; bool explicit_cb_reg = (*name == '*' || *name == '+'); - bool implicit_cb_reg = (*name == NUL) && (cb_flags & CB_UNNAMEDMASK); + bool implicit_cb_reg = (*name == NUL) && (cb_flags & (kOptCbFlagUnnamed | kOptCbFlagUnnamedplus)); if (!explicit_cb_reg && !implicit_cb_reg) { goto end; } @@ -6733,7 +6851,7 @@ static yankreg_T *adjust_clipboard_name(int *name, bool quiet, bool writing) if (explicit_cb_reg) { target = get_global_reg(*name == '*' ? STAR_REGISTER : PLUS_REGISTER); - if (writing && (cb_flags & (*name == '*' ? CB_UNNAMED : CB_UNNAMEDPLUS))) { + if (writing && (cb_flags & (*name == '*' ? kOptCbFlagUnnamed : kOptCbFlagUnnamedplus))) { clipboard_needs_update = false; } goto end; @@ -6747,8 +6865,8 @@ static yankreg_T *adjust_clipboard_name(int *name, bool quiet, bool writing) goto end; } - if (cb_flags & CB_UNNAMEDPLUS) { - *name = (cb_flags & CB_UNNAMED && writing) ? '"' : '+'; + if (cb_flags & kOptCbFlagUnnamedplus) { + *name = (cb_flags & kOptCbFlagUnnamed && writing) ? '"' : '+'; target = get_global_reg(PLUS_REGISTER); } else { *name = '*'; |