aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/api/buffer.c34
-rw-r--r--src/nvim/buffer_defs.h20
-rw-r--r--src/nvim/buffer_updates.c18
-rw-r--r--src/nvim/ex_docmd.c7
-rw-r--r--src/nvim/fileio.c3
-rw-r--r--src/nvim/getchar.c1
-rw-r--r--src/nvim/globals.h2
-rw-r--r--src/nvim/lua/executor.c65
-rw-r--r--src/nvim/mbyte.c58
-rw-r--r--src/nvim/memline.c53
-rw-r--r--src/nvim/misc1.c3
-rw-r--r--src/nvim/spell.c6
-rw-r--r--src/nvim/terminal.c2
-rw-r--r--src/nvim/testdir/test_spell.vim13
-rw-r--r--src/nvim/version.c17
15 files changed, 279 insertions, 23 deletions
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index b0b65545ab..c6f82e9d85 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -109,9 +109,11 @@ String buffer_get_line(Buffer buffer, Integer index, Error *err)
/// `nvim_buf_lines_event`. Otherwise, the first notification will be
/// a `nvim_buf_changedtick_event`. Not used for lua callbacks.
/// @param opts Optional parameters.
-/// `on_lines`: lua callback received on change.
+/// `on_lines`: lua callback received on change.
/// `on_changedtick`: lua callback received on changedtick
/// increment without text change.
+/// `utf_sizes`: include UTF-32 and UTF-16 size of
+/// the replaced region.
/// See |api-buffer-updates-lua| for more information
/// @param[out] err Error details, if any
/// @return False when updates couldn't be enabled because the buffer isn't
@@ -156,6 +158,12 @@ Boolean nvim_buf_attach(uint64_t channel_id,
}
cb.on_detach = v->data.luaref;
v->data.integer = LUA_NOREF;
+ } else if (is_lua && strequal("utf_sizes", k.data)) {
+ if (v->type != kObjectTypeBoolean) {
+ api_set_error(err, kErrorTypeValidation, "utf_sizes must be boolean");
+ goto error;
+ }
+ cb.utf_sizes = v->data.boolean;
} else {
api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data);
goto error;
@@ -1176,6 +1184,30 @@ free_exit:
return 0;
}
+Dictionary nvim__buf_stats(Buffer buffer, Error *err)
+{
+ Dictionary rv = ARRAY_DICT_INIT;
+
+ buf_T *buf = find_buffer_by_handle(buffer, err);
+ if (!buf) {
+ return rv;
+ }
+
+ // Number of times the cached line was flushed.
+ // This should generally not increase while editing the same
+ // line in the same mode.
+ PUT(rv, "flush_count", INTEGER_OBJ(buf->flush_count));
+ // lnum of current line
+ PUT(rv, "current_lnum", INTEGER_OBJ(buf->b_ml.ml_line_lnum));
+ // whether the line has unflushed changes.
+ PUT(rv, "line_dirty", BOOLEAN_OBJ(buf->b_ml.ml_flags & ML_LINE_DIRTY));
+ // NB: this should be zero at any time API functions are called,
+ // this exists to debug issues
+ PUT(rv, "dirty_bytes", INTEGER_OBJ((Integer)buf->deleted_bytes));
+
+ return rv;
+}
+
// Check if deleting lines made the cursor position invalid.
// Changed lines from `lo` to `hi`; added `extra` lines (negative if deleted).
static void fix_cursor(linenr_T lo, linenr_T hi, linenr_T extra)
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 143737b478..b11eaefdd0 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -459,8 +459,9 @@ typedef struct {
LuaRef on_lines;
LuaRef on_changedtick;
LuaRef on_detach;
+ bool utf_sizes;
} BufUpdateCallbacks;
-#define BUF_UPDATE_CALLBACKS_INIT { LUA_NOREF, LUA_NOREF, LUA_NOREF }
+#define BUF_UPDATE_CALLBACKS_INIT { LUA_NOREF, LUA_NOREF, LUA_NOREF, false }
#define BUF_HAS_QF_ENTRY 1
#define BUF_HAS_LL_ENTRY 2
@@ -802,11 +803,26 @@ struct file_buffer {
kvec_t(BufhlLine *) b_bufhl_move_space; // temporary space for highlights
- // array of channelids which have asked to receive updates for this
+ // array of channel_id:s which have asked to receive updates for this
// buffer.
kvec_t(uint64_t) update_channels;
+ // array of lua callbacks for buffer updates.
kvec_t(BufUpdateCallbacks) update_callbacks;
+ // whether an update callback has requested codepoint size of deleted regions.
+ bool update_need_codepoints;
+
+ // Measurements of the deleted or replaced region since the last update
+ // event. Some consumers of buffer changes need to know the byte size (like
+ // tree-sitter) or the corresponding UTF-32/UTF-16 size (like LSP) of the
+ // deleted text.
+ size_t deleted_bytes;
+ size_t deleted_codepoints;
+ size_t deleted_codeunits;
+
+ // The number for times the current line has been flushed in the memline.
+ int flush_count;
+
int b_diff_failed; // internal diff failed for this buffer
};
diff --git a/src/nvim/buffer_updates.c b/src/nvim/buffer_updates.c
index 21efda9fd9..3604578b50 100644
--- a/src/nvim/buffer_updates.c
+++ b/src/nvim/buffer_updates.c
@@ -26,6 +26,9 @@ bool buf_updates_register(buf_T *buf, uint64_t channel_id,
if (channel_id == LUA_INTERNAL_CALL) {
kv_push(buf->update_callbacks, cb);
+ if (cb.utf_sizes) {
+ buf->update_need_codepoints = true;
+ }
return true;
}
@@ -169,6 +172,10 @@ void buf_updates_send_changes(buf_T *buf,
int64_t num_removed,
bool send_tick)
{
+ size_t deleted_codepoints, deleted_codeunits;
+ size_t deleted_bytes = ml_flush_deleted_bytes(buf, &deleted_codepoints,
+ &deleted_codeunits);
+
if (!buf_updates_active(buf)) {
return;
}
@@ -231,8 +238,8 @@ void buf_updates_send_changes(buf_T *buf,
bool keep = true;
if (cb.on_lines != LUA_NOREF) {
Array args = ARRAY_DICT_INIT;
- Object items[5];
- args.size = 5;
+ Object items[8];
+ args.size = 6; // may be increased to 8 below
args.items = items;
// the first argument is always the buffer handle
@@ -250,6 +257,13 @@ void buf_updates_send_changes(buf_T *buf,
// the last line in the updated range
args.items[4] = INTEGER_OBJ(firstline - 1 + num_added);
+ // byte count of previous contents
+ args.items[5] = INTEGER_OBJ((Integer)deleted_bytes);
+ if (cb.utf_sizes) {
+ args.size = 8;
+ args.items[6] = INTEGER_OBJ((Integer)deleted_codepoints);
+ args.items[7] = INTEGER_OBJ((Integer)deleted_codeunits);
+ }
textlock++;
Object res = executor_exec_lua_cb(cb.on_lines, "lines", args, true);
textlock--;
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index b315639681..bad844e9d5 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -4060,10 +4060,9 @@ static char_u *replace_makeprg(exarg_T *eap, char_u *p, char_u **cmdlinep)
return p;
}
-/*
- * Expand file name in Ex command argument.
- * Return FAIL for failure, OK otherwise.
- */
+// Expand file name in Ex command argument.
+// When an error is detected, "errormsgp" is set to a non-NULL pointer.
+// Return FAIL for failure, OK otherwise.
int expand_filename(exarg_T *eap, char_u **cmdlinep, char_u **errormsgp)
{
int has_wildcards; /* need to expand wildcards */
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 410c68017d..882bf1b830 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -1761,6 +1761,9 @@ failed:
ml_delete(curbuf->b_ml.ml_line_count, false);
linecnt--;
}
+ curbuf->deleted_bytes = 0;
+ curbuf->deleted_codepoints = 0;
+ curbuf->deleted_codeunits = 0;
linecnt = curbuf->b_ml.ml_line_count - linecnt;
if (filesize == 0)
linecnt = 0;
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index f7614fd3e1..03f64c2019 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -1945,6 +1945,7 @@ static int vgetorpeek(int advance)
// No matching mapping found or found a non-matching mapping that
// matches at least what the matching mapping matched
keylen = 0;
+ (void)keylen; // suppress clang/dead assignment
// If there was no mapping, use the character from the typeahead
// buffer right here. Otherwise, use the mapping (loop around).
if (mp == NULL) {
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index d13b121562..b095e759d9 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -627,6 +627,8 @@ EXTERN pos_T Insstart_orig;
EXTERN int orig_line_count INIT(= 0); /* Line count when "gR" started */
EXTERN int vr_lines_changed INIT(= 0); /* #Lines changed by "gR" so far */
+// increase around internal delete/replace
+EXTERN int inhibit_delete_count INIT(= 0);
/*
* These flags are set based upon 'fileencoding'.
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index 4051354d65..29682e8add 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -112,6 +112,65 @@ static int nlua_stricmp(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
return 1;
}
+/// convert byte index to UTF-32 and UTF-16 indicies
+///
+/// Expects a string and an optional index. If no index is supplied, the length
+/// of the string is returned.
+///
+/// Returns two values: the UTF-32 and UTF-16 indicies.
+static int nlua_str_utfindex(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
+{
+ size_t s1_len;
+ const char *s1 = luaL_checklstring(lstate, 1, &s1_len);
+ intptr_t idx;
+ if (lua_gettop(lstate) >= 2) {
+ idx = luaL_checkinteger(lstate, 2);
+ if (idx < 0 || idx > (intptr_t)s1_len) {
+ return luaL_error(lstate, "index out of range");
+ }
+ } else {
+ idx = (intptr_t)s1_len;
+ }
+
+ size_t codepoints = 0, codeunits = 0;
+ mb_utflen((const char_u *)s1, (size_t)idx, &codepoints, &codeunits);
+
+ lua_pushinteger(lstate, (long)codepoints);
+ lua_pushinteger(lstate, (long)codeunits);
+
+ return 2;
+}
+
+/// convert UTF-32 or UTF-16 indicies to byte index.
+///
+/// Expects up to three args: string, index and use_utf16.
+/// If use_utf16 is not supplied it defaults to false (use UTF-32)
+///
+/// Returns the byte index.
+static int nlua_str_byteindex(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
+{
+ size_t s1_len;
+ const char *s1 = luaL_checklstring(lstate, 1, &s1_len);
+ intptr_t idx = luaL_checkinteger(lstate, 2);
+ if (idx < 0) {
+ return luaL_error(lstate, "index out of range");
+ }
+ bool use_utf16 = false;
+ if (lua_gettop(lstate) >= 3) {
+ use_utf16 = lua_toboolean(lstate, 3);
+ }
+
+ ssize_t byteidx = mb_utf_index_to_bytes((const char_u *)s1, s1_len,
+ (size_t)idx, use_utf16);
+ if (byteidx == -1) {
+ return luaL_error(lstate, "index out of range");
+ }
+
+ lua_pushinteger(lstate, (long)byteidx);
+
+ return 1;
+}
+
static void nlua_luv_error_event(void **argv)
{
char *error = (char *)argv[0];
@@ -220,6 +279,12 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
// stricmp
lua_pushcfunction(lstate, &nlua_stricmp);
lua_setfield(lstate, -2, "stricmp");
+ // str_utfindex
+ lua_pushcfunction(lstate, &nlua_str_utfindex);
+ lua_setfield(lstate, -2, "str_utfindex");
+ // str_byteindex
+ lua_pushcfunction(lstate, &nlua_str_byteindex);
+ lua_setfield(lstate, -2, "str_byteindex");
// schedule
lua_pushcfunction(lstate, &nlua_schedule);
lua_setfield(lstate, -2, "schedule");
diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c
index 3017f3c855..fae7635d34 100644
--- a/src/nvim/mbyte.c
+++ b/src/nvim/mbyte.c
@@ -1438,6 +1438,64 @@ int utf16_to_utf8(const wchar_t *strw, char **str)
#endif
+/// Measure the length of a string in corresponding UTF-32 and UTF-16 units.
+///
+/// Invalid UTF-8 bytes, or embedded surrogates, count as one code point/unit
+/// each.
+///
+/// The out parameters are incremented. This is used to measure the size of
+/// a buffer region consisting of multiple line segments.
+///
+/// @param s the string
+/// @param len maximum length (an earlier NUL terminates)
+/// @param[out] codepoints incremented with UTF-32 code point size
+/// @param[out] codeunits incremented with UTF-16 code unit size
+void mb_utflen(const char_u *s, size_t len, size_t *codepoints,
+ size_t *codeunits)
+ FUNC_ATTR_NONNULL_ALL
+{
+ size_t count = 0, extra = 0;
+ size_t clen;
+ for (size_t i = 0; i < len && s[i] != NUL; i += clen) {
+ clen = utf_ptr2len_len(s+i, len-i);
+ // NB: gets the byte value of invalid sequence bytes.
+ // we only care whether the char fits in the BMP or not
+ int c = (clen > 1) ? utf_ptr2char(s+i) : s[i];
+ count++;
+ if (c > 0xFFFF) {
+ extra++;
+ }
+ }
+ *codepoints += count;
+ *codeunits += count + extra;
+}
+
+ssize_t mb_utf_index_to_bytes(const char_u *s, size_t len,
+ size_t index, bool use_utf16_units)
+ FUNC_ATTR_NONNULL_ALL
+{
+ size_t count = 0;
+ size_t clen, i;
+ if (index == 0) {
+ return 0;
+ }
+ for (i = 0; i < len && s[i] != NUL; i += clen) {
+ clen = utf_ptr2len_len(s+i, len-i);
+ // NB: gets the byte value of invalid sequence bytes.
+ // we only care whether the char fits in the BMP or not
+ int c = (clen > 1) ? utf_ptr2char(s+i) : s[i];
+ count++;
+ if (use_utf16_units && c > 0xFFFF) {
+ count++;
+ }
+ if (count >= index) {
+ return i+clen;
+ }
+ }
+ return -1;
+}
+
+
/*
* Version of strnicmp() that handles multi-byte characters.
* Needed for Big5, Shift-JIS and UTF-8 encoding. Other DBCS encodings can
diff --git a/src/nvim/memline.c b/src/nvim/memline.c
index b027459706..3220c7d9b8 100644
--- a/src/nvim/memline.c
+++ b/src/nvim/memline.c
@@ -2383,6 +2383,23 @@ static int ml_append_int(
return OK;
}
+void ml_add_deleted_len(char_u *ptr, ssize_t len)
+{
+ if (inhibit_delete_count) {
+ return;
+ }
+ if (len == -1) {
+ len = STRLEN(ptr);
+ }
+ curbuf->deleted_bytes += len+1;
+ if (curbuf->update_need_codepoints) {
+ mb_utflen(ptr, len, &curbuf->deleted_codepoints,
+ &curbuf->deleted_codeunits);
+ curbuf->deleted_codepoints++; // NL char
+ curbuf->deleted_codeunits++;
+ }
+}
+
/*
* Replace line lnum, with buffering, in current buffer.
*
@@ -2403,13 +2420,24 @@ int ml_replace(linenr_T lnum, char_u *line, bool copy)
if (curbuf->b_ml.ml_mfp == NULL && open_buffer(FALSE, NULL, 0) == FAIL)
return FAIL;
+ bool readlen = true;
+
if (copy) {
line = vim_strsave(line);
}
- if (curbuf->b_ml.ml_line_lnum != lnum) /* other line buffered */
- ml_flush_line(curbuf); /* flush it */
- else if (curbuf->b_ml.ml_flags & ML_LINE_DIRTY) /* same line allocated */
- xfree(curbuf->b_ml.ml_line_ptr); /* free it */
+ if (curbuf->b_ml.ml_line_lnum != lnum) { // other line buffered
+ ml_flush_line(curbuf); // flush it
+ } else if (curbuf->b_ml.ml_flags & ML_LINE_DIRTY) { // same line allocated
+ ml_add_deleted_len(curbuf->b_ml.ml_line_ptr, -1);
+ readlen = false; // already added the length
+
+ xfree(curbuf->b_ml.ml_line_ptr); // free it
+ }
+
+ if (readlen && kv_size(curbuf->update_callbacks)) {
+ ml_add_deleted_len(ml_get_buf(curbuf, lnum, false), -1);
+ }
+
curbuf->b_ml.ml_line_ptr = line;
curbuf->b_ml.ml_line_lnum = lnum;
curbuf->b_ml.ml_flags = (curbuf->b_ml.ml_flags | ML_LINE_DIRTY) & ~ML_EMPTY;
@@ -2491,6 +2519,10 @@ static int ml_delete_int(buf_T *buf, linenr_T lnum, bool message)
else
line_size = ((dp->db_index[idx - 1]) & DB_INDEX_MASK) - line_start;
+ // Line should always have an NL char internally (represented as NUL),
+ // even if 'noeol' is set.
+ assert(line_size >= 1);
+ ml_add_deleted_len((char_u *)dp + line_start, line_size-1);
/*
* special case: If there is only one line in the data block it becomes empty.
@@ -2676,6 +2708,17 @@ void ml_clearmarked(void)
return;
}
+size_t ml_flush_deleted_bytes(buf_T *buf, size_t *codepoints, size_t *codeunits)
+{
+ size_t ret = buf->deleted_bytes;
+ *codepoints = buf->deleted_codepoints;
+ *codeunits = buf->deleted_codeunits;
+ buf->deleted_bytes = 0;
+ buf->deleted_codepoints = 0;
+ buf->deleted_codeunits = 0;
+ return ret;
+}
+
/*
* flush ml_line if necessary
*/
@@ -2704,6 +2747,8 @@ static void ml_flush_line(buf_T *buf)
return;
entered = TRUE;
+ buf->flush_count++;
+
lnum = buf->b_ml.ml_line_lnum;
new_line = buf->b_ml.ml_line_ptr;
diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c
index db0d56b5fd..a62fa6d585 100644
--- a/src/nvim/misc1.c
+++ b/src/nvim/misc1.c
@@ -780,6 +780,7 @@ open_line (
did_append = FALSE;
}
+ inhibit_delete_count++;
if (newindent
|| did_si
) {
@@ -821,6 +822,7 @@ open_line (
did_si = false;
}
}
+ inhibit_delete_count--;
/*
* In REPLACE mode, for each character in the extra leader, there must be
@@ -1685,6 +1687,7 @@ int del_bytes(colnr_T count, bool fixpos_arg, bool use_delcombine)
bool was_alloced = ml_line_alloced(); // check if oldp was allocated
char_u *newp;
if (was_alloced) {
+ ml_add_deleted_len(curbuf->b_ml.ml_line_ptr, oldlen);
newp = oldp; // use same allocated memory
} else { // need to allocate a new line
newp = xmalloc((size_t)(oldlen + 1 - count));
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index cc214616f4..404f279e73 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -1807,9 +1807,11 @@ void count_common_word(slang_T *lp, char_u *word, int len, int count)
char_u buf[MAXWLEN];
char_u *p;
- if (len == -1)
+ if (len == -1) {
p = word;
- else {
+ } else if (len >= MAXWLEN) {
+ return;
+ } else {
STRLCPY(buf, word, len + 1);
p = buf;
}
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index d8d529d0f6..3b0f42aacd 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -1306,7 +1306,7 @@ static void refresh_screen(Terminal *term, buf_T *buf)
static void adjust_topline(Terminal *term, buf_T *buf, long added)
{
- FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
if (wp->w_buffer == buf) {
linenr_T ml_end = buf->b_ml.ml_line_count;
bool following = ml_end == wp->w_cursor.lnum + added; // cursor at end?
diff --git a/src/nvim/testdir/test_spell.vim b/src/nvim/testdir/test_spell.vim
index b3438cc649..d7b8ca9e9c 100644
--- a/src/nvim/testdir/test_spell.vim
+++ b/src/nvim/testdir/test_spell.vim
@@ -1,4 +1,5 @@
" Test spell checking
+" Note: this file uses latin1 encoding, but is used with utf-8 encoding.
if !has('spell')
finish
@@ -351,6 +352,18 @@ func Test_zeq_crash()
bwipe!
endfunc
+" Check handling a word longer than MAXWLEN.
+func Test_spell_long_word()
+ set enc=utf-8
+ new
+ call setline(1, "d\xCC\xB4\xCC\xBD\xCD\x88\xCD\x94a\xCC\xB5\xCD\x84\xCD\x84\xCC\xA8\xCD\x9Cr\xCC\xB5\xCC\x8E\xCD\x85\xCD\x85k\xCC\xB6\xCC\x89\xCC\x9D \xCC\xB6\xCC\x83\xCC\x8F\xCC\xA4\xCD\x8Ef\xCC\xB7\xCC\x81\xCC\x80\xCC\xA9\xCC\xB0\xCC\xAC\xCC\xA2\xCD\x95\xCD\x87\xCD\x8D\xCC\x9E\xCD\x99\xCC\xAD\xCC\xAB\xCC\x97\xCC\xBBo\xCC\xB6\xCC\x84\xCC\x95\xCC\x8C\xCC\x8B\xCD\x9B\xCD\x9C\xCC\xAFr\xCC\xB7\xCC\x94\xCD\x83\xCD\x97\xCC\x8C\xCC\x82\xCD\x82\xCD\x80\xCD\x91\xCC\x80\xCC\xBE\xCC\x82\xCC\x8F\xCC\xA3\xCD\x85\xCC\xAE\xCD\x8D\xCD\x99\xCC\xBC\xCC\xAB\xCC\xA7\xCD\x88c\xCC\xB7\xCD\x83\xCC\x84\xCD\x92\xCC\x86\xCC\x83\xCC\x88\xCC\x92\xCC\x94\xCC\xBE\xCC\x9D\xCC\xAF\xCC\x98\xCC\x9D\xCC\xBB\xCD\x8E\xCC\xBB\xCC\xB3\xCC\xA3\xCD\x8E\xCD\x99\xCC\xA5\xCC\xAD\xCC\x99\xCC\xB9\xCC\xAE\xCC\xA5\xCC\x9E\xCD\x88\xCC\xAE\xCC\x9E\xCC\xA9\xCC\x97\xCC\xBC\xCC\x99\xCC\xA5\xCD\x87\xCC\x97\xCD\x8E\xCD\x94\xCC\x99\xCC\x9D\xCC\x96\xCD\x94\xCC\xAB\xCC\xA7\xCC\xA5\xCC\x98\xCC\xBB\xCC\xAF\xCC\xABe\xCC\xB7\xCC\x8E\xCC\x82\xCD\x86\xCD\x9B\xCC\x94\xCD\x83\xCC\x85\xCD\x8A\xCD\x8C\xCC\x8B\xCD\x92\xCD\x91\xCC\x8F\xCC\x81\xCD\x95\xCC\xA2\xCC\xB9\xCC\xB2\xCD\x9C\xCC\xB1\xCC\xA6\xCC\xB3\xCC\xAF\xCC\xAE\xCC\x9C\xCD\x99s\xCC\xB8\xCC\x8C\xCC\x8E\xCC\x87\xCD\x81\xCD\x82\xCC\x86\xCD\x8C\xCD\x8C\xCC\x8B\xCC\x84\xCC\x8C\xCD\x84\xCD\x9B\xCD\x86\xCC\x93\xCD\x90\xCC\x85\xCC\x94\xCD\x98\xCD\x84\xCD\x92\xCD\x8B\xCC\x90\xCC\x83\xCC\x8F\xCD\x84\xCD\x81\xCD\x9B\xCC\x90\xCD\x81\xCC\x8F\xCC\xBD\xCC\x88\xCC\xBF\xCC\x88\xCC\x84\xCC\x8E\xCD\x99\xCD\x94\xCC\x99\xCD\x99\xCC\xB0\xCC\xA8\xCC\xA3\xCC\xA8\xCC\x96\xCC\x99\xCC\xAE\xCC\xBC\xCC\x99\xCD\x9A\xCC\xB2\xCC\xB1\xCC\x9F\xCC\xBB\xCC\xA6\xCD\x85\xCC\xAA\xCD\x89\xCC\x9D\xCC\x99\xCD\x96\xCC\xB1\xCC\xB1\xCC\x99\xCC\xA6\xCC\xA5\xCD\x95\xCC\xB2\xCC\xA0\xCD\x99 within")
+ set spell spelllang=en
+ redraw
+ redraw!
+ bwipe!
+ set nospell
+endfunc
+
func LoadAffAndDic(aff_contents, dic_contents)
throw 'skipped: Nvim does not support enc=latin1'
set enc=latin1
diff --git a/src/nvim/version.c b/src/nvim/version.c
index f3326beb4c..74a4852def 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -2030,14 +2030,19 @@ static void version_msg(char *s)
version_msg_wrap((char_u *)s, false);
}
-/// List all features aligned in columns, dictionary style.
+/// List all features.
+/// This does not use list_in_columns (as in Vim), because there are only a
+/// few, and we do not start at a new line.
static void list_features(void)
{
- list_in_columns((char_u **)features, -1, -1);
- if (msg_col > 0) {
- msg_putchar('\n');
+ version_msg(_("\n\nFeatures: "));
+ for (int i = 0; features[i] != NULL; i++) {
+ version_msg(features[i]);
+ if (features[i+1] != NULL) {
+ version_msg(" ");
+ }
}
- MSG_PUTS("See \":help feature-compile\"\n\n");
+ version_msg("\nSee \":help feature-compile\"\n\n");
}
/// List string items nicely aligned in columns.
@@ -2146,8 +2151,6 @@ void list_version(void)
}
#endif // ifdef HAVE_PATHDEF
- version_msg(_("\n\nFeatures: "));
-
list_features();
#ifdef SYS_VIMRC_FILE