mirror of
https://github.com/neovim/neovim.git
synced 2026-04-05 07:09:23 +00:00
Merge pull request #34894 from janlazo/vim-8.1.0857
vim-patch:8.1.{770,857,914,977,1004,1526,1551,1565,1584,1629,1641,1703,1728,1730,1736,1802,1853,1891,2127,2200},8.2.3922,9.0.{546,928},9.1.1382
This commit is contained in:
@@ -2116,7 +2116,6 @@ text...
|
||||
# Number
|
||||
* Funcref
|
||||
|
||||
|
||||
:unl[et][!] {name} ... *:unlet* *:unl* *E108* *E795*
|
||||
Remove the internal variable {name}. Several variable
|
||||
names can be given, they are all removed. The name
|
||||
|
||||
@@ -727,6 +727,19 @@ v:version
|
||||
:if has("nvim-0.2.1")
|
||||
<
|
||||
|
||||
*v:versionlong* *versionlong-variable*
|
||||
v:versionlong
|
||||
Like v:version, but also including the patchlevel in the last
|
||||
four digits. Version 8.1 with patch 123 has value 8010123.
|
||||
This can be used like this: >
|
||||
if v:versionlong >= 8010123
|
||||
<
|
||||
However, if there are gaps in the list of patches included
|
||||
this will not work well. This can happen if a recent patch
|
||||
was included into an older version, e.g. for a security fix.
|
||||
Use the has() function to make sure the patch is actually
|
||||
included.
|
||||
|
||||
*v:vim_did_enter* *vim_did_enter-variable*
|
||||
v:vim_did_enter
|
||||
0 during startup, 1 just before |VimEnter|.
|
||||
|
||||
15
runtime/lua/vim/_meta/vvars.lua
generated
15
runtime/lua/vim/_meta/vvars.lua
generated
@@ -772,6 +772,21 @@ vim.v.val = ...
|
||||
--- @type integer
|
||||
vim.v.version = ...
|
||||
|
||||
--- Like v:version, but also including the patchlevel in the last
|
||||
--- four digits. Version 8.1 with patch 123 has value 8010123.
|
||||
--- This can be used like this:
|
||||
--- ```
|
||||
--- if v:versionlong >= 8010123
|
||||
--- ```
|
||||
---
|
||||
--- However, if there are gaps in the list of patches included
|
||||
--- this will not work well. This can happen if a recent patch
|
||||
--- was included into an older version, e.g. for a security fix.
|
||||
--- Use the has() function to make sure the patch is actually
|
||||
--- included.
|
||||
--- @type integer
|
||||
vim.v.versionlong = ...
|
||||
|
||||
--- 0 during startup, 1 just before `VimEnter`.
|
||||
--- Read-only.
|
||||
--- @type integer
|
||||
|
||||
@@ -1566,7 +1566,7 @@ bool has_event(event_T event) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
|
||||
/// Return true when there is a CursorHold/CursorHoldI autocommand defined for
|
||||
/// the current mode.
|
||||
bool has_cursorhold(void) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
static bool has_cursorhold(void) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
{
|
||||
return has_event((get_real_state() == MODE_NORMAL_BUSY ? EVENT_CURSORHOLD : EVENT_CURSORHOLDI));
|
||||
}
|
||||
|
||||
@@ -1683,7 +1683,7 @@ void set_curbuf(buf_T *buf, int action, bool update_jumplist)
|
||||
/// Enter a new current buffer.
|
||||
/// Old curbuf must have been abandoned already! This also means "curbuf" may
|
||||
/// be pointing to freed memory.
|
||||
void enter_buffer(buf_T *buf)
|
||||
static void enter_buffer(buf_T *buf)
|
||||
{
|
||||
// when closing the current buffer stop Visual mode
|
||||
if (VIsual_active
|
||||
@@ -2207,7 +2207,7 @@ int buflist_getfile(int n, linenr_T lnum, int options, int forceit)
|
||||
}
|
||||
|
||||
/// Go to the last known line number for the current buffer.
|
||||
void buflist_getfpos(void)
|
||||
static void buflist_getfpos(void)
|
||||
{
|
||||
pos_T *fpos = &buflist_findfmark(curbuf)->mark;
|
||||
|
||||
|
||||
@@ -957,118 +957,6 @@ int del_bytes(colnr_T count, bool fixpos_arg, bool use_delcombine)
|
||||
return OK;
|
||||
}
|
||||
|
||||
/// Copy the indent from ptr to the current line (and fill to size).
|
||||
/// Leaves the cursor on the first non-blank in the line.
|
||||
///
|
||||
/// @return true if the line was changed.
|
||||
bool copy_indent(int size, char *src)
|
||||
{
|
||||
char *p = NULL;
|
||||
char *line = NULL;
|
||||
int ind_len;
|
||||
int line_len = 0;
|
||||
int tab_pad;
|
||||
|
||||
// Round 1: compute the number of characters needed for the indent
|
||||
// Round 2: copy the characters.
|
||||
for (int round = 1; round <= 2; round++) {
|
||||
int todo = size;
|
||||
ind_len = 0;
|
||||
int ind_done = 0;
|
||||
int ind_col = 0;
|
||||
char *s = src;
|
||||
|
||||
// Count/copy the usable portion of the source line.
|
||||
while (todo > 0 && ascii_iswhite(*s)) {
|
||||
if (*s == TAB) {
|
||||
tab_pad = tabstop_padding(ind_done,
|
||||
curbuf->b_p_ts,
|
||||
curbuf->b_p_vts_array);
|
||||
|
||||
// Stop if this tab will overshoot the target.
|
||||
if (todo < tab_pad) {
|
||||
break;
|
||||
}
|
||||
todo -= tab_pad;
|
||||
ind_done += tab_pad;
|
||||
ind_col += tab_pad;
|
||||
} else {
|
||||
todo--;
|
||||
ind_done++;
|
||||
ind_col++;
|
||||
}
|
||||
ind_len++;
|
||||
|
||||
if (p != NULL) {
|
||||
*p++ = *s;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
|
||||
// Fill to next tabstop with a tab, if possible.
|
||||
tab_pad = tabstop_padding(ind_done, curbuf->b_p_ts, curbuf->b_p_vts_array);
|
||||
|
||||
if ((todo >= tab_pad) && !curbuf->b_p_et) {
|
||||
todo -= tab_pad;
|
||||
ind_len++;
|
||||
ind_col += tab_pad;
|
||||
|
||||
if (p != NULL) {
|
||||
*p++ = TAB;
|
||||
}
|
||||
}
|
||||
|
||||
// Add tabs required for indent.
|
||||
if (!curbuf->b_p_et) {
|
||||
while (true) {
|
||||
tab_pad = tabstop_padding(ind_col,
|
||||
curbuf->b_p_ts,
|
||||
curbuf->b_p_vts_array);
|
||||
if (todo < tab_pad) {
|
||||
break;
|
||||
}
|
||||
todo -= tab_pad;
|
||||
ind_len++;
|
||||
ind_col += tab_pad;
|
||||
if (p != NULL) {
|
||||
*p++ = TAB;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Count/add spaces required for indent.
|
||||
while (todo > 0) {
|
||||
todo--;
|
||||
ind_len++;
|
||||
|
||||
if (p != NULL) {
|
||||
*p++ = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
if (p == NULL) {
|
||||
// Allocate memory for the result: the copied indent, new indent
|
||||
// and the rest of the line.
|
||||
line_len = get_cursor_line_len() + 1;
|
||||
assert(ind_len + line_len >= 0);
|
||||
size_t line_size;
|
||||
STRICT_ADD(ind_len, line_len, &line_size, size_t);
|
||||
line = xmalloc(line_size);
|
||||
p = line;
|
||||
}
|
||||
}
|
||||
|
||||
// Append the original line
|
||||
memmove(p, get_cursor_line_ptr(), (size_t)line_len);
|
||||
|
||||
// Replace the line
|
||||
ml_replace(curwin->w_cursor.lnum, line, false);
|
||||
|
||||
// Put the cursor after the indent.
|
||||
curwin->w_cursor.col = ind_len;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// open_line: Add a new line below or above the current line.
|
||||
///
|
||||
/// For MODE_VREPLACE state, we only add a new line when we get to the end of
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "nvim/errors.h"
|
||||
#include "nvim/eval.h"
|
||||
#include "nvim/eval/encode.h"
|
||||
#include "nvim/eval/funcs.h"
|
||||
#include "nvim/eval/typval.h"
|
||||
#include "nvim/event/loop.h"
|
||||
#include "nvim/event/multiqueue.h"
|
||||
@@ -24,6 +25,7 @@
|
||||
#include "nvim/event/rstream.h"
|
||||
#include "nvim/event/socket.h"
|
||||
#include "nvim/event/wstream.h"
|
||||
#include "nvim/ex_cmds.h"
|
||||
#include "nvim/garray.h"
|
||||
#include "nvim/gettext_defs.h"
|
||||
#include "nvim/globals.h"
|
||||
@@ -1001,3 +1003,65 @@ Array channel_all_info(Arena *arena)
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// "prompt_setcallback({buffer}, {callback})" function
|
||||
void f_prompt_setcallback(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
Callback prompt_callback = { .type = kCallbackNone };
|
||||
|
||||
if (check_secure()) {
|
||||
return;
|
||||
}
|
||||
buf_T *buf = tv_get_buf(&argvars[0], false);
|
||||
if (buf == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (argvars[1].v_type != VAR_STRING || *argvars[1].vval.v_string != NUL) {
|
||||
if (!callback_from_typval(&prompt_callback, &argvars[1])) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
callback_free(&buf->b_prompt_callback);
|
||||
buf->b_prompt_callback = prompt_callback;
|
||||
}
|
||||
|
||||
/// "prompt_setinterrupt({buffer}, {callback})" function
|
||||
void f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
Callback interrupt_callback = { .type = kCallbackNone };
|
||||
|
||||
if (check_secure()) {
|
||||
return;
|
||||
}
|
||||
buf_T *buf = tv_get_buf(&argvars[0], false);
|
||||
if (buf == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (argvars[1].v_type != VAR_STRING || *argvars[1].vval.v_string != NUL) {
|
||||
if (!callback_from_typval(&interrupt_callback, &argvars[1])) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
callback_free(&buf->b_prompt_interrupt);
|
||||
buf->b_prompt_interrupt = interrupt_callback;
|
||||
}
|
||||
|
||||
/// "prompt_setprompt({buffer}, {text})" function
|
||||
void f_prompt_setprompt(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
if (check_secure()) {
|
||||
return;
|
||||
}
|
||||
buf_T *buf = tv_get_buf(&argvars[0], false);
|
||||
if (buf == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
const char *text = tv_get_string(&argvars[1]);
|
||||
xfree(buf->b_prompt_text);
|
||||
buf->b_prompt_text = xstrdup(text);
|
||||
}
|
||||
|
||||
@@ -1791,7 +1791,7 @@ void digraph_getlist_common(bool list_all, typval_T *rettv)
|
||||
}
|
||||
}
|
||||
|
||||
struct dg_header_entry {
|
||||
static struct dg_header_entry {
|
||||
int dg_start;
|
||||
const char *dg_header;
|
||||
} header_table[] = {
|
||||
|
||||
501
src/nvim/edit.c
501
src/nvim/edit.c
@@ -1636,204 +1636,6 @@ void undisplay_dollar(void)
|
||||
redrawWinline(curwin, curwin->w_cursor.lnum);
|
||||
}
|
||||
|
||||
/// Insert an indent (for <Tab> or CTRL-T) or delete an indent (for CTRL-D).
|
||||
/// Keep the cursor on the same character.
|
||||
/// type == INDENT_INC increase indent (for CTRL-T or <Tab>)
|
||||
/// type == INDENT_DEC decrease indent (for CTRL-D)
|
||||
/// type == INDENT_SET set indent to "amount"
|
||||
///
|
||||
/// @param round if true, round the indent to 'shiftwidth' (only with _INC and _Dec).
|
||||
/// @param call_changed_bytes call changed_bytes()
|
||||
void change_indent(int type, int amount, int round, bool call_changed_bytes)
|
||||
{
|
||||
int insstart_less; // reduction for Insstart.col
|
||||
colnr_T orig_col = 0; // init for GCC
|
||||
char *orig_line = NULL; // init for GCC
|
||||
|
||||
// MODE_VREPLACE state needs to know what the line was like before changing
|
||||
if (State & VREPLACE_FLAG) {
|
||||
orig_line = xstrnsave(get_cursor_line_ptr(), (size_t)get_cursor_line_len());
|
||||
orig_col = curwin->w_cursor.col;
|
||||
}
|
||||
|
||||
// for the following tricks we don't want list mode
|
||||
int save_p_list = curwin->w_p_list;
|
||||
curwin->w_p_list = false;
|
||||
colnr_T vc = getvcol_nolist(&curwin->w_cursor);
|
||||
int vcol = vc;
|
||||
|
||||
// For Replace mode we need to fix the replace stack later, which is only
|
||||
// possible when the cursor is in the indent. Remember the number of
|
||||
// characters before the cursor if it's possible.
|
||||
int start_col = curwin->w_cursor.col;
|
||||
|
||||
// determine offset from first non-blank
|
||||
int new_cursor_col = curwin->w_cursor.col;
|
||||
beginline(BL_WHITE);
|
||||
new_cursor_col -= curwin->w_cursor.col;
|
||||
|
||||
insstart_less = curwin->w_cursor.col;
|
||||
|
||||
// If the cursor is in the indent, compute how many screen columns the
|
||||
// cursor is to the left of the first non-blank.
|
||||
if (new_cursor_col < 0) {
|
||||
vcol = get_indent() - vcol;
|
||||
}
|
||||
|
||||
if (new_cursor_col > 0) { // can't fix replace stack
|
||||
start_col = -1;
|
||||
}
|
||||
|
||||
// Set the new indent. The cursor will be put on the first non-blank.
|
||||
if (type == INDENT_SET) {
|
||||
set_indent(amount, call_changed_bytes ? SIN_CHANGED : 0);
|
||||
} else {
|
||||
int save_State = State;
|
||||
|
||||
// Avoid being called recursively.
|
||||
if (State & VREPLACE_FLAG) {
|
||||
State = MODE_INSERT;
|
||||
}
|
||||
shift_line(type == INDENT_DEC, round, 1, call_changed_bytes);
|
||||
State = save_State;
|
||||
}
|
||||
insstart_less -= curwin->w_cursor.col;
|
||||
|
||||
// Try to put cursor on same character.
|
||||
// If the cursor is at or after the first non-blank in the line,
|
||||
// compute the cursor column relative to the column of the first
|
||||
// non-blank character.
|
||||
// If we are not in insert mode, leave the cursor on the first non-blank.
|
||||
// If the cursor is before the first non-blank, position it relative
|
||||
// to the first non-blank, counted in screen columns.
|
||||
if (new_cursor_col >= 0) {
|
||||
// When changing the indent while the cursor is touching it, reset
|
||||
// Insstart_col to 0.
|
||||
if (new_cursor_col == 0) {
|
||||
insstart_less = MAXCOL;
|
||||
}
|
||||
new_cursor_col += curwin->w_cursor.col;
|
||||
} else if (!(State & MODE_INSERT)) {
|
||||
new_cursor_col = curwin->w_cursor.col;
|
||||
} else {
|
||||
// Compute the screen column where the cursor should be.
|
||||
vcol = get_indent() - vcol;
|
||||
int const end_vcol = (colnr_T)((vcol < 0) ? 0 : vcol);
|
||||
curwin->w_virtcol = end_vcol;
|
||||
|
||||
// Advance the cursor until we reach the right screen column.
|
||||
new_cursor_col = 0;
|
||||
char *const line = get_cursor_line_ptr();
|
||||
vcol = 0;
|
||||
if (*line != NUL) {
|
||||
CharsizeArg csarg;
|
||||
CSType cstype = init_charsize_arg(&csarg, curwin, 0, line);
|
||||
StrCharInfo ci = utf_ptr2StrCharInfo(line);
|
||||
while (true) {
|
||||
int next_vcol = vcol + win_charsize(cstype, vcol, ci.ptr, ci.chr.value, &csarg).width;
|
||||
if (next_vcol > end_vcol) {
|
||||
break;
|
||||
}
|
||||
vcol = next_vcol;
|
||||
ci = utfc_next(ci);
|
||||
if (*ci.ptr == NUL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
new_cursor_col = (int)(ci.ptr - line);
|
||||
}
|
||||
|
||||
// May need to insert spaces to be able to position the cursor on
|
||||
// the right screen column.
|
||||
if (vcol != (int)curwin->w_virtcol) {
|
||||
curwin->w_cursor.col = (colnr_T)new_cursor_col;
|
||||
const size_t ptrlen = (size_t)(curwin->w_virtcol - vcol);
|
||||
char *ptr = xmallocz(ptrlen);
|
||||
memset(ptr, ' ', ptrlen);
|
||||
new_cursor_col += (int)ptrlen;
|
||||
ins_str(ptr, ptrlen);
|
||||
xfree(ptr);
|
||||
}
|
||||
|
||||
// When changing the indent while the cursor is in it, reset
|
||||
// Insstart_col to 0.
|
||||
insstart_less = MAXCOL;
|
||||
}
|
||||
|
||||
curwin->w_p_list = save_p_list;
|
||||
curwin->w_cursor.col = MAX(0, (colnr_T)new_cursor_col);
|
||||
curwin->w_set_curswant = true;
|
||||
changed_cline_bef_curs(curwin);
|
||||
|
||||
// May have to adjust the start of the insert.
|
||||
if (State & MODE_INSERT) {
|
||||
if (curwin->w_cursor.lnum == Insstart.lnum && Insstart.col != 0) {
|
||||
if ((int)Insstart.col <= insstart_less) {
|
||||
Insstart.col = 0;
|
||||
} else {
|
||||
Insstart.col -= insstart_less;
|
||||
}
|
||||
}
|
||||
if ((int)ai_col <= insstart_less) {
|
||||
ai_col = 0;
|
||||
} else {
|
||||
ai_col -= insstart_less;
|
||||
}
|
||||
}
|
||||
|
||||
// For MODE_REPLACE state, may have to fix the replace stack, if it's
|
||||
// possible. If the number of characters before the cursor decreased, need
|
||||
// to pop a few characters from the replace stack.
|
||||
// If the number of characters before the cursor increased, need to push a
|
||||
// few NULs onto the replace stack.
|
||||
if (REPLACE_NORMAL(State) && start_col >= 0) {
|
||||
while (start_col > (int)curwin->w_cursor.col) {
|
||||
replace_join(0); // remove a NUL from the replace stack
|
||||
start_col--;
|
||||
}
|
||||
while (start_col < (int)curwin->w_cursor.col) {
|
||||
replace_push_nul();
|
||||
start_col++;
|
||||
}
|
||||
}
|
||||
|
||||
// For MODE_VREPLACE state, we also have to fix the replace stack. In this
|
||||
// case it is always possible because we backspace over the whole line and
|
||||
// then put it back again the way we wanted it.
|
||||
if (State & VREPLACE_FLAG) {
|
||||
// Save new line
|
||||
char *new_line = xstrnsave(get_cursor_line_ptr(), (size_t)get_cursor_line_len());
|
||||
|
||||
// We only put back the new line up to the cursor
|
||||
new_line[curwin->w_cursor.col] = NUL;
|
||||
int new_col = curwin->w_cursor.col;
|
||||
|
||||
// Put back original line
|
||||
ml_replace(curwin->w_cursor.lnum, orig_line, false);
|
||||
curwin->w_cursor.col = orig_col;
|
||||
|
||||
curbuf_splice_pending++;
|
||||
|
||||
// Backspace from cursor to start of line
|
||||
backspace_until_column(0);
|
||||
|
||||
// Insert new stuff into line again
|
||||
ins_bytes(new_line);
|
||||
|
||||
xfree(new_line);
|
||||
|
||||
curbuf_splice_pending--;
|
||||
|
||||
// TODO(bfredl): test for crazy edge cases, like we stand on a TAB or
|
||||
// something? does this even do the right text change then?
|
||||
int delta = orig_col - new_col;
|
||||
extmark_splice_cols(curbuf, (int)curwin->w_cursor.lnum - 1, new_col,
|
||||
delta < 0 ? -delta : 0,
|
||||
delta > 0 ? delta : 0,
|
||||
kExtmarkUndo);
|
||||
}
|
||||
}
|
||||
|
||||
/// Truncate the space at the end of a line. This is to be used only in an
|
||||
/// insert mode. It handles fixing the replace stack for MODE_REPLACE and
|
||||
/// MODE_VREPLACE modes.
|
||||
@@ -2885,7 +2687,7 @@ static int replace_pop_if_nul(void)
|
||||
/// encountered.
|
||||
///
|
||||
/// @param off offset for which NUL to remove
|
||||
static void replace_join(int off)
|
||||
void replace_join(int off)
|
||||
{
|
||||
for (ssize_t i = (ssize_t)kv_size(replace_stack); --i >= 0;) {
|
||||
if (kv_A(replace_stack, i) == NUL && off-- <= 0) {
|
||||
@@ -2978,233 +2780,6 @@ static void replace_do_bs(int limit_col)
|
||||
}
|
||||
}
|
||||
|
||||
/// Check that C-indenting is on.
|
||||
bool cindent_on(void)
|
||||
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
{
|
||||
return !p_paste && (curbuf->b_p_cin || *curbuf->b_p_inde != NUL);
|
||||
}
|
||||
|
||||
/// Check that "cinkeys" contains the key "keytyped",
|
||||
/// when == '*': Only if key is preceded with '*' (indent before insert)
|
||||
/// when == '!': Only if key is preceded with '!' (don't insert)
|
||||
/// when == ' ': Only if key is not preceded with '*' or '!' (indent afterwards)
|
||||
///
|
||||
/// "keytyped" can have a few special values:
|
||||
/// KEY_OPEN_FORW :
|
||||
/// KEY_OPEN_BACK :
|
||||
/// KEY_COMPLETE : Just finished completion.
|
||||
///
|
||||
/// @param keytyped key that was typed
|
||||
/// @param when condition on when to perform the check
|
||||
/// @param line_is_empty when true, accept keys with '0' before them.
|
||||
bool in_cinkeys(int keytyped, int when, bool line_is_empty)
|
||||
{
|
||||
char *look;
|
||||
bool try_match;
|
||||
bool try_match_word;
|
||||
char *p;
|
||||
bool icase;
|
||||
|
||||
if (keytyped == NUL) {
|
||||
// Can happen with CTRL-Y and CTRL-E on a short line.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (*curbuf->b_p_inde != NUL) {
|
||||
look = curbuf->b_p_indk; // 'indentexpr' set: use 'indentkeys'
|
||||
} else {
|
||||
look = curbuf->b_p_cink; // 'indentexpr' empty: use 'cinkeys'
|
||||
}
|
||||
while (*look) {
|
||||
// Find out if we want to try a match with this key, depending on
|
||||
// 'when' and a '*' or '!' before the key.
|
||||
switch (when) {
|
||||
case '*':
|
||||
try_match = (*look == '*'); break;
|
||||
case '!':
|
||||
try_match = (*look == '!'); break;
|
||||
default:
|
||||
try_match = (*look != '*') && (*look != '!'); break;
|
||||
}
|
||||
if (*look == '*' || *look == '!') {
|
||||
look++;
|
||||
}
|
||||
|
||||
// If there is a '0', only accept a match if the line is empty.
|
||||
// But may still match when typing last char of a word.
|
||||
if (*look == '0') {
|
||||
try_match_word = try_match;
|
||||
if (!line_is_empty) {
|
||||
try_match = false;
|
||||
}
|
||||
look++;
|
||||
} else {
|
||||
try_match_word = false;
|
||||
}
|
||||
|
||||
// Does it look like a control character?
|
||||
if (*look == '^' && look[1] >= '?' && look[1] <= '_') {
|
||||
if (try_match && keytyped == CTRL_CHR(look[1])) {
|
||||
return true;
|
||||
}
|
||||
look += 2;
|
||||
|
||||
// 'o' means "o" command, open forward.
|
||||
// 'O' means "O" command, open backward.
|
||||
} else if (*look == 'o') {
|
||||
if (try_match && keytyped == KEY_OPEN_FORW) {
|
||||
return true;
|
||||
}
|
||||
look++;
|
||||
} else if (*look == 'O') {
|
||||
if (try_match && keytyped == KEY_OPEN_BACK) {
|
||||
return true;
|
||||
}
|
||||
look++;
|
||||
|
||||
// 'e' means to check for "else" at start of line and just before the
|
||||
// cursor.
|
||||
} else if (*look == 'e') {
|
||||
if (try_match && keytyped == 'e' && curwin->w_cursor.col >= 4) {
|
||||
p = get_cursor_line_ptr();
|
||||
if (skipwhite(p) == p + curwin->w_cursor.col - 4
|
||||
&& strncmp(p + curwin->w_cursor.col - 4, "else", 4) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
look++;
|
||||
|
||||
// ':' only causes an indent if it is at the end of a label or case
|
||||
// statement, or when it was before typing the ':' (to fix
|
||||
// class::method for C++).
|
||||
} else if (*look == ':') {
|
||||
if (try_match && keytyped == ':') {
|
||||
p = get_cursor_line_ptr();
|
||||
if (cin_iscase(p, false) || cin_isscopedecl(p) || cin_islabel()) {
|
||||
return true;
|
||||
}
|
||||
// Need to get the line again after cin_islabel().
|
||||
p = get_cursor_line_ptr();
|
||||
if (curwin->w_cursor.col > 2
|
||||
&& p[curwin->w_cursor.col - 1] == ':'
|
||||
&& p[curwin->w_cursor.col - 2] == ':') {
|
||||
p[curwin->w_cursor.col - 1] = ' ';
|
||||
const bool i = cin_iscase(p, false)
|
||||
|| cin_isscopedecl(p)
|
||||
|| cin_islabel();
|
||||
p = get_cursor_line_ptr();
|
||||
p[curwin->w_cursor.col - 1] = ':';
|
||||
if (i) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
look++;
|
||||
|
||||
// Is it a key in <>, maybe?
|
||||
} else if (*look == '<') {
|
||||
if (try_match) {
|
||||
// make up some named keys <o>, <O>, <e>, <0>, <>>, <<>, <*>,
|
||||
// <:> and <!> so that people can re-indent on o, O, e, 0, <,
|
||||
// >, *, : and ! keys if they really really want to.
|
||||
if (vim_strchr("<>!*oOe0:", (uint8_t)look[1]) != NULL
|
||||
&& keytyped == look[1]) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (keytyped == get_special_key_code(look + 1)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
while (*look && *look != '>') {
|
||||
look++;
|
||||
}
|
||||
while (*look == '>') {
|
||||
look++;
|
||||
}
|
||||
// Is it a word: "=word"?
|
||||
} else if (*look == '=' && look[1] != ',' && look[1] != NUL) {
|
||||
look++;
|
||||
if (*look == '~') {
|
||||
icase = true;
|
||||
look++;
|
||||
} else {
|
||||
icase = false;
|
||||
}
|
||||
p = vim_strchr(look, ',');
|
||||
if (p == NULL) {
|
||||
p = look + strlen(look);
|
||||
}
|
||||
if ((try_match || try_match_word)
|
||||
&& curwin->w_cursor.col >= (colnr_T)(p - look)) {
|
||||
bool match = false;
|
||||
|
||||
if (keytyped == KEY_COMPLETE) {
|
||||
char *n, *s;
|
||||
|
||||
// Just completed a word, check if it starts with "look".
|
||||
// search back for the start of a word.
|
||||
char *line = get_cursor_line_ptr();
|
||||
for (s = line + curwin->w_cursor.col; s > line; s = n) {
|
||||
n = mb_prevptr(line, s);
|
||||
if (!vim_iswordp(n)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(p >= look && (uintmax_t)(p - look) <= SIZE_MAX);
|
||||
if (s + (p - look) <= line + curwin->w_cursor.col
|
||||
&& (icase
|
||||
? mb_strnicmp(s, look, (size_t)(p - look))
|
||||
: strncmp(s, look, (size_t)(p - look))) == 0) {
|
||||
match = true;
|
||||
}
|
||||
} else {
|
||||
// TODO(@brammool): multi-byte
|
||||
if (keytyped == (int)(uint8_t)p[-1]
|
||||
|| (icase && keytyped < 256 && keytyped >= 0
|
||||
&& TOLOWER_LOC(keytyped) == TOLOWER_LOC((uint8_t)p[-1]))) {
|
||||
char *line = get_cursor_pos_ptr();
|
||||
assert(p >= look && (uintmax_t)(p - look) <= SIZE_MAX);
|
||||
if ((curwin->w_cursor.col == (colnr_T)(p - look)
|
||||
|| !vim_iswordc((uint8_t)line[-(p - look) - 1]))
|
||||
&& (icase
|
||||
? mb_strnicmp(line - (p - look), look, (size_t)(p - look))
|
||||
: strncmp(line - (p - look), look, (size_t)(p - look))) == 0) {
|
||||
match = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (match && try_match_word && !try_match) {
|
||||
// "0=word": Check if there are only blanks before the
|
||||
// word.
|
||||
if (getwhitecols_curline() !=
|
||||
(int)(curwin->w_cursor.col - (p - look))) {
|
||||
match = false;
|
||||
}
|
||||
}
|
||||
if (match) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
look = p;
|
||||
|
||||
// Ok, it's a boring generic character.
|
||||
} else {
|
||||
if (try_match && (uint8_t)(*look) == keytyped) {
|
||||
return true;
|
||||
}
|
||||
if (*look != NUL) {
|
||||
look++;
|
||||
}
|
||||
}
|
||||
|
||||
// Skip over ", ".
|
||||
look = skip_to_option_part(look);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void ins_reg(void)
|
||||
{
|
||||
bool need_redraw = false;
|
||||
@@ -4630,80 +4205,6 @@ static int ins_ctrl_ey(int tc)
|
||||
return c;
|
||||
}
|
||||
|
||||
// Try to do some very smart auto-indenting.
|
||||
// Used when inserting a "normal" character.
|
||||
static void ins_try_si(int c)
|
||||
{
|
||||
pos_T *pos;
|
||||
|
||||
// do some very smart indenting when entering '{' or '}'
|
||||
if (((did_si || can_si_back) && c == '{') || (can_si && c == '}' && inindent(0))) {
|
||||
pos_T old_pos;
|
||||
char *ptr;
|
||||
int i;
|
||||
bool temp;
|
||||
// for '}' set indent equal to indent of line containing matching '{'
|
||||
if (c == '}' && (pos = findmatch(NULL, '{')) != NULL) {
|
||||
old_pos = curwin->w_cursor;
|
||||
// If the matching '{' has a ')' immediately before it (ignoring
|
||||
// white-space), then line up with the start of the line
|
||||
// containing the matching '(' if there is one. This handles the
|
||||
// case where an "if (..\n..) {" statement continues over multiple
|
||||
// lines -- webb
|
||||
ptr = ml_get(pos->lnum);
|
||||
i = pos->col;
|
||||
if (i > 0) { // skip blanks before '{'
|
||||
while (--i > 0 && ascii_iswhite(ptr[i])) {}
|
||||
}
|
||||
curwin->w_cursor.lnum = pos->lnum;
|
||||
curwin->w_cursor.col = i;
|
||||
if (ptr[i] == ')' && (pos = findmatch(NULL, '(')) != NULL) {
|
||||
curwin->w_cursor = *pos;
|
||||
}
|
||||
i = get_indent();
|
||||
curwin->w_cursor = old_pos;
|
||||
if (State & VREPLACE_FLAG) {
|
||||
change_indent(INDENT_SET, i, false, true);
|
||||
} else {
|
||||
set_indent(i, SIN_CHANGED);
|
||||
}
|
||||
} else if (curwin->w_cursor.col > 0) {
|
||||
// when inserting '{' after "O" reduce indent, but not
|
||||
// more than indent of previous line
|
||||
temp = true;
|
||||
if (c == '{' && can_si_back && curwin->w_cursor.lnum > 1) {
|
||||
old_pos = curwin->w_cursor;
|
||||
i = get_indent();
|
||||
while (curwin->w_cursor.lnum > 1) {
|
||||
ptr = skipwhite(ml_get(--(curwin->w_cursor.lnum)));
|
||||
|
||||
// ignore empty lines and lines starting with '#'.
|
||||
if (*ptr != '#' && *ptr != NUL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (get_indent() >= i) {
|
||||
temp = false;
|
||||
}
|
||||
curwin->w_cursor = old_pos;
|
||||
}
|
||||
if (temp) {
|
||||
shift_line(true, false, 1, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set indent of '#' always to 0
|
||||
if (curwin->w_cursor.col > 0 && can_si && c == '#' && inindent(0)) {
|
||||
// remember current indent for next line
|
||||
old_indent = get_indent();
|
||||
set_indent(0, SIN_CHANGED);
|
||||
}
|
||||
|
||||
// Adjust ai_col, the char at this position can be deleted.
|
||||
ai_col = MIN(ai_col, curwin->w_cursor.col);
|
||||
}
|
||||
|
||||
// Get the value that w_virtcol would have when 'list' is off.
|
||||
// Unless 'cpo' contains the 'L' flag.
|
||||
colnr_T get_nolist_virtcol(void)
|
||||
|
||||
@@ -266,6 +266,7 @@ static struct vimvar {
|
||||
VV(VV_TYPE_BOOL, "t_bool", VAR_NUMBER, VV_RO),
|
||||
VV(VV_TYPE_BLOB, "t_blob", VAR_NUMBER, VV_RO),
|
||||
VV(VV_EVENT, "event", VAR_DICT, VV_RO),
|
||||
VV(VV_VERSIONLONG, "versionlong", VAR_NUMBER, VV_RO),
|
||||
VV(VV_ECHOSPACE, "echospace", VAR_NUMBER, VV_RO),
|
||||
VV(VV_ARGV, "argv", VAR_LIST, VV_RO),
|
||||
VV(VV_COLLATE, "collate", VAR_STRING, VV_RO),
|
||||
@@ -433,6 +434,7 @@ void eval_init(void)
|
||||
}
|
||||
}
|
||||
vimvars[VV_VERSION].vv_nr = VIM_VERSION_100;
|
||||
vimvars[VV_VERSIONLONG].vv_nr = VIM_VERSION_100 * 10000 + highest_patch();
|
||||
|
||||
dict_T *const msgpack_types_dict = tv_dict_alloc();
|
||||
for (size_t i = 0; i < ARRAY_SIZE(msgpack_type_names); i++) {
|
||||
|
||||
@@ -162,6 +162,7 @@ typedef enum {
|
||||
VV_TYPE_BOOL,
|
||||
VV_TYPE_BLOB,
|
||||
VV_EVENT,
|
||||
VV_VERSIONLONG,
|
||||
VV_ECHOSPACE,
|
||||
VV_ARGV,
|
||||
VV_COLLATE,
|
||||
|
||||
@@ -706,27 +706,3 @@ void restore_buffer(bufref_T *save_curbuf)
|
||||
curbuf->b_nwindows++;
|
||||
}
|
||||
}
|
||||
|
||||
/// Find a window for buffer "buf".
|
||||
/// If found true is returned and "wp" and "tp" are set to
|
||||
/// the window and tabpage.
|
||||
/// If not found, false is returned.
|
||||
///
|
||||
/// @param buf buffer to find a window for
|
||||
/// @param[out] wp stores the found window
|
||||
/// @param[out] tp stores the found tabpage
|
||||
///
|
||||
/// @return true if a window was found for the buffer.
|
||||
bool find_win_for_buf(buf_T *buf, win_T **wp, tabpage_T **tp)
|
||||
{
|
||||
*wp = NULL;
|
||||
*tp = NULL;
|
||||
FOR_ALL_TAB_WINDOWS(tp2, wp2) {
|
||||
if (wp2->w_buffer == buf) {
|
||||
*tp = tp2;
|
||||
*wp = wp2;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -777,20 +777,6 @@ static void f_charcol(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
get_col(argvars, rettv, true);
|
||||
}
|
||||
|
||||
/// "cindent(lnum)" function
|
||||
static void f_cindent(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
pos_T pos = curwin->w_cursor;
|
||||
linenr_T lnum = tv_get_lnum(argvars);
|
||||
if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) {
|
||||
curwin->w_cursor.lnum = lnum;
|
||||
rettv->vval.v_number = get_c_indent();
|
||||
curwin->w_cursor = pos;
|
||||
} else {
|
||||
rettv->vval.v_number = -1;
|
||||
}
|
||||
}
|
||||
|
||||
win_T *get_optional_window(typval_T *argvars, int idx)
|
||||
{
|
||||
if (argvars[idx].v_type == VAR_UNKNOWN) {
|
||||
@@ -3246,17 +3232,6 @@ static void f_hostname(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
rettv->vval.v_string = xstrdup(hostname);
|
||||
}
|
||||
|
||||
/// "indent()" function
|
||||
static void f_indent(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
const linenr_T lnum = tv_get_lnum(argvars);
|
||||
if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) {
|
||||
rettv->vval.v_number = get_indent_lnum(lnum);
|
||||
} else {
|
||||
rettv->vval.v_number = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/// "index()" function
|
||||
static void f_index(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
@@ -4415,20 +4390,6 @@ static void f_line2byte(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
}
|
||||
}
|
||||
|
||||
/// "lispindent(lnum)" function
|
||||
static void f_lispindent(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
const pos_T pos = curwin->w_cursor;
|
||||
const linenr_T lnum = tv_get_lnum(argvars);
|
||||
if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) {
|
||||
curwin->w_cursor.lnum = lnum;
|
||||
rettv->vval.v_number = get_lisp_indent();
|
||||
curwin->w_cursor = pos;
|
||||
} else {
|
||||
rettv->vval.v_number = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/// "localtime()" function
|
||||
static void f_localtime(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
@@ -5280,52 +5241,6 @@ static void f_printf(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
}
|
||||
}
|
||||
|
||||
/// "prompt_setcallback({buffer}, {callback})" function
|
||||
static void f_prompt_setcallback(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
Callback prompt_callback = { .type = kCallbackNone };
|
||||
|
||||
if (check_secure()) {
|
||||
return;
|
||||
}
|
||||
buf_T *buf = tv_get_buf(&argvars[0], false);
|
||||
if (buf == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (argvars[1].v_type != VAR_STRING || *argvars[1].vval.v_string != NUL) {
|
||||
if (!callback_from_typval(&prompt_callback, &argvars[1])) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
callback_free(&buf->b_prompt_callback);
|
||||
buf->b_prompt_callback = prompt_callback;
|
||||
}
|
||||
|
||||
/// "prompt_setinterrupt({buffer}, {callback})" function
|
||||
static void f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
Callback interrupt_callback = { .type = kCallbackNone };
|
||||
|
||||
if (check_secure()) {
|
||||
return;
|
||||
}
|
||||
buf_T *buf = tv_get_buf(&argvars[0], false);
|
||||
if (buf == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (argvars[1].v_type != VAR_STRING || *argvars[1].vval.v_string != NUL) {
|
||||
if (!callback_from_typval(&interrupt_callback, &argvars[1])) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
callback_free(&buf->b_prompt_interrupt);
|
||||
buf->b_prompt_interrupt = interrupt_callback;
|
||||
}
|
||||
|
||||
/// "prompt_getprompt({buffer})" function
|
||||
static void f_prompt_getprompt(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
@@ -5346,22 +5261,6 @@ static void f_prompt_getprompt(typval_T *argvars, typval_T *rettv, EvalFuncData
|
||||
rettv->vval.v_string = xstrdup(buf_prompt_text(buf));
|
||||
}
|
||||
|
||||
/// "prompt_setprompt({buffer}, {text})" function
|
||||
static void f_prompt_setprompt(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
if (check_secure()) {
|
||||
return;
|
||||
}
|
||||
buf_T *buf = tv_get_buf(&argvars[0], false);
|
||||
if (buf == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
const char *text = tv_get_string(&argvars[1]);
|
||||
xfree(buf->b_prompt_text);
|
||||
buf->b_prompt_text = xstrdup(text);
|
||||
}
|
||||
|
||||
/// "prompt_getinput({buffer})" function
|
||||
static void f_prompt_getinput(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
|
||||
@@ -190,7 +190,7 @@ void tv_list_watch_remove(list_T *const l, listwatch_T *const lwrem)
|
||||
///
|
||||
/// @param[out] l List from which item is removed.
|
||||
/// @param[in] item List item being removed.
|
||||
void tv_list_watch_fix(list_T *const l, const listitem_T *const item)
|
||||
static void tv_list_watch_fix(list_T *const l, const listitem_T *const item)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
for (listwatch_T *lw = l->lv_watch; lw != NULL; lw = lw->lw_next) {
|
||||
|
||||
@@ -2144,7 +2144,7 @@ void do_wqall(exarg_T *eap)
|
||||
/// Check the 'write' option.
|
||||
///
|
||||
/// @return true and give a message when it's not st.
|
||||
bool not_writing(void)
|
||||
static bool not_writing(void)
|
||||
{
|
||||
if (p_write) {
|
||||
return false;
|
||||
|
||||
@@ -799,7 +799,7 @@ void report_make_pending(int pending, void *value)
|
||||
|
||||
/// If something pending in a finally clause is resumed at the ":endtry", report
|
||||
/// it if required by the 'verbose' option or when debugging.
|
||||
void report_resume_pending(int pending, void *value)
|
||||
static void report_resume_pending(int pending, void *value)
|
||||
{
|
||||
if (p_verbose >= 14 || debug_break_level > 0) {
|
||||
if (debug_break_level <= 0) {
|
||||
@@ -814,7 +814,7 @@ void report_resume_pending(int pending, void *value)
|
||||
|
||||
/// If something pending in a finally clause is discarded, report it if required
|
||||
/// by the 'verbose' option or when debugging.
|
||||
void report_discard_pending(int pending, void *value)
|
||||
static void report_discard_pending(int pending, void *value)
|
||||
{
|
||||
if (p_verbose >= 14 || debug_break_level > 0) {
|
||||
if (debug_break_level <= 0) {
|
||||
|
||||
@@ -1031,7 +1031,7 @@ fail:
|
||||
|
||||
/// Free the list of lists of visited files and directories
|
||||
/// Can handle it if the passed search_context is NULL;
|
||||
void vim_findfile_free_visited(void *search_ctx_arg)
|
||||
static void vim_findfile_free_visited(void *search_ctx_arg)
|
||||
{
|
||||
if (search_ctx_arg == NULL) {
|
||||
return;
|
||||
|
||||
@@ -2049,20 +2049,6 @@ static char *readfile_charconvert(char *fname, char *fenc, int *fdp)
|
||||
return tmpname;
|
||||
}
|
||||
|
||||
/// Read marks for the current buffer from the ShaDa file, when we support
|
||||
/// buffer marks and the buffer has a name.
|
||||
static void check_marks_read(void)
|
||||
{
|
||||
if (!curbuf->b_marks_read && get_shada_parameter('\'') > 0
|
||||
&& curbuf->b_ffname != NULL) {
|
||||
shada_read_marks();
|
||||
}
|
||||
|
||||
// Always set b_marks_read; needed when 'shada' is changed to include
|
||||
// the ' parameter after opening a buffer.
|
||||
curbuf->b_marks_read = true;
|
||||
}
|
||||
|
||||
/// Set the name of the current buffer. Use when the buffer doesn't have a
|
||||
/// name and a ":r" or ":w" command with a file name is used.
|
||||
int set_rw_fname(char *fname, char *sfname)
|
||||
|
||||
@@ -1282,7 +1282,7 @@ void may_sync_undo(void)
|
||||
}
|
||||
|
||||
/// Make "typebuf" empty and allocate new buffers.
|
||||
void alloc_typebuf(void)
|
||||
static void alloc_typebuf(void)
|
||||
{
|
||||
typebuf.tb_buf = xmalloc(TYPELEN_INIT);
|
||||
typebuf.tb_noremap = xmalloc(TYPELEN_INIT);
|
||||
@@ -1298,7 +1298,7 @@ void alloc_typebuf(void)
|
||||
}
|
||||
|
||||
/// Free the buffers of "typebuf".
|
||||
void free_typebuf(void)
|
||||
static void free_typebuf(void)
|
||||
{
|
||||
if (typebuf.tb_buf == typebuf_init) {
|
||||
internal_error("Free typebuf 1");
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "nvim/edit.h"
|
||||
#include "nvim/errors.h"
|
||||
#include "nvim/eval.h"
|
||||
#include "nvim/eval/typval.h"
|
||||
#include "nvim/eval/typval_defs.h"
|
||||
#include "nvim/ex_cmds_defs.h"
|
||||
#include "nvim/ex_docmd.h"
|
||||
@@ -31,6 +32,7 @@
|
||||
#include "nvim/memory.h"
|
||||
#include "nvim/message.h"
|
||||
#include "nvim/move.h"
|
||||
#include "nvim/ops.h"
|
||||
#include "nvim/option.h"
|
||||
#include "nvim/option_defs.h"
|
||||
#include "nvim/option_vars.h"
|
||||
@@ -276,7 +278,7 @@ void tabstop_fromto(colnr_T start_col, colnr_T end_col, int ts_arg, const colnr_
|
||||
}
|
||||
|
||||
/// See if two tabstop arrays contain the same values.
|
||||
bool tabstop_eq(const colnr_T *ts1, const colnr_T *ts2)
|
||||
static bool tabstop_eq(const colnr_T *ts1, const colnr_T *ts2)
|
||||
{
|
||||
if ((ts1 == 0 && ts2) || (ts1 && ts2 == 0)) {
|
||||
return false;
|
||||
@@ -333,7 +335,7 @@ int get_sw_value(buf_T *buf)
|
||||
}
|
||||
|
||||
/// Idem, using "pos".
|
||||
int get_sw_value_pos(buf_T *buf, pos_T *pos, bool left)
|
||||
static int get_sw_value_pos(buf_T *buf, pos_T *pos, bool left)
|
||||
{
|
||||
pos_T save_cursor = curwin->w_cursor;
|
||||
|
||||
@@ -977,12 +979,482 @@ bool inindent(int extra)
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Handle reindenting a block of lines.
|
||||
void op_reindent(oparg_T *oap, Indenter how)
|
||||
{
|
||||
int i = 0;
|
||||
linenr_T first_changed = 0;
|
||||
linenr_T last_changed = 0;
|
||||
linenr_T start_lnum = curwin->w_cursor.lnum;
|
||||
|
||||
// Don't even try when 'modifiable' is off.
|
||||
if (!MODIFIABLE(curbuf)) {
|
||||
emsg(_(e_modifiable));
|
||||
return;
|
||||
}
|
||||
|
||||
// Save for undo. Do this once for all lines, much faster than doing this
|
||||
// for each line separately, especially when undoing.
|
||||
if (u_savecommon(curbuf, start_lnum - 1, start_lnum + oap->line_count,
|
||||
start_lnum + oap->line_count, false) == OK) {
|
||||
int amount;
|
||||
for (i = oap->line_count - 1; i >= 0 && !got_int; i--) {
|
||||
// it's a slow thing to do, so give feedback so there's no worry
|
||||
// that the computer's just hung.
|
||||
|
||||
if (i > 1
|
||||
&& (i % 50 == 0 || i == oap->line_count - 1)
|
||||
&& oap->line_count > p_report) {
|
||||
smsg(0, _("%" PRId64 " lines to indent... "), (int64_t)i);
|
||||
}
|
||||
|
||||
// Be vi-compatible: For lisp indenting the first line is not
|
||||
// indented, unless there is only one line.
|
||||
if (i != oap->line_count - 1 || oap->line_count == 1
|
||||
|| how != get_lisp_indent) {
|
||||
char *l = skipwhite(get_cursor_line_ptr());
|
||||
if (*l == NUL) { // empty or blank line
|
||||
amount = 0;
|
||||
} else {
|
||||
amount = how(); // get the indent for this line
|
||||
}
|
||||
if (amount >= 0 && set_indent(amount, 0)) {
|
||||
// did change the indent, call changed_lines() later
|
||||
if (first_changed == 0) {
|
||||
first_changed = curwin->w_cursor.lnum;
|
||||
}
|
||||
last_changed = curwin->w_cursor.lnum;
|
||||
}
|
||||
}
|
||||
curwin->w_cursor.lnum++;
|
||||
curwin->w_cursor.col = 0; // make sure it's valid
|
||||
}
|
||||
}
|
||||
|
||||
// put cursor on first non-blank of indented line
|
||||
curwin->w_cursor.lnum = start_lnum;
|
||||
beginline(BL_SOL | BL_FIX);
|
||||
|
||||
// Mark changed lines so that they will be redrawn. When Visual
|
||||
// highlighting was present, need to continue until the last line. When
|
||||
// there is no change still need to remove the Visual highlighting.
|
||||
if (last_changed != 0) {
|
||||
changed_lines(curbuf, first_changed, 0,
|
||||
oap->is_VIsual ? start_lnum + oap->line_count
|
||||
: last_changed + 1, 0, true);
|
||||
} else if (oap->is_VIsual) {
|
||||
redraw_curbuf_later(UPD_INVERTED);
|
||||
}
|
||||
|
||||
if (oap->line_count > p_report) {
|
||||
i = oap->line_count - (i + 1);
|
||||
smsg(0, NGETTEXT("%" PRId64 " line indented ", "%" PRId64 " lines indented ", i), (int64_t)i);
|
||||
}
|
||||
if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0) {
|
||||
// set '[ and '] marks
|
||||
curbuf->b_op_start = oap->start;
|
||||
curbuf->b_op_end = oap->end;
|
||||
}
|
||||
}
|
||||
|
||||
/// @return true if lines starting with '#' should be left aligned.
|
||||
bool preprocs_left(void)
|
||||
{
|
||||
return ((curbuf->b_p_si && !curbuf->b_p_cin)
|
||||
|| (curbuf->b_p_cin && in_cinkeys('#', ' ', true)
|
||||
&& curbuf->b_ind_hash_comment == 0));
|
||||
}
|
||||
|
||||
/// @return true if the conditions are OK for smart indenting.
|
||||
bool may_do_si(void)
|
||||
{
|
||||
return curbuf->b_p_si && !curbuf->b_p_cin && *curbuf->b_p_inde == NUL && !p_paste;
|
||||
}
|
||||
|
||||
// Try to do some very smart auto-indenting.
|
||||
// Used when inserting a "normal" character.
|
||||
void ins_try_si(int c)
|
||||
{
|
||||
pos_T *pos;
|
||||
|
||||
// do some very smart indenting when entering '{' or '}'
|
||||
if (((did_si || can_si_back) && c == '{') || (can_si && c == '}' && inindent(0))) {
|
||||
pos_T old_pos;
|
||||
char *ptr;
|
||||
int i;
|
||||
bool temp;
|
||||
// for '}' set indent equal to indent of line containing matching '{'
|
||||
if (c == '}' && (pos = findmatch(NULL, '{')) != NULL) {
|
||||
old_pos = curwin->w_cursor;
|
||||
// If the matching '{' has a ')' immediately before it (ignoring
|
||||
// white-space), then line up with the start of the line
|
||||
// containing the matching '(' if there is one. This handles the
|
||||
// case where an "if (..\n..) {" statement continues over multiple
|
||||
// lines -- webb
|
||||
ptr = ml_get(pos->lnum);
|
||||
i = pos->col;
|
||||
if (i > 0) { // skip blanks before '{'
|
||||
while (--i > 0 && ascii_iswhite(ptr[i])) {}
|
||||
}
|
||||
curwin->w_cursor.lnum = pos->lnum;
|
||||
curwin->w_cursor.col = i;
|
||||
if (ptr[i] == ')' && (pos = findmatch(NULL, '(')) != NULL) {
|
||||
curwin->w_cursor = *pos;
|
||||
}
|
||||
i = get_indent();
|
||||
curwin->w_cursor = old_pos;
|
||||
if (State & VREPLACE_FLAG) {
|
||||
change_indent(INDENT_SET, i, false, true);
|
||||
} else {
|
||||
set_indent(i, SIN_CHANGED);
|
||||
}
|
||||
} else if (curwin->w_cursor.col > 0) {
|
||||
// when inserting '{' after "O" reduce indent, but not
|
||||
// more than indent of previous line
|
||||
temp = true;
|
||||
if (c == '{' && can_si_back && curwin->w_cursor.lnum > 1) {
|
||||
old_pos = curwin->w_cursor;
|
||||
i = get_indent();
|
||||
while (curwin->w_cursor.lnum > 1) {
|
||||
ptr = skipwhite(ml_get(--(curwin->w_cursor.lnum)));
|
||||
|
||||
// ignore empty lines and lines starting with '#'.
|
||||
if (*ptr != '#' && *ptr != NUL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (get_indent() >= i) {
|
||||
temp = false;
|
||||
}
|
||||
curwin->w_cursor = old_pos;
|
||||
}
|
||||
if (temp) {
|
||||
shift_line(true, false, 1, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set indent of '#' always to 0
|
||||
if (curwin->w_cursor.col > 0 && can_si && c == '#' && inindent(0)) {
|
||||
// remember current indent for next line
|
||||
old_indent = get_indent();
|
||||
set_indent(0, SIN_CHANGED);
|
||||
}
|
||||
|
||||
// Adjust ai_col, the char at this position can be deleted.
|
||||
ai_col = MIN(ai_col, curwin->w_cursor.col);
|
||||
}
|
||||
|
||||
/// Insert an indent (for <Tab> or CTRL-T) or delete an indent (for CTRL-D).
|
||||
/// Keep the cursor on the same character.
|
||||
/// type == INDENT_INC increase indent (for CTRL-T or <Tab>)
|
||||
/// type == INDENT_DEC decrease indent (for CTRL-D)
|
||||
/// type == INDENT_SET set indent to "amount"
|
||||
///
|
||||
/// @param round if true, round the indent to 'shiftwidth' (only with _INC and _Dec).
|
||||
/// @param call_changed_bytes call changed_bytes()
|
||||
void change_indent(int type, int amount, int round, bool call_changed_bytes)
|
||||
{
|
||||
int insstart_less; // reduction for Insstart.col
|
||||
colnr_T orig_col = 0; // init for GCC
|
||||
char *orig_line = NULL; // init for GCC
|
||||
|
||||
// MODE_VREPLACE state needs to know what the line was like before changing
|
||||
if (State & VREPLACE_FLAG) {
|
||||
orig_line = xstrnsave(get_cursor_line_ptr(), (size_t)get_cursor_line_len());
|
||||
orig_col = curwin->w_cursor.col;
|
||||
}
|
||||
|
||||
// for the following tricks we don't want list mode
|
||||
int save_p_list = curwin->w_p_list;
|
||||
curwin->w_p_list = false;
|
||||
colnr_T vc = getvcol_nolist(&curwin->w_cursor);
|
||||
int vcol = vc;
|
||||
|
||||
// For Replace mode we need to fix the replace stack later, which is only
|
||||
// possible when the cursor is in the indent. Remember the number of
|
||||
// characters before the cursor if it's possible.
|
||||
int start_col = curwin->w_cursor.col;
|
||||
|
||||
// determine offset from first non-blank
|
||||
int new_cursor_col = curwin->w_cursor.col;
|
||||
beginline(BL_WHITE);
|
||||
new_cursor_col -= curwin->w_cursor.col;
|
||||
|
||||
insstart_less = curwin->w_cursor.col;
|
||||
|
||||
// If the cursor is in the indent, compute how many screen columns the
|
||||
// cursor is to the left of the first non-blank.
|
||||
if (new_cursor_col < 0) {
|
||||
vcol = get_indent() - vcol;
|
||||
}
|
||||
|
||||
if (new_cursor_col > 0) { // can't fix replace stack
|
||||
start_col = -1;
|
||||
}
|
||||
|
||||
// Set the new indent. The cursor will be put on the first non-blank.
|
||||
if (type == INDENT_SET) {
|
||||
set_indent(amount, call_changed_bytes ? SIN_CHANGED : 0);
|
||||
} else {
|
||||
int save_State = State;
|
||||
|
||||
// Avoid being called recursively.
|
||||
if (State & VREPLACE_FLAG) {
|
||||
State = MODE_INSERT;
|
||||
}
|
||||
shift_line(type == INDENT_DEC, round, 1, call_changed_bytes);
|
||||
State = save_State;
|
||||
}
|
||||
insstart_less -= curwin->w_cursor.col;
|
||||
|
||||
// Try to put cursor on same character.
|
||||
// If the cursor is at or after the first non-blank in the line,
|
||||
// compute the cursor column relative to the column of the first
|
||||
// non-blank character.
|
||||
// If we are not in insert mode, leave the cursor on the first non-blank.
|
||||
// If the cursor is before the first non-blank, position it relative
|
||||
// to the first non-blank, counted in screen columns.
|
||||
if (new_cursor_col >= 0) {
|
||||
// When changing the indent while the cursor is touching it, reset
|
||||
// Insstart_col to 0.
|
||||
if (new_cursor_col == 0) {
|
||||
insstart_less = MAXCOL;
|
||||
}
|
||||
new_cursor_col += curwin->w_cursor.col;
|
||||
} else if (!(State & MODE_INSERT)) {
|
||||
new_cursor_col = curwin->w_cursor.col;
|
||||
} else {
|
||||
// Compute the screen column where the cursor should be.
|
||||
vcol = get_indent() - vcol;
|
||||
int const end_vcol = (colnr_T)((vcol < 0) ? 0 : vcol);
|
||||
curwin->w_virtcol = end_vcol;
|
||||
|
||||
// Advance the cursor until we reach the right screen column.
|
||||
new_cursor_col = 0;
|
||||
char *const line = get_cursor_line_ptr();
|
||||
vcol = 0;
|
||||
if (*line != NUL) {
|
||||
CharsizeArg csarg;
|
||||
CSType cstype = init_charsize_arg(&csarg, curwin, 0, line);
|
||||
StrCharInfo ci = utf_ptr2StrCharInfo(line);
|
||||
while (true) {
|
||||
int next_vcol = vcol + win_charsize(cstype, vcol, ci.ptr, ci.chr.value, &csarg).width;
|
||||
if (next_vcol > end_vcol) {
|
||||
break;
|
||||
}
|
||||
vcol = next_vcol;
|
||||
ci = utfc_next(ci);
|
||||
if (*ci.ptr == NUL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
new_cursor_col = (int)(ci.ptr - line);
|
||||
}
|
||||
|
||||
// May need to insert spaces to be able to position the cursor on
|
||||
// the right screen column.
|
||||
if (vcol != (int)curwin->w_virtcol) {
|
||||
curwin->w_cursor.col = (colnr_T)new_cursor_col;
|
||||
const size_t ptrlen = (size_t)(curwin->w_virtcol - vcol);
|
||||
char *ptr = xmallocz(ptrlen);
|
||||
memset(ptr, ' ', ptrlen);
|
||||
new_cursor_col += (int)ptrlen;
|
||||
ins_str(ptr, ptrlen);
|
||||
xfree(ptr);
|
||||
}
|
||||
|
||||
// When changing the indent while the cursor is in it, reset
|
||||
// Insstart_col to 0.
|
||||
insstart_less = MAXCOL;
|
||||
}
|
||||
|
||||
curwin->w_p_list = save_p_list;
|
||||
curwin->w_cursor.col = MAX(0, (colnr_T)new_cursor_col);
|
||||
curwin->w_set_curswant = true;
|
||||
changed_cline_bef_curs(curwin);
|
||||
|
||||
// May have to adjust the start of the insert.
|
||||
if (State & MODE_INSERT) {
|
||||
if (curwin->w_cursor.lnum == Insstart.lnum && Insstart.col != 0) {
|
||||
if ((int)Insstart.col <= insstart_less) {
|
||||
Insstart.col = 0;
|
||||
} else {
|
||||
Insstart.col -= insstart_less;
|
||||
}
|
||||
}
|
||||
if ((int)ai_col <= insstart_less) {
|
||||
ai_col = 0;
|
||||
} else {
|
||||
ai_col -= insstart_less;
|
||||
}
|
||||
}
|
||||
|
||||
// For MODE_REPLACE state, may have to fix the replace stack, if it's
|
||||
// possible. If the number of characters before the cursor decreased, need
|
||||
// to pop a few characters from the replace stack.
|
||||
// If the number of characters before the cursor increased, need to push a
|
||||
// few NULs onto the replace stack.
|
||||
if (REPLACE_NORMAL(State) && start_col >= 0) {
|
||||
while (start_col > (int)curwin->w_cursor.col) {
|
||||
replace_join(0); // remove a NUL from the replace stack
|
||||
start_col--;
|
||||
}
|
||||
while (start_col < (int)curwin->w_cursor.col) {
|
||||
replace_push_nul();
|
||||
start_col++;
|
||||
}
|
||||
}
|
||||
|
||||
// For MODE_VREPLACE state, we also have to fix the replace stack. In this
|
||||
// case it is always possible because we backspace over the whole line and
|
||||
// then put it back again the way we wanted it.
|
||||
if (State & VREPLACE_FLAG) {
|
||||
// Save new line
|
||||
char *new_line = xstrnsave(get_cursor_line_ptr(), (size_t)get_cursor_line_len());
|
||||
|
||||
// We only put back the new line up to the cursor
|
||||
new_line[curwin->w_cursor.col] = NUL;
|
||||
int new_col = curwin->w_cursor.col;
|
||||
|
||||
// Put back original line
|
||||
ml_replace(curwin->w_cursor.lnum, orig_line, false);
|
||||
curwin->w_cursor.col = orig_col;
|
||||
|
||||
curbuf_splice_pending++;
|
||||
|
||||
// Backspace from cursor to start of line
|
||||
backspace_until_column(0);
|
||||
|
||||
// Insert new stuff into line again
|
||||
ins_bytes(new_line);
|
||||
|
||||
xfree(new_line);
|
||||
|
||||
curbuf_splice_pending--;
|
||||
|
||||
// TODO(bfredl): test for crazy edge cases, like we stand on a TAB or
|
||||
// something? does this even do the right text change then?
|
||||
int delta = orig_col - new_col;
|
||||
extmark_splice_cols(curbuf, (int)curwin->w_cursor.lnum - 1, new_col,
|
||||
delta < 0 ? -delta : 0,
|
||||
delta > 0 ? delta : 0,
|
||||
kExtmarkUndo);
|
||||
}
|
||||
}
|
||||
|
||||
/// Copy the indent from ptr to the current line (and fill to size).
|
||||
/// Leaves the cursor on the first non-blank in the line.
|
||||
///
|
||||
/// @return true if the line was changed.
|
||||
bool copy_indent(int size, char *src)
|
||||
{
|
||||
char *p = NULL;
|
||||
char *line = NULL;
|
||||
int ind_len;
|
||||
int line_len = 0;
|
||||
int tab_pad;
|
||||
|
||||
// Round 1: compute the number of characters needed for the indent
|
||||
// Round 2: copy the characters.
|
||||
for (int round = 1; round <= 2; round++) {
|
||||
int todo = size;
|
||||
ind_len = 0;
|
||||
int ind_done = 0;
|
||||
int ind_col = 0;
|
||||
char *s = src;
|
||||
|
||||
// Count/copy the usable portion of the source line.
|
||||
while (todo > 0 && ascii_iswhite(*s)) {
|
||||
if (*s == TAB) {
|
||||
tab_pad = tabstop_padding(ind_done,
|
||||
curbuf->b_p_ts,
|
||||
curbuf->b_p_vts_array);
|
||||
|
||||
// Stop if this tab will overshoot the target.
|
||||
if (todo < tab_pad) {
|
||||
break;
|
||||
}
|
||||
todo -= tab_pad;
|
||||
ind_done += tab_pad;
|
||||
ind_col += tab_pad;
|
||||
} else {
|
||||
todo--;
|
||||
ind_done++;
|
||||
ind_col++;
|
||||
}
|
||||
ind_len++;
|
||||
|
||||
if (p != NULL) {
|
||||
*p++ = *s;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
|
||||
// Fill to next tabstop with a tab, if possible.
|
||||
tab_pad = tabstop_padding(ind_done, curbuf->b_p_ts, curbuf->b_p_vts_array);
|
||||
|
||||
if ((todo >= tab_pad) && !curbuf->b_p_et) {
|
||||
todo -= tab_pad;
|
||||
ind_len++;
|
||||
ind_col += tab_pad;
|
||||
|
||||
if (p != NULL) {
|
||||
*p++ = TAB;
|
||||
}
|
||||
}
|
||||
|
||||
// Add tabs required for indent.
|
||||
if (!curbuf->b_p_et) {
|
||||
while (true) {
|
||||
tab_pad = tabstop_padding(ind_col,
|
||||
curbuf->b_p_ts,
|
||||
curbuf->b_p_vts_array);
|
||||
if (todo < tab_pad) {
|
||||
break;
|
||||
}
|
||||
todo -= tab_pad;
|
||||
ind_len++;
|
||||
ind_col += tab_pad;
|
||||
if (p != NULL) {
|
||||
*p++ = TAB;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Count/add spaces required for indent.
|
||||
while (todo > 0) {
|
||||
todo--;
|
||||
ind_len++;
|
||||
|
||||
if (p != NULL) {
|
||||
*p++ = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
if (p == NULL) {
|
||||
// Allocate memory for the result: the copied indent, new indent
|
||||
// and the rest of the line.
|
||||
line_len = get_cursor_line_len() + 1;
|
||||
assert(ind_len + line_len >= 0);
|
||||
size_t line_size;
|
||||
STRICT_ADD(ind_len, line_len, &line_size, size_t);
|
||||
line = xmalloc(line_size);
|
||||
p = line;
|
||||
}
|
||||
}
|
||||
|
||||
// Append the original line
|
||||
memmove(p, get_cursor_line_ptr(), (size_t)line_len);
|
||||
|
||||
// Replace the line
|
||||
ml_replace(curwin->w_cursor.lnum, line, false);
|
||||
|
||||
// Put the cursor after the indent.
|
||||
curwin->w_cursor.col = ind_len;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Give a "resulting text too long" error and maybe set got_int.
|
||||
static void emsg_text_too_long(void)
|
||||
{
|
||||
@@ -1474,3 +1946,28 @@ void fix_indent(void)
|
||||
do_c_expr_indent();
|
||||
}
|
||||
}
|
||||
|
||||
/// "indent()" function
|
||||
void f_indent(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
const linenr_T lnum = tv_get_lnum(argvars);
|
||||
if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) {
|
||||
rettv->vval.v_number = get_indent_lnum(lnum);
|
||||
} else {
|
||||
rettv->vval.v_number = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/// "lispindent(lnum)" function
|
||||
void f_lispindent(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
const pos_T pos = curwin->w_cursor;
|
||||
const linenr_T lnum = tv_get_lnum(argvars);
|
||||
if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) {
|
||||
curwin->w_cursor.lnum = lnum;
|
||||
rettv->vval.v_number = get_lisp_indent();
|
||||
curwin->w_cursor = pos;
|
||||
} else {
|
||||
rettv->vval.v_number = -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "nvim/ex_cmds_defs.h" // IWYU pragma: keep
|
||||
#include "nvim/normal_defs.h"
|
||||
#include "nvim/pos_defs.h" // IWYU pragma: keep
|
||||
#include "nvim/types_defs.h" // IWYU pragma: keep
|
||||
|
||||
@@ -14,6 +15,8 @@ enum {
|
||||
SIN_NOMARK = 8, ///< don't adjust extmarks
|
||||
};
|
||||
|
||||
typedef int (*Indenter)(void);
|
||||
|
||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||
# include "indent.h.generated.h"
|
||||
#endif
|
||||
|
||||
@@ -9,9 +9,11 @@
|
||||
#include "nvim/charset.h"
|
||||
#include "nvim/cursor.h"
|
||||
#include "nvim/edit.h"
|
||||
#include "nvim/eval/typval.h"
|
||||
#include "nvim/globals.h"
|
||||
#include "nvim/indent.h"
|
||||
#include "nvim/indent_c.h"
|
||||
#include "nvim/keycodes.h"
|
||||
#include "nvim/macros_defs.h"
|
||||
#include "nvim/mark_defs.h"
|
||||
#include "nvim/math.h"
|
||||
@@ -232,6 +234,13 @@ bool cin_is_cinword(const char *line)
|
||||
return retval;
|
||||
}
|
||||
|
||||
/// Check that C-indenting is on.
|
||||
bool cindent_on(void)
|
||||
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
{
|
||||
return !p_paste && (curbuf->b_p_cin || *curbuf->b_p_inde != NUL);
|
||||
}
|
||||
|
||||
// Skip over white space and C comments within the line.
|
||||
// Also skip over Perl/shell comments if desired.
|
||||
static const char *cin_skipcomment(const char *s)
|
||||
@@ -346,7 +355,7 @@ static bool cin_islabel_skip(const char **s)
|
||||
|
||||
// Recognize a label: "label:".
|
||||
// Note: curwin->w_cursor must be where we are looking for the label.
|
||||
bool cin_islabel(void) // XXX
|
||||
static bool cin_islabel(void) // XXX
|
||||
{
|
||||
const char *s = cin_skipcomment(get_cursor_line_ptr());
|
||||
|
||||
@@ -445,7 +454,7 @@ static int cin_isinit(void)
|
||||
/// Recognize a switch label: "case .*:" or "default:".
|
||||
///
|
||||
/// @param strict Allow relaxed check of case statement for JS
|
||||
bool cin_iscase(const char *s, bool strict)
|
||||
static bool cin_iscase(const char *s, bool strict)
|
||||
{
|
||||
s = cin_skipcomment(s);
|
||||
if (cin_starts_with(s, "case")) {
|
||||
@@ -491,7 +500,7 @@ static int cin_isdefault(const char *s)
|
||||
}
|
||||
|
||||
/// Recognize a scope declaration label set in 'cinscopedecls'.
|
||||
bool cin_isscopedecl(const char *p)
|
||||
static bool cin_isscopedecl(const char *p)
|
||||
{
|
||||
const char *s = cin_skipcomment(p);
|
||||
|
||||
@@ -3695,6 +3704,226 @@ static int find_match(int lookfor, linenr_T ourscope)
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
/// Check that "cinkeys" contains the key "keytyped",
|
||||
/// when == '*': Only if key is preceded with '*' (indent before insert)
|
||||
/// when == '!': Only if key is preceded with '!' (don't insert)
|
||||
/// when == ' ': Only if key is not preceded with '*' or '!' (indent afterwards)
|
||||
///
|
||||
/// "keytyped" can have a few special values:
|
||||
/// KEY_OPEN_FORW :
|
||||
/// KEY_OPEN_BACK :
|
||||
/// KEY_COMPLETE : Just finished completion.
|
||||
///
|
||||
/// @param keytyped key that was typed
|
||||
/// @param when condition on when to perform the check
|
||||
/// @param line_is_empty when true, accept keys with '0' before them.
|
||||
bool in_cinkeys(int keytyped, int when, bool line_is_empty)
|
||||
{
|
||||
char *look;
|
||||
bool try_match;
|
||||
bool try_match_word;
|
||||
char *p;
|
||||
bool icase;
|
||||
|
||||
if (keytyped == NUL) {
|
||||
// Can happen with CTRL-Y and CTRL-E on a short line.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (*curbuf->b_p_inde != NUL) {
|
||||
look = curbuf->b_p_indk; // 'indentexpr' set: use 'indentkeys'
|
||||
} else {
|
||||
look = curbuf->b_p_cink; // 'indentexpr' empty: use 'cinkeys'
|
||||
}
|
||||
while (*look) {
|
||||
// Find out if we want to try a match with this key, depending on
|
||||
// 'when' and a '*' or '!' before the key.
|
||||
switch (when) {
|
||||
case '*':
|
||||
try_match = (*look == '*'); break;
|
||||
case '!':
|
||||
try_match = (*look == '!'); break;
|
||||
default:
|
||||
try_match = (*look != '*') && (*look != '!'); break;
|
||||
}
|
||||
if (*look == '*' || *look == '!') {
|
||||
look++;
|
||||
}
|
||||
|
||||
// If there is a '0', only accept a match if the line is empty.
|
||||
// But may still match when typing last char of a word.
|
||||
if (*look == '0') {
|
||||
try_match_word = try_match;
|
||||
if (!line_is_empty) {
|
||||
try_match = false;
|
||||
}
|
||||
look++;
|
||||
} else {
|
||||
try_match_word = false;
|
||||
}
|
||||
|
||||
// Does it look like a control character?
|
||||
if (*look == '^' && look[1] >= '?' && look[1] <= '_') {
|
||||
if (try_match && keytyped == CTRL_CHR(look[1])) {
|
||||
return true;
|
||||
}
|
||||
look += 2;
|
||||
|
||||
// 'o' means "o" command, open forward.
|
||||
// 'O' means "O" command, open backward.
|
||||
} else if (*look == 'o') {
|
||||
if (try_match && keytyped == KEY_OPEN_FORW) {
|
||||
return true;
|
||||
}
|
||||
look++;
|
||||
} else if (*look == 'O') {
|
||||
if (try_match && keytyped == KEY_OPEN_BACK) {
|
||||
return true;
|
||||
}
|
||||
look++;
|
||||
|
||||
// 'e' means to check for "else" at start of line and just before the
|
||||
// cursor.
|
||||
} else if (*look == 'e') {
|
||||
if (try_match && keytyped == 'e' && curwin->w_cursor.col >= 4) {
|
||||
p = get_cursor_line_ptr();
|
||||
if (skipwhite(p) == p + curwin->w_cursor.col - 4
|
||||
&& strncmp(p + curwin->w_cursor.col - 4, "else", 4) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
look++;
|
||||
|
||||
// ':' only causes an indent if it is at the end of a label or case
|
||||
// statement, or when it was before typing the ':' (to fix
|
||||
// class::method for C++).
|
||||
} else if (*look == ':') {
|
||||
if (try_match && keytyped == ':') {
|
||||
p = get_cursor_line_ptr();
|
||||
if (cin_iscase(p, false) || cin_isscopedecl(p) || cin_islabel()) {
|
||||
return true;
|
||||
}
|
||||
// Need to get the line again after cin_islabel().
|
||||
p = get_cursor_line_ptr();
|
||||
if (curwin->w_cursor.col > 2
|
||||
&& p[curwin->w_cursor.col - 1] == ':'
|
||||
&& p[curwin->w_cursor.col - 2] == ':') {
|
||||
p[curwin->w_cursor.col - 1] = ' ';
|
||||
const bool i = cin_iscase(p, false)
|
||||
|| cin_isscopedecl(p)
|
||||
|| cin_islabel();
|
||||
p = get_cursor_line_ptr();
|
||||
p[curwin->w_cursor.col - 1] = ':';
|
||||
if (i) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
look++;
|
||||
|
||||
// Is it a key in <>, maybe?
|
||||
} else if (*look == '<') {
|
||||
if (try_match) {
|
||||
// make up some named keys <o>, <O>, <e>, <0>, <>>, <<>, <*>,
|
||||
// <:> and <!> so that people can re-indent on o, O, e, 0, <,
|
||||
// >, *, : and ! keys if they really really want to.
|
||||
if (vim_strchr("<>!*oOe0:", (uint8_t)look[1]) != NULL
|
||||
&& keytyped == look[1]) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (keytyped == get_special_key_code(look + 1)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
while (*look && *look != '>') {
|
||||
look++;
|
||||
}
|
||||
while (*look == '>') {
|
||||
look++;
|
||||
}
|
||||
// Is it a word: "=word"?
|
||||
} else if (*look == '=' && look[1] != ',' && look[1] != NUL) {
|
||||
look++;
|
||||
if (*look == '~') {
|
||||
icase = true;
|
||||
look++;
|
||||
} else {
|
||||
icase = false;
|
||||
}
|
||||
p = vim_strchr(look, ',');
|
||||
if (p == NULL) {
|
||||
p = look + strlen(look);
|
||||
}
|
||||
if ((try_match || try_match_word)
|
||||
&& curwin->w_cursor.col >= (colnr_T)(p - look)) {
|
||||
bool match = false;
|
||||
|
||||
if (keytyped == KEY_COMPLETE) {
|
||||
char *n, *s;
|
||||
|
||||
// Just completed a word, check if it starts with "look".
|
||||
// search back for the start of a word.
|
||||
char *line = get_cursor_line_ptr();
|
||||
for (s = line + curwin->w_cursor.col; s > line; s = n) {
|
||||
n = mb_prevptr(line, s);
|
||||
if (!vim_iswordp(n)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(p >= look && (uintmax_t)(p - look) <= SIZE_MAX);
|
||||
if (s + (p - look) <= line + curwin->w_cursor.col
|
||||
&& (icase
|
||||
? mb_strnicmp(s, look, (size_t)(p - look))
|
||||
: strncmp(s, look, (size_t)(p - look))) == 0) {
|
||||
match = true;
|
||||
}
|
||||
} else {
|
||||
// TODO(@brammool): multi-byte
|
||||
if (keytyped == (int)(uint8_t)p[-1]
|
||||
|| (icase && keytyped < 256 && keytyped >= 0
|
||||
&& TOLOWER_LOC(keytyped) == TOLOWER_LOC((uint8_t)p[-1]))) {
|
||||
char *line = get_cursor_pos_ptr();
|
||||
assert(p >= look && (uintmax_t)(p - look) <= SIZE_MAX);
|
||||
if ((curwin->w_cursor.col == (colnr_T)(p - look)
|
||||
|| !vim_iswordc((uint8_t)line[-(p - look) - 1]))
|
||||
&& (icase
|
||||
? mb_strnicmp(line - (p - look), look, (size_t)(p - look))
|
||||
: strncmp(line - (p - look), look, (size_t)(p - look))) == 0) {
|
||||
match = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (match && try_match_word && !try_match) {
|
||||
// "0=word": Check if there are only blanks before the
|
||||
// word.
|
||||
if (getwhitecols_curline() !=
|
||||
(int)(curwin->w_cursor.col - (p - look))) {
|
||||
match = false;
|
||||
}
|
||||
}
|
||||
if (match) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
look = p;
|
||||
|
||||
// Ok, it's a boring generic character.
|
||||
} else {
|
||||
if (try_match && (uint8_t)(*look) == keytyped) {
|
||||
return true;
|
||||
}
|
||||
if (*look != NUL) {
|
||||
look++;
|
||||
}
|
||||
}
|
||||
|
||||
// Skip over ", ".
|
||||
look = skip_to_option_part(look);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Do C or expression indenting on the current line.
|
||||
void do_c_expr_indent(void)
|
||||
{
|
||||
@@ -3704,3 +3933,17 @@ void do_c_expr_indent(void)
|
||||
fixthisline(get_c_indent);
|
||||
}
|
||||
}
|
||||
|
||||
/// "cindent(lnum)" function
|
||||
void f_cindent(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
pos_T pos = curwin->w_cursor;
|
||||
linenr_T lnum = tv_get_lnum(argvars);
|
||||
if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) {
|
||||
curwin->w_cursor.lnum = lnum;
|
||||
rettv->vval.v_number = get_c_indent();
|
||||
curwin->w_cursor = pos;
|
||||
} else {
|
||||
rettv->vval.v_number = -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "nvim/eval/typval_defs.h"
|
||||
#include "nvim/pos_defs.h" // IWYU pragma: keep
|
||||
#include "nvim/types_defs.h" // IWYU pragma: keep
|
||||
|
||||
|
||||
@@ -1090,7 +1090,7 @@ char *get_menu_names(expand_T *xp, int idx)
|
||||
///
|
||||
/// @param name may be modified.
|
||||
/// @return start of the next element
|
||||
char *menu_name_skip(char *const name)
|
||||
static char *menu_name_skip(char *const name)
|
||||
{
|
||||
char *p;
|
||||
|
||||
|
||||
@@ -662,7 +662,7 @@ void msg_source(int hl_id)
|
||||
/// If "emsg_off" is set: no error messages at the moment.
|
||||
/// If "msg" is in 'debug': do error message but without side effects.
|
||||
/// If "emsg_skip" is set: never do error messages.
|
||||
int emsg_not_now(void)
|
||||
static int emsg_not_now(void)
|
||||
{
|
||||
if ((emsg_off > 0 && vim_strchr(p_debug, 'm') == NULL
|
||||
&& vim_strchr(p_debug, 't') == NULL)
|
||||
@@ -3045,7 +3045,7 @@ static bool do_more_prompt(int typed_char)
|
||||
return retval;
|
||||
}
|
||||
|
||||
void msg_moremsg(bool full)
|
||||
static void msg_moremsg(bool full)
|
||||
{
|
||||
int attr = hl_combine_attr(HL_ATTR(HLF_MSG), HL_ATTR(HLF_M));
|
||||
grid_line_start(&msg_grid_adj, Rows - 1);
|
||||
@@ -3739,7 +3739,7 @@ static void copy_confirm_hotkeys(const char *buttons, int default_button_idx,
|
||||
}
|
||||
|
||||
/// Display the ":confirm" message. Also called when screen resized.
|
||||
void display_confirm_msg(void)
|
||||
static void display_confirm_msg(void)
|
||||
{
|
||||
// Avoid that 'q' at the more prompt truncates the message here.
|
||||
confirm_msg_used++;
|
||||
|
||||
@@ -134,16 +134,6 @@ static char opchars[][3] = {
|
||||
{ Ctrl_X, NUL, OPF_CHANGE }, // OP_NR_SUB
|
||||
};
|
||||
|
||||
yankreg_T *get_y_previous(void)
|
||||
{
|
||||
return y_previous;
|
||||
}
|
||||
|
||||
void set_y_previous(yankreg_T *yreg)
|
||||
{
|
||||
y_previous = yreg;
|
||||
}
|
||||
|
||||
/// Translate a command name into an operator type.
|
||||
/// Must only be called with a valid operator name!
|
||||
int get_op_type(int char1, int char2)
|
||||
@@ -723,84 +713,6 @@ static void block_insert(oparg_T *oap, const char *s, size_t slen, bool b_insert
|
||||
changed_lines(curbuf, oap->start.lnum + 1, 0, oap->end.lnum + 1, 0, true);
|
||||
}
|
||||
|
||||
/// Handle reindenting a block of lines.
|
||||
void op_reindent(oparg_T *oap, Indenter how)
|
||||
{
|
||||
int i = 0;
|
||||
linenr_T first_changed = 0;
|
||||
linenr_T last_changed = 0;
|
||||
linenr_T start_lnum = curwin->w_cursor.lnum;
|
||||
|
||||
// Don't even try when 'modifiable' is off.
|
||||
if (!MODIFIABLE(curbuf)) {
|
||||
emsg(_(e_modifiable));
|
||||
return;
|
||||
}
|
||||
|
||||
// Save for undo. Do this once for all lines, much faster than doing this
|
||||
// for each line separately, especially when undoing.
|
||||
if (u_savecommon(curbuf, start_lnum - 1, start_lnum + oap->line_count,
|
||||
start_lnum + oap->line_count, false) == OK) {
|
||||
int amount;
|
||||
for (i = oap->line_count - 1; i >= 0 && !got_int; i--) {
|
||||
// it's a slow thing to do, so give feedback so there's no worry
|
||||
// that the computer's just hung.
|
||||
|
||||
if (i > 1
|
||||
&& (i % 50 == 0 || i == oap->line_count - 1)
|
||||
&& oap->line_count > p_report) {
|
||||
smsg(0, _("%" PRId64 " lines to indent... "), (int64_t)i);
|
||||
}
|
||||
|
||||
// Be vi-compatible: For lisp indenting the first line is not
|
||||
// indented, unless there is only one line.
|
||||
if (i != oap->line_count - 1 || oap->line_count == 1
|
||||
|| how != get_lisp_indent) {
|
||||
char *l = skipwhite(get_cursor_line_ptr());
|
||||
if (*l == NUL) { // empty or blank line
|
||||
amount = 0;
|
||||
} else {
|
||||
amount = how(); // get the indent for this line
|
||||
}
|
||||
if (amount >= 0 && set_indent(amount, 0)) {
|
||||
// did change the indent, call changed_lines() later
|
||||
if (first_changed == 0) {
|
||||
first_changed = curwin->w_cursor.lnum;
|
||||
}
|
||||
last_changed = curwin->w_cursor.lnum;
|
||||
}
|
||||
}
|
||||
curwin->w_cursor.lnum++;
|
||||
curwin->w_cursor.col = 0; // make sure it's valid
|
||||
}
|
||||
}
|
||||
|
||||
// put cursor on first non-blank of indented line
|
||||
curwin->w_cursor.lnum = start_lnum;
|
||||
beginline(BL_SOL | BL_FIX);
|
||||
|
||||
// Mark changed lines so that they will be redrawn. When Visual
|
||||
// highlighting was present, need to continue until the last line. When
|
||||
// there is no change still need to remove the Visual highlighting.
|
||||
if (last_changed != 0) {
|
||||
changed_lines(curbuf, first_changed, 0,
|
||||
oap->is_VIsual ? start_lnum + oap->line_count
|
||||
: last_changed + 1, 0, true);
|
||||
} else if (oap->is_VIsual) {
|
||||
redraw_curbuf_later(UPD_INVERTED);
|
||||
}
|
||||
|
||||
if (oap->line_count > p_report) {
|
||||
i = oap->line_count - (i + 1);
|
||||
smsg(0, NGETTEXT("%" PRId64 " line indented ", "%" PRId64 " lines indented ", i), (int64_t)i);
|
||||
}
|
||||
if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0) {
|
||||
// set '[ and '] marks
|
||||
curbuf->b_op_start = oap->start;
|
||||
curbuf->b_op_end = oap->end;
|
||||
}
|
||||
}
|
||||
|
||||
// Keep the last expression line here, for repeating.
|
||||
static char *expr_line = NULL;
|
||||
|
||||
@@ -3738,14 +3650,6 @@ void adjust_cursor_eol(void)
|
||||
}
|
||||
}
|
||||
|
||||
/// @return true if lines starting with '#' should be left aligned.
|
||||
bool preprocs_left(void)
|
||||
{
|
||||
return ((curbuf->b_p_si && !curbuf->b_p_cin)
|
||||
|| (curbuf->b_p_cin && in_cinkeys('#', ' ', true)
|
||||
&& curbuf->b_ind_hash_comment == 0));
|
||||
}
|
||||
|
||||
/// @return the character name of the register with the given number
|
||||
int get_register_name(int num)
|
||||
{
|
||||
|
||||
@@ -33,8 +33,6 @@ struct block_def {
|
||||
colnr_T start_char_vcols; ///< number of vcols of pre-block char
|
||||
};
|
||||
|
||||
typedef int (*Indenter)(void);
|
||||
|
||||
/// flags for do_put()
|
||||
enum {
|
||||
PUT_FIXINDENT = 1, ///< make indent look nice
|
||||
|
||||
@@ -1537,40 +1537,6 @@ void set_options_bin(int oldval, int newval, int opt_flags)
|
||||
didset_options_sctx(opt_flags, p_bin_dep_opts);
|
||||
}
|
||||
|
||||
/// Find the parameter represented by the given character (eg ', :, ", or /),
|
||||
/// and return its associated value in the 'shada' string.
|
||||
/// Only works for number parameters, not for 'r' or 'n'.
|
||||
/// If the parameter is not specified in the string or there is no following
|
||||
/// number, return -1.
|
||||
int get_shada_parameter(int type)
|
||||
{
|
||||
char *p = find_shada_parameter(type);
|
||||
if (p != NULL && ascii_isdigit(*p)) {
|
||||
return atoi(p);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// Find the parameter represented by the given character (eg ''', ':', '"', or
|
||||
/// '/') in the 'shada' option and return a pointer to the string after it.
|
||||
/// Return NULL if the parameter is not specified in the string.
|
||||
char *find_shada_parameter(int type)
|
||||
{
|
||||
for (char *p = p_shada; *p; p++) {
|
||||
if (*p == type) {
|
||||
return p + 1;
|
||||
}
|
||||
if (*p == 'n') { // 'n' is always the last one
|
||||
break;
|
||||
}
|
||||
p = vim_strchr(p, ','); // skip until next ','
|
||||
if (p == NULL) { // hit the end without finding parameter
|
||||
break;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/// Expand environment variables for some string options.
|
||||
/// These string options cannot be indirect!
|
||||
/// If "val" is NULL expand the current value of the option.
|
||||
@@ -4950,7 +4916,7 @@ void copy_winopt(winopt_T *from, winopt_T *to)
|
||||
}
|
||||
|
||||
/// Check string options in a window for a NULL value.
|
||||
void check_win_options(win_T *win)
|
||||
static void check_win_options(win_T *win)
|
||||
{
|
||||
check_winopt(&win->w_onebuf_opt);
|
||||
check_winopt(&win->w_allbuf_opt);
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#include "nvim/pos_defs.h"
|
||||
#include "nvim/regexp.h"
|
||||
#include "nvim/regexp_defs.h"
|
||||
#include "nvim/shada.h"
|
||||
#include "nvim/spell.h"
|
||||
#include "nvim/spellfile.h"
|
||||
#include "nvim/spellsuggest.h"
|
||||
|
||||
@@ -171,7 +171,7 @@ proftime_T profile_self(proftime_T self, proftime_T total, proftime_T children)
|
||||
/// Gets the current waittime.
|
||||
///
|
||||
/// @return the current waittime
|
||||
proftime_T profile_get_wait(void) FUNC_ATTR_PURE
|
||||
static proftime_T profile_get_wait(void) FUNC_ATTR_PURE
|
||||
{
|
||||
return prof_wait_time;
|
||||
}
|
||||
@@ -194,7 +194,7 @@ proftime_T profile_sub_wait(proftime_T tm, proftime_T tma) FUNC_ATTR_PURE
|
||||
/// Checks if time `tm1` is equal to `tm2`.
|
||||
///
|
||||
/// @return true if `tm1` == `tm2`
|
||||
bool profile_equal(proftime_T tm1, proftime_T tm2) FUNC_ATTR_CONST
|
||||
static bool profile_equal(proftime_T tm1, proftime_T tm2) FUNC_ATTR_CONST
|
||||
{
|
||||
return tm1 == tm2;
|
||||
}
|
||||
|
||||
@@ -3772,3 +3772,51 @@ void shada_read_string(String string, const int flags)
|
||||
shada_read(&sd_reader, flags);
|
||||
close_file(&sd_reader);
|
||||
}
|
||||
|
||||
/// Find the parameter represented by the given character (eg ', :, ", or /),
|
||||
/// and return its associated value in the 'shada' string.
|
||||
/// Only works for number parameters, not for 'r' or 'n'.
|
||||
/// If the parameter is not specified in the string or there is no following
|
||||
/// number, return -1.
|
||||
int get_shada_parameter(int type)
|
||||
{
|
||||
char *p = find_shada_parameter(type);
|
||||
if (p != NULL && ascii_isdigit(*p)) {
|
||||
return atoi(p);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// Find the parameter represented by the given character (eg ''', ':', '"', or
|
||||
/// '/') in the 'shada' option and return a pointer to the string after it.
|
||||
/// Return NULL if the parameter is not specified in the string.
|
||||
char *find_shada_parameter(int type)
|
||||
{
|
||||
for (char *p = p_shada; *p; p++) {
|
||||
if (*p == type) {
|
||||
return p + 1;
|
||||
}
|
||||
if (*p == 'n') { // 'n' is always the last one
|
||||
break;
|
||||
}
|
||||
p = vim_strchr(p, ','); // skip until next ','
|
||||
if (p == NULL) { // hit the end without finding parameter
|
||||
break;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/// Read marks for the current buffer from the ShaDa file, when we support
|
||||
/// buffer marks and the buffer has a name.
|
||||
void check_marks_read(void)
|
||||
{
|
||||
if (!curbuf->b_marks_read && get_shada_parameter('\'') > 0
|
||||
&& curbuf->b_ffname != NULL) {
|
||||
shada_read_marks();
|
||||
}
|
||||
|
||||
// Always set b_marks_read; needed when 'shada' is changed to include
|
||||
// the ' parameter after opening a buffer.
|
||||
curbuf->b_marks_read = true;
|
||||
}
|
||||
|
||||
@@ -2991,7 +2991,7 @@ void u_clearallandblockfree(buf_T *buf)
|
||||
}
|
||||
|
||||
/// Save the line "lnum" for the "U" command.
|
||||
void u_saveline(buf_T *buf, linenr_T lnum)
|
||||
static void u_saveline(buf_T *buf, linenr_T lnum)
|
||||
{
|
||||
if (lnum == buf->b_u_line_lnum) { // line is already saved
|
||||
return;
|
||||
|
||||
@@ -2528,6 +2528,12 @@ bool has_nvim_version(const char *const version_str)
|
||||
&& patch <= NVIM_VERSION_PATCH))));
|
||||
}
|
||||
|
||||
int highest_patch(void)
|
||||
{
|
||||
// this relies on the highest patch number to be the first entry
|
||||
return included_patches[0];
|
||||
}
|
||||
|
||||
/// Checks whether a Vim patch has been included.
|
||||
///
|
||||
/// @param n Patch number.
|
||||
|
||||
@@ -878,6 +878,21 @@ M.vars = {
|
||||
<
|
||||
]=],
|
||||
},
|
||||
versionlong = {
|
||||
type = 'integer',
|
||||
desc = [=[
|
||||
Like v:version, but also including the patchlevel in the last
|
||||
four digits. Version 8.1 with patch 123 has value 8010123.
|
||||
This can be used like this: >
|
||||
if v:versionlong >= 8010123
|
||||
<
|
||||
However, if there are gaps in the list of patches included
|
||||
this will not work well. This can happen if a recent patch
|
||||
was included into an older version, e.g. for a security fix.
|
||||
Use the has() function to make sure the patch is actually
|
||||
included.
|
||||
]=],
|
||||
},
|
||||
vim_did_enter = {
|
||||
type = 'integer',
|
||||
desc = [=[
|
||||
|
||||
@@ -4262,7 +4262,7 @@ int win_new_tabpage(int after, char *filename)
|
||||
// Open a new tab page if ":tab cmd" was used. It will edit the same buffer,
|
||||
// like with ":split".
|
||||
// Returns OK if a new tab page was created, FAIL otherwise.
|
||||
int may_open_tabpage(void)
|
||||
static int may_open_tabpage(void)
|
||||
{
|
||||
int n = (cmdmod.cmod_tab == 0) ? postponed_split_tab : cmdmod.cmod_tab;
|
||||
|
||||
|
||||
@@ -272,6 +272,17 @@ func Test_string_concat_scriptversion1()
|
||||
endif
|
||||
endfunc
|
||||
|
||||
" scriptversion 2
|
||||
func Test_vvar_scriptversion2()
|
||||
call assert_true(exists('version'))
|
||||
echo version
|
||||
call assert_fails('let version = 1', 'E46:')
|
||||
call assert_equal(v:version, version)
|
||||
|
||||
call assert_equal(v:version, v:versionlong / 10000)
|
||||
call assert_true(v:versionlong > 8011525)
|
||||
endfunc
|
||||
|
||||
" scriptversion 1
|
||||
func Test_vvar_scriptversion1()
|
||||
call assert_equal(15, 017)
|
||||
|
||||
@@ -319,6 +319,9 @@ func Test_ruby_Vim_evaluate()
|
||||
call assert_equal('foo', rubyeval('Vim::evaluate("\"foo\"")'))
|
||||
call assert_equal('String', rubyeval('Vim::evaluate("\"foo\"").class'))
|
||||
|
||||
call assert_equal(["\x01\xAB"], rubyeval('Vim::evaluate("0z01ab").unpack("M")'))
|
||||
call assert_equal('String', rubyeval('Vim::evaluate("0z01ab").class'))
|
||||
|
||||
call assert_equal([1, 2], rubyeval('Vim::evaluate("[1, 2]")'))
|
||||
call assert_equal('Array', rubyeval('Vim::evaluate("[1, 2]").class'))
|
||||
|
||||
|
||||
@@ -96,9 +96,6 @@ describe('profiling related functions', function()
|
||||
local function profile_cmp(t1, t2)
|
||||
return prof.profile_cmp(t1, t2)
|
||||
end
|
||||
local function profile_equal(t1, t2)
|
||||
return prof.profile_equal(t1, t2)
|
||||
end
|
||||
local function profile_msg(q)
|
||||
return ffi.string(prof.profile_msg(q))
|
||||
end
|
||||
@@ -110,20 +107,6 @@ describe('profiling related functions', function()
|
||||
return tonumber(s) + tonumber(us) / 1000000
|
||||
end
|
||||
|
||||
describe('profile_equal', function()
|
||||
itp('times are equal to themselves', function()
|
||||
local start = profile_start()
|
||||
assert.is_true(profile_equal(start, start))
|
||||
|
||||
local e = profile_end(start)
|
||||
assert.is_true(profile_equal(e, e))
|
||||
end)
|
||||
|
||||
itp('times are unequal to others', function()
|
||||
assert.is_false(profile_equal(profile_start(), profile_start()))
|
||||
end)
|
||||
end)
|
||||
|
||||
-- this is quite difficult to test, as it would rely on other functions in
|
||||
-- the profiling package. Those functions in turn will probably be tested
|
||||
-- using profile_cmp... circular reasoning.
|
||||
@@ -169,7 +152,6 @@ describe('profiling related functions', function()
|
||||
describe('profile_zero', function()
|
||||
itp('returns the same value on each call', function()
|
||||
eq(0, profile_zero())
|
||||
assert.is_true(profile_equal(profile_zero(), profile_zero()))
|
||||
end)
|
||||
end)
|
||||
|
||||
@@ -203,7 +185,7 @@ describe('profiling related functions', function()
|
||||
|
||||
describe('profile_setlimit', function()
|
||||
itp('sets no limit when 0 is passed', function()
|
||||
eq(true, profile_equal(profile_setlimit(0), profile_zero()))
|
||||
eq(profile_setlimit(0), profile_zero())
|
||||
end)
|
||||
|
||||
itp('sets a limit in the future otherwise', function()
|
||||
|
||||
Reference in New Issue
Block a user