aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/ops.c
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2025-02-05 23:09:29 +0000
committerJosh Rahm <joshuarahm@gmail.com>2025-02-05 23:09:29 +0000
commitd5f194ce780c95821a855aca3c19426576d28ae0 (patch)
treed45f461b19f9118ad2bb1f440a7a08973ad18832 /src/nvim/ops.c
parentc5d770d311841ea5230426cc4c868e8db27300a8 (diff)
parent44740e561fc93afe3ebecfd3618bda2d2abeafb0 (diff)
downloadrneovim-rahm.tar.gz
rneovim-rahm.tar.bz2
rneovim-rahm.zip
Merge remote-tracking branch 'upstream/master' into mix_20240309HEADrahm
Diffstat (limited to 'src/nvim/ops.c')
-rw-r--r--src/nvim/ops.c188
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 = '*';