diff options
-rw-r--r-- | runtime/doc/api.txt | 20 | ||||
-rw-r--r-- | runtime/doc/lsp.txt | 10 | ||||
-rw-r--r-- | runtime/filetype.vim | 9 | ||||
-rw-r--r-- | runtime/lua/vim/lsp.lua | 36 | ||||
-rw-r--r-- | src/nvim/api/buffer.c | 42 | ||||
-rw-r--r-- | src/nvim/api/private/helpers.c | 37 | ||||
-rw-r--r-- | src/nvim/api/vim.c | 42 | ||||
-rw-r--r-- | src/nvim/decoration.c | 2 | ||||
-rw-r--r-- | src/nvim/extmark.c | 9 | ||||
-rw-r--r-- | src/nvim/lua/vim.lua | 11 | ||||
-rw-r--r-- | src/nvim/message.c | 34 | ||||
-rw-r--r-- | src/nvim/message.h | 9 | ||||
-rw-r--r-- | src/nvim/normal.c | 29 | ||||
-rw-r--r-- | src/nvim/po/uk.po | 250 | ||||
-rw-r--r-- | src/nvim/spell.c | 11 | ||||
-rw-r--r-- | src/nvim/testdir/test_filetype.vim | 17 | ||||
-rw-r--r-- | src/nvim/testdir/test_fold.vim | 35 | ||||
-rw-r--r-- | src/nvim/testdir/test_highlight.vim | 14 | ||||
-rw-r--r-- | test/functional/api/extmark_spec.lua | 34 | ||||
-rw-r--r-- | test/functional/api/vim_spec.lua | 73 |
20 files changed, 576 insertions, 148 deletions
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt index 485c93b0dd..717a7caadf 100644 --- a/runtime/doc/api.txt +++ b/runtime/doc/api.txt @@ -663,6 +663,17 @@ nvim_del_var({name}) *nvim_del_var()* Parameters: ~ {name} Variable name +nvim_echo({chunks}, {history}, {opts}) *nvim_echo()* + Echo a message. + + Parameters: ~ + {chunks} A list of [text, hl_group] arrays, each + representing a text chunk with specified + highlight. `hl_group` element can be omitted + for no highlight. + {history} if true, add to |message-history|. + {opts} Optional parameters. Reserved for future use. + nvim_err_write({str}) *nvim_err_write()* Writes a message to the Vim error buffer. Does not append "\n", the message is buffered (won't display) until a linefeed @@ -2153,6 +2164,15 @@ nvim_buf_set_extmark({buffer}, {ns_id}, {line}, {col}, {opts}) mark will only be used for the current redraw cycle, and not be permantently stored in the buffer. + • right_gravity : boolean that indicates the + direction the extmark will be shifted in when + new text is inserted (true for right, false + for left). defaults to true. + • end_right_gravity : boolean that indicates the + direction the extmark end position (if it + exists) will be shifted in when new text is + inserted (true for right, false for left). + Defaults to false. Return: ~ Id of the created/updated extmark diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt index 772afdcc1a..06666c3a27 100644 --- a/runtime/doc/lsp.txt +++ b/runtime/doc/lsp.txt @@ -679,6 +679,14 @@ get_active_clients() *vim.lsp.get_active_clients()* Return: ~ Table of |vim.lsp.client| objects + *vim.lsp.get_buffers_by_client_id()* +get_buffers_by_client_id({client_id}) + Parameters: ~ + {client_id} client id + + Return: ~ + list of buffer ids + get_client_by_id({client_id}) *vim.lsp.get_client_by_id()* Gets a client by id, or nil if the id is invalid. The returned client may not yet be fully initialized. @@ -1754,7 +1762,7 @@ make_workspace_params({added}, {removed}) Create the workspace params Parameters: ~ - {added} + {added} {removed} *vim.lsp.util.open_floating_preview()* diff --git a/runtime/filetype.vim b/runtime/filetype.vim index 9104519451..1343a1fd0b 100644 --- a/runtime/filetype.vim +++ b/runtime/filetype.vim @@ -1733,8 +1733,13 @@ au BufNewFile,BufRead *.tli setf tli " Telix Salt au BufNewFile,BufRead *.slt setf tsalt -" Tera Term Language -au BufRead,BufNewFile *.ttl setf teraterm +" Tera Term Language or Turtle +au BufRead,BufNewFile *.ttl + \ if getline(1) =~ '^@\?\(prefix\|base\)' | + \ setf turtle | + \ else | + \ setf teraterm | + \ endif " Terminfo au BufNewFile,BufRead *.ti setf terminfo diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 64d08e9733..6229ee7359 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -121,6 +121,9 @@ local active_clients = {} local all_buffer_active_clients = {} local uninitialized_clients = {} +-- Tracks all buffers attached to a client. +local all_client_active_buffers = {} + --@private --- Invokes a function for each LSP client attached to the buffer {bufnr}. --- @@ -933,7 +936,7 @@ function lsp.buf_attach_client(bufnr, client_id) on_lines = text_document_did_change_handler; on_detach = function() local params = { textDocument = { uri = uri; } } - for_each_buffer_client(bufnr, function(client, _client_id) + for_each_buffer_client(bufnr, function(client, _) if client.resolved_capabilities.text_document_open_close then client.notify('textDocument/didClose', params) end @@ -947,6 +950,13 @@ function lsp.buf_attach_client(bufnr, client_id) utf_sizes = true; }) end + + if not all_client_active_buffers[client_id] then + all_client_active_buffers[client_id] = {} + end + + table.insert(all_client_active_buffers[client_id], bufnr) + if buffer_client_ids[client_id] then return end -- This is our first time attaching this client to this buffer. buffer_client_ids[client_id] = true @@ -978,6 +988,19 @@ function lsp.get_client_by_id(client_id) return active_clients[client_id] or uninitialized_clients[client_id] end +--- Returns list of buffers attached to client_id. +-- +--@param client_id client id +--@returns list of buffer ids +function lsp.get_buffers_by_client_id(client_id) + local active_client_buffers = all_client_active_buffers[client_id] + if active_client_buffers then + return active_client_buffers + else + return {} + end +end + --- Stops a client(s). --- --- You can also use the `stop()` function on a |vim.lsp.client| object. @@ -995,12 +1018,23 @@ end function lsp.stop_client(client_id, force) local ids = type(client_id) == 'table' and client_id or {client_id} for _, id in ipairs(ids) do + local resolved_client_id if type(id) == 'table' and id.stop ~= nil then id.stop(force) + resolved_client_id = id.id elseif active_clients[id] then active_clients[id].stop(force) + resolved_client_id = id elseif uninitialized_clients[id] then uninitialized_clients[id].stop(true) + resolved_client_id = id + end + if resolved_client_id then + local client_buffers = lsp.get_buffers_by_client_id(resolved_client_id) + for idx = 1, #client_buffers do + lsp.diagnostic.clear(client_buffers[idx], resolved_client_id) + end + all_client_active_buffers[resolved_client_id] = nil end end end diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 8d82d22040..2890d89bc0 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -1400,6 +1400,13 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, /// callbacks. The mark will only be used for the current /// redraw cycle, and not be permantently stored in the /// buffer. +/// - right_gravity : boolean that indicates the direction +/// the extmark will be shifted in when new text is inserted +/// (true for right, false for left). defaults to true. +/// - end_right_gravity : boolean that indicates the direction +/// the extmark end position (if it exists) will be shifted +/// in when new text is inserted (true for right, false +/// for left). Defaults to false. /// @param[out] err Error details, if any /// @return Id of the created/updated extmark Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, @@ -1440,6 +1447,10 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, DecorPriority priority = DECOR_PRIORITY_BASE; colnr_T col2 = 0; VirtText virt_text = KV_INITIAL_VALUE; + bool right_gravity = true; + bool end_right_gravity = false; + bool end_gravity_set = false; + for (size_t i = 0; i < opts.size; i++) { String k = opts.items[i].key; Object *v = &opts.items[i].value; @@ -1522,12 +1533,35 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, goto error; } priority = (DecorPriority)v->data.integer; + } else if (strequal("right_gravity", k.data)) { + if (v->type != kObjectTypeBoolean) { + api_set_error(err, kErrorTypeValidation, + "right_gravity must be a boolean"); + goto error; + } + right_gravity = v->data.boolean; + } else if (strequal("end_right_gravity", k.data)) { + if (v->type != kObjectTypeBoolean) { + api_set_error(err, kErrorTypeValidation, + "end_right_gravity must be a boolean"); + goto error; + } + end_right_gravity = v->data.boolean; + end_gravity_set = true; } else { api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data); goto error; } } + // Only error out if they try to set end_right_gravity without + // setting end_col or end_line + if (line2 == -1 && col2 == 0 && end_gravity_set) { + api_set_error(err, kErrorTypeValidation, + "cannot set end_right_gravity " + "without setting end_line or end_col"); + } + if (col2 >= 0) { if (line2 >= 0 && line2 < buf->b_ml.ml_line_count) { len = STRLEN(ml_get_buf(buf, (linenr_T)line2 + 1, false)); @@ -1572,7 +1606,8 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, } id = extmark_set(buf, (uint64_t)ns_id, id, (int)line, (colnr_T)col, - line2, col2, decor, kExtmarkNoUndo); + line2, col2, decor, right_gravity, + end_right_gravity, kExtmarkNoUndo); } return (Integer)id; @@ -1687,7 +1722,7 @@ Integer nvim_buf_add_highlight(Buffer buffer, extmark_set(buf, ns_id, 0, (int)line, (colnr_T)col_start, end_line, (colnr_T)col_end, - decor_hl(hl_id), kExtmarkNoUndo); + decor_hl(hl_id), true, false, kExtmarkNoUndo); return src_id; } @@ -1796,7 +1831,8 @@ Integer nvim_buf_set_virtual_text(Buffer buffer, Decoration *decor = xcalloc(1, sizeof(*decor)); decor->virt_text = virt_text; - extmark_set(buf, ns_id, 0, (int)line, 0, -1, -1, decor, kExtmarkNoUndo); + extmark_set(buf, ns_id, 0, (int)line, 0, -1, -1, decor, true, + false, kExtmarkNoUndo); return src_id; } diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 8f224e8c78..7cee569989 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -1645,6 +1645,43 @@ bool api_object_to_bool(Object obj, const char *what, } } +HlMessage parse_hl_msg(Array chunks, Error *err) +{ + HlMessage hl_msg = KV_INITIAL_VALUE; + for (size_t i = 0; i < chunks.size; i++) { + if (chunks.items[i].type != kObjectTypeArray) { + api_set_error(err, kErrorTypeValidation, "Chunk is not an array"); + goto free_exit; + } + Array chunk = chunks.items[i].data.array; + if (chunk.size == 0 || chunk.size > 2 + || chunk.items[0].type != kObjectTypeString + || (chunk.size == 2 && chunk.items[1].type != kObjectTypeString)) { + api_set_error(err, kErrorTypeValidation, + "Chunk is not an array with one or two strings"); + goto free_exit; + } + + String str = copy_string(chunk.items[0].data.string); + + int attr = 0; + if (chunk.size == 2) { + String hl = chunk.items[1].data.string; + if (hl.size > 0) { + int hl_id = syn_check_group((char_u *)hl.data, (int)hl.size); + attr = hl_id > 0 ? syn_id2attr(hl_id) : 0; + } + } + kv_push(hl_msg, ((HlMessageChunk){ .text = str, .attr = attr })); + } + + return hl_msg; + +free_exit: + clear_hl_msg(&hl_msg); + return hl_msg; +} + const char *describe_ns(NS ns_id) { String name; diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 1e972e01be..09895a2119 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -990,6 +990,48 @@ void nvim_set_option(uint64_t channel_id, String name, Object value, Error *err) set_option_to(channel_id, NULL, SREQ_GLOBAL, name, value, err); } +/// Echo a message. +/// +/// @param chunks A list of [text, hl_group] arrays, each representing a +/// text chunk with specified highlight. `hl_group` element +/// can be omitted for no highlight. +/// @param history if true, add to |message-history|. +/// @param opts Optional parameters. Reserved for future use. +void nvim_echo(Array chunks, Boolean history, Dictionary opts, Error *err) + FUNC_API_SINCE(7) +{ + HlMessage hl_msg = parse_hl_msg(chunks, err); + if (ERROR_SET(err)) { + goto error; + } + + if (opts.size > 0) { + api_set_error(err, kErrorTypeValidation, "opts dict isn't empty"); + goto error; + } + + no_wait_return++; + msg_start(); + msg_clr_eos(); + bool need_clear = false; + for (uint32_t i = 0; i < kv_size(hl_msg); i++) { + HlMessageChunk chunk = kv_A(hl_msg, i); + msg_multiline_attr((const char *)chunk.text.data, chunk.attr, + false, &need_clear); + } + if (history) { + msg_ext_set_kind("echomsg"); + add_hl_msg_hist(hl_msg); + } else { + msg_ext_set_kind("echo"); + } + no_wait_return--; + msg_end(); + +error: + clear_hl_msg(&hl_msg); +} + /// Writes a message to the Vim output buffer. Does not append "\n", the /// message is buffered (won't display) until a linefeed is written. /// diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c index e6a616c927..f3ee42fab1 100644 --- a/src/nvim/decoration.c +++ b/src/nvim/decoration.c @@ -69,7 +69,7 @@ void bufhl_add_hl_pos_offset(buf_T *buf, } (void)extmark_set(buf, (uint64_t)src_id, 0, (int)lnum-1, hl_start, (int)lnum-1+end_off, hl_end, - decor, kExtmarkNoUndo); + decor, true, false, kExtmarkNoUndo); } } diff --git a/src/nvim/extmark.c b/src/nvim/extmark.c index b2d8532cd7..cacbeddb32 100644 --- a/src/nvim/extmark.c +++ b/src/nvim/extmark.c @@ -71,7 +71,8 @@ static ExtmarkNs *buf_ns_ref(buf_T *buf, uint64_t ns_id, bool put) { /// @returns the mark id uint64_t extmark_set(buf_T *buf, uint64_t ns_id, uint64_t id, int row, colnr_T col, int end_row, colnr_T end_col, - Decoration *decor, ExtmarkOp op) + Decoration *decor, bool right_gravity, + bool end_right_gravity, ExtmarkOp op) { ExtmarkNs *ns = buf_ns_ref(buf, ns_id, true); assert(ns != NULL); @@ -109,10 +110,10 @@ uint64_t extmark_set(buf_T *buf, uint64_t ns_id, uint64_t id, if (end_row > -1) { mark = marktree_put_pair(buf->b_marktree, - row, col, true, - end_row, end_col, false); + row, col, right_gravity, + end_row, end_col, end_right_gravity); } else { - mark = marktree_put(buf->b_marktree, row, col, true); + mark = marktree_put(buf->b_marktree, row, col, right_gravity); } revised: diff --git a/src/nvim/lua/vim.lua b/src/nvim/lua/vim.lua index b20fbbf038..80b311de2c 100644 --- a/src/nvim/lua/vim.lua +++ b/src/nvim/lua/vim.lua @@ -121,10 +121,17 @@ function vim._load_package(name) end for _,trail in ipairs(vim._so_trails) do - local path = "lua/"..trail:gsub('?',basename) + local path = "lua"..trail:gsub('?', basename) -- so_trails contains a leading slash local found = vim.api.nvim_get_runtime_file(path, false) if #found > 0 then - local f, err = package.loadlib(found[1]) + -- Making function name in Lua 5.1 (see src/loadlib.c:mkfuncname) is + -- a) strip prefix up to and including the first dash, if any + -- b) replace all dots by underscores + -- c) prepend "luaopen_" + -- So "foo-bar.baz" should result in "luaopen_bar_baz" + local dash = name:find("-", 1, true) + local modname = dash and name:sub(dash + 1) or name + local f, err = package.loadlib(found[1], "luaopen_"..modname:gsub("%.", "_")) return f or error(err) end end diff --git a/src/nvim/message.c b/src/nvim/message.c index f94529c687..ba7a667a60 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -890,6 +890,40 @@ char_u *msg_may_trunc(int force, char_u *s) return s; } +void clear_hl_msg(HlMessage *hl_msg) +{ + for (size_t i = 0; i < kv_size(*hl_msg); i++) { + xfree(kv_A(*hl_msg, i).text.data); + } + kv_destroy(*hl_msg); + *hl_msg = (HlMessage)KV_INITIAL_VALUE; +} + +#define LINE_BUFFER_SIZE 4096 + +void add_hl_msg_hist(HlMessage hl_msg) +{ + // TODO(notomo): support multi highlighted message history + size_t pos = 0; + char buf[LINE_BUFFER_SIZE]; + for (uint32_t i = 0; i < kv_size(hl_msg); i++) { + HlMessageChunk chunk = kv_A(hl_msg, i); + for (uint32_t j = 0; j < chunk.text.size; j++) { + if (pos == LINE_BUFFER_SIZE - 1) { + buf[pos] = NUL; + add_msg_hist((const char *)buf, -1, MSG_HIST, true); + pos = 0; + continue; + } + buf[pos++] = chunk.text.data[j]; + } + } + if (pos != 0) { + buf[pos] = NUL; + add_msg_hist((const char *)buf, -1, MSG_HIST, true); + } +} + /// @param[in] len Length of s or -1. static void add_msg_hist(const char *s, int len, int attr, bool multiline) { diff --git a/src/nvim/message.h b/src/nvim/message.h index fdb9bc96ca..377c725fa1 100644 --- a/src/nvim/message.h +++ b/src/nvim/message.h @@ -8,6 +8,8 @@ #include "nvim/macros.h" #include "nvim/types.h" #include "nvim/grid_defs.h" +#include "nvim/api/private/defs.h" +#include "nvim/lib/kvec.h" /* * Types of dialogs passed to do_dialog(). @@ -75,6 +77,13 @@ /// Like #MSG_PUTS_ATTR, but if middle part of long messages will be replaced #define MSG_PUTS_LONG_ATTR(s, a) msg_puts_long_attr((char_u *)(s), (a)) +typedef struct { + String text; + int attr; +} HlMessageChunk; + +typedef kvec_t(HlMessageChunk) HlMessage; + /// Message history for `:messages` typedef struct msg_hist { struct msg_hist *next; ///< Next message. diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 4e955667dc..8f22243348 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -3978,16 +3978,19 @@ static bool nv_screengo(oparg_T *oap, int dir, long dist) curwin->w_curswant -= width2; } else { // to previous line + + // Move to the start of a closed fold. Don't do that when + // 'foldopen' contains "all": it will open in a moment. + if (!(fdo_flags & FDO_ALL)) { + (void)hasFolding(curwin->w_cursor.lnum, + &curwin->w_cursor.lnum, NULL); + } if (curwin->w_cursor.lnum == 1) { retval = false; break; } - --curwin->w_cursor.lnum; - /* Move to the start of a closed fold. Don't do that when - * 'foldopen' contains "all": it will open in a moment. */ - if (!(fdo_flags & FDO_ALL)) - (void)hasFolding(curwin->w_cursor.lnum, - &curwin->w_cursor.lnum, NULL); + curwin->w_cursor.lnum--; + linelen = linetabsize(get_cursor_line_ptr()); if (linelen > width1) { int w = (((linelen - width1 - 1) / width2) + 1) * width2; @@ -6708,11 +6711,8 @@ static void nv_g_cmd(cmdarg_T *cap) */ case 'j': case K_DOWN: - /* with 'nowrap' it works just like the normal "j" command; also when - * in a closed fold */ - if (!curwin->w_p_wrap - || hasFolding(curwin->w_cursor.lnum, NULL, NULL) - ) { + // with 'nowrap' it works just like the normal "j" command. + if (!curwin->w_p_wrap) { oap->motion_type = kMTLineWise; i = cursor_down(cap->count1, oap->op_type == OP_NOP); } else @@ -6723,11 +6723,8 @@ static void nv_g_cmd(cmdarg_T *cap) case 'k': case K_UP: - /* with 'nowrap' it works just like the normal "k" command; also when - * in a closed fold */ - if (!curwin->w_p_wrap - || hasFolding(curwin->w_cursor.lnum, NULL, NULL) - ) { + // with 'nowrap' it works just like the normal "k" command. + if (!curwin->w_p_wrap) { oap->motion_type = kMTLineWise; i = cursor_up(cap->count1, oap->op_type == OP_NOP); } else diff --git a/src/nvim/po/uk.po b/src/nvim/po/uk.po index 2a5cb54f7b..f0ae154648 100644 --- a/src/nvim/po/uk.po +++ b/src/nvim/po/uk.po @@ -14,7 +14,7 @@ msgid "" msgstr "" "Project-Id-Version: vim 7.4\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-23 18:45+0300\n" +"POT-Creation-Date: 2021-01-18 17:46+0200\n" "PO-Revision-Date: 2020-08-23 20:19+0300\n" "Last-Translator: Анатолій Сахнік <sakhnik@gmail.com>\n" "Language-Team: Ukrainian\n" @@ -23,6 +23,67 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +msgid "--Deleted--" +msgstr "--Знищено--" + +#, c-format +msgid "auto-removing autocommand: %s <buffer=%d>" +msgstr "Автоматичне знищення автокоманди: %s <буфер=%d>" + +#, c-format +msgid "E367: No such group: \"%s\"" +msgstr "E367: Немає такої групи: «%s»" + +msgid "E936: Cannot delete the current group" +msgstr "E936: Не вдалося знищити цю групу" + +msgid "W19: Deleting augroup that is still in use" +msgstr "W19: Знищення автогрупи, яка все ще використовується" + +#, c-format +msgid "E215: Illegal character after *: %s" +msgstr "E215: Недозволений символ після *: %s" + +#, c-format +msgid "E216: No such event: %s" +msgstr "E216: Немає такої події: %s" + +#, c-format +msgid "E216: No such group or event: %s" +msgstr "E216: Немає такої групи чи події: %s" + +msgid "" +"\n" +"--- Autocommands ---" +msgstr "" +"\n" +"--- Автокоманди ---" + +#, c-format +msgid "E680: <buffer=%d>: invalid buffer number " +msgstr "E680: <буфер=%d>: некоректний номер буфера " + +msgid "E217: Can't execute autocommands for ALL events" +msgstr "E217: Не можу виконувати автокоманди для УСІХ подій" + +msgid "No matching autocommands" +msgstr "Немає відповідних автокоманд" + +msgid "E218: autocommand nesting too deep" +msgstr "E218: Забагато вкладених автокоманд" + +#, c-format +msgid "%s Autocommands for \"%s\"" +msgstr "%s Автокоманди для «%s»" + +#, c-format +msgid "Executing %s" +msgstr "Виконується %s" + +#, c-format +msgid "autocommand %s" +msgstr "автокоманда %s" + msgid "[Location List]" msgstr "[Список місць]" @@ -95,9 +156,15 @@ msgid "" "E89: No write since last change for buffer %<PRId64> (add ! to override)" msgstr "E89: Буфер %<PRId64> має зміни (! щоб не зважати)" +msgid "E948: Job still running (add ! to end the job)" +msgstr "E948: Задача все ще виконується (! щоб закінчити)" + msgid "E37: No write since last change (add ! to override)" msgstr "E37: Зміни не було записано (! щоб не зважати)" +msgid "E948: Job still running" +msgstr "E948: Задача все ще виконується" + msgid "E37: No write since last change" msgstr "E37: Не записано після останніх змін" @@ -465,6 +532,10 @@ msgid "E957: Invalid window number" msgstr "E957: Некоректний номер вікна" #, c-format +msgid "E940: Cannot lock or unlock variable %s" +msgstr "E940: Неможливо заблокувати чи розблокувати змінну %s" + +#, c-format msgid "E734: Wrong variable type for %s=" msgstr "E734: Неправильний тип змінної для %s=" @@ -544,10 +615,6 @@ msgstr "E690: Пропущено «in» після :for" msgid "E108: No such variable: \"%s\"" msgstr "E108: Змінної немає: «%s»" -#, c-format -msgid "E940: Cannot lock or unlock variable %s" -msgstr "E940: Неможливо заблокувати чи розблокувати змінну %s" - msgid "E109: Missing ':' after '?'" msgstr "E109: Бракує ':' після '?'" @@ -950,9 +1017,6 @@ msgstr "E684: Індекс списку поза межами: %<PRId64>" msgid "E686: Argument of %s must be a List" msgstr "E686: Аргумент у %s має бути списком" -msgid "E928: String required" -msgstr "E928: Потрібен String" - #, c-format msgid "Error converting the call result: %s" msgstr "Не вдалося перетворити результат виклику: %s" @@ -1591,6 +1655,10 @@ msgid "Close \"%s\"?" msgstr "Закрити «%s»?" #, c-format +msgid "E947: Job still running in buffer \"%s\"" +msgstr "E947: Задача все ще запущена у буфері «%s»" + +#, c-format msgid "E162: No write since last change for buffer \"%s\"" msgstr "E162: Буфер «%s» має незбережені зміни" @@ -1615,18 +1683,6 @@ msgid "E666: compiler not supported: %s" msgstr "E666: Компілятор не підтримується: %s" #, c-format -msgid "Searching for \"%s\" in \"%s\"" -msgstr "Пошук «%s» в «%s»" - -#, c-format -msgid "Searching for \"%s\"" -msgstr "Пошук «%s»" - -#, c-format -msgid "not found in '%s': \"%s\"" -msgstr "не знайдено в '%s': «%s»" - -#, c-format msgid ":source error parsing command %s" msgstr ":source помилка розбору команди %s" @@ -1702,12 +1758,16 @@ msgstr "Режим Ex. Для повернення до нормального msgid "E501: At end-of-file" msgstr "E501: Кінець файлу" -msgid "E169: Command too recursive" -msgstr "E169: Команда занадто рекурсивна" +#, c-format +msgid "Executing: %s" +msgstr "Виконується: %s" msgid "line %" msgstr "рядок %" +msgid "E169: Command too recursive" +msgstr "E169: Команда занадто рекурсивна" + #, c-format msgid "E605: Exception not caught: %s" msgstr "E605: Виняткова ситуація не оброблена: %s" @@ -1724,9 +1784,6 @@ msgstr "E464: Неоднозначний вжиток команди корис msgid "E492: Not an editor command" msgstr "E492: Це не команда редактора" -msgid "E981: Command not allowed in restricted mode" -msgstr "E981: Команду не дозволено у обмеженому режимі" - msgid "E493: Backwards range given" msgstr "E493: Інтервал задано навиворіт" @@ -1736,6 +1793,11 @@ msgstr "Інтервал задано навиворіт, щоб помінят msgid "E494: Use w or w>>" msgstr "E494: Спробуйте w або w>>" +msgid "" +"INTERNAL: Cannot use EX_DFLALL with ADDR_NONE, ADDR_UNSIGNED or ADDR_QUICKFIX" +msgstr "" +"ВНУТРІШНЄ: Не можна вживати EX_DFLALL з ADDR_NONE, ADDR_UNSIGNED чи ADDR_QUICKFIX" + msgid "E943: Command table needs to be updated, run 'make'" msgstr "E943: Потрібно поновити таблицю команд, запустіть 'make'" @@ -1762,10 +1824,10 @@ msgstr "E174: Команда вже існує, ! щоб замінити її: msgid "" "\n" -" Name Args Address Complete Definition" +" Name Args Address Complete Definition" msgstr "" "\n" -" Назва Арг. Адреса Доповнення Визначення" +" Назва Арг. Адреса Доповнення Визначення" msgid "No user-defined commands found" msgstr "Не знайдено команд користувача" @@ -2077,12 +2139,12 @@ msgstr "E347: У шляху пошуку більше немає файлів « msgid "E812: Autocommands changed buffer or buffer name" msgstr "E812: Автокоманди змінили буфер чи його назву" -msgid "Illegal file name" -msgstr "Недозволена назва файлу" - msgid "is a directory" msgstr "каталог" +msgid "Illegal file name" +msgstr "Недозволена назва файлу" + msgid "is not a file" msgstr "не файл" @@ -2104,9 +2166,6 @@ msgstr "E201: Автокоманди *ReadPre не повинні змінюва msgid "E202: Conversion made file unreadable!" msgstr "E202: Конвертація унеможливила читання файлу!" -msgid "[fifo/socket]" -msgstr "[канал/сокет]" - msgid "[fifo]" msgstr "[канал]" @@ -2353,67 +2412,6 @@ msgstr "E462: Не вдалося підготувати «%s», щоб пере msgid "E321: Could not reload \"%s\"" msgstr "E321: Не вдалося перечитати «%s»" -msgid "--Deleted--" -msgstr "--Знищено--" - -#, c-format -msgid "auto-removing autocommand: %s <buffer=%d>" -msgstr "Автоматичне знищення автокоманди: %s <буфер=%d>" - -#, c-format -msgid "E367: No such group: \"%s\"" -msgstr "E367: Немає такої групи: «%s»" - -msgid "E936: Cannot delete the current group" -msgstr "E936: Не вдалося знищити цю групу" - -msgid "W19: Deleting augroup that is still in use" -msgstr "W19: Знищення автогрупи, яка все ще використовується" - -#, c-format -msgid "E215: Illegal character after *: %s" -msgstr "E215: Недозволений символ після *: %s" - -#, c-format -msgid "E216: No such event: %s" -msgstr "E216: Немає такої події: %s" - -#, c-format -msgid "E216: No such group or event: %s" -msgstr "E216: Немає такої групи чи події: %s" - -msgid "" -"\n" -"--- Autocommands ---" -msgstr "" -"\n" -"--- Автокоманди ---" - -#, c-format -msgid "E680: <buffer=%d>: invalid buffer number " -msgstr "E680: <буфер=%d>: некоректний номер буфера " - -msgid "E217: Can't execute autocommands for ALL events" -msgstr "E217: Не можу виконувати автокоманди для УСІХ подій" - -msgid "No matching autocommands" -msgstr "Немає відповідних автокоманд" - -msgid "E218: autocommand nesting too deep" -msgstr "E218: Забагато вкладених автокоманд" - -#, c-format -msgid "%s Autocommands for \"%s\"" -msgstr "%s Автокоманди для «%s»" - -#, c-format -msgid "Executing %s" -msgstr "Виконується %s" - -#, c-format -msgid "autocommand %s" -msgstr "автокоманда %s" - msgid "E219: Missing {." msgstr "E219: Бракує {." @@ -2519,9 +2517,6 @@ msgstr "E685: Внутрішня помилка: %s" msgid "Interrupted" msgstr "Перервано" -msgid "E14: Invalid address" -msgstr "E14: Неправильна адреса" - msgid "E474: Invalid argument" msgstr "E474: Некоректний аргумент" @@ -2719,6 +2714,9 @@ msgstr "E45: Встановлено опцію 'readonly' (! щоб не зва msgid "E46: Cannot change read-only variable \"%.*s\"" msgstr "E46: Змінна тільки для читання: «%.*s»" +msgid "E928: String required" +msgstr "E928: Потрібен String" + msgid "E715: Dictionary required" msgstr "E715: Потрібен словник" @@ -2727,8 +2725,8 @@ msgid "E118: Too many arguments for function: %s" msgstr "E118: Забагато аргументів для функції: %s" #, c-format -msgid "E716: Key not present in Dictionary: %s" -msgstr "E716: Немає такого ключа у словнику: %s" +msgid "E716: Key not present in Dictionary: \"%s\"" +msgstr "E716: Немає такого ключа у словнику: «%s»" msgid "E714: List required" msgstr "E714: Потрібен список" @@ -3158,6 +3156,10 @@ msgid "E5106: Error while creating shared module: %.*s" msgstr "E5106: Помилка створення розділюваного модуля: %.*s" #, c-format +msgid "E5106: Error while creating inspect module: %.*s" +msgstr "E5106: Помилка створення модуля inspect: %.*s" + +#, c-format msgid "E5106: Error while creating vim module: %.*s" msgstr "E5106: Помилка створення модуля vim: %.*s" @@ -3165,10 +3167,6 @@ msgid "E970: Failed to initialize lua interpreter" msgstr "E970: Не вдалося ініціалізувати інтерпретатор lua" #, c-format -msgid "E5117: Error while updating package paths: %.*s" -msgstr "E5117: Помилка оновлення шляхів пакунку: %.*s" - -#, c-format msgid "E5114: Error while converting print argument #%i: %.*s" msgstr "E5114: Не вдалося перетворити аргумент #%i друку: %.*s" @@ -3256,6 +3254,10 @@ msgid "pre-vimrc command line" msgstr "команди перед vimrc" #, c-format +msgid "Conflicting configs: \"%s\" \"%s\"" +msgstr "Суперечливі конфігурації: «%s» «%s»" + +#, c-format msgid "E282: Cannot read from \"%s\"" msgstr "E282: Не вдалося прочитати з «%s»" @@ -4002,8 +4004,7 @@ msgstr "" "Введіть :qa! і натисність <Enter> щоб відкинути всі зміни і вийти Nvim" msgid "Type :qa and press <Enter> to exit Nvim" -msgstr "" -"Введіть :qa і натисність <Enter> щоб вийти з Nvim" +msgstr "Введіть :qa і натисність <Enter> щоб вийти з Nvim" #, c-format msgid "1 line %sed 1 time" @@ -4068,10 +4069,10 @@ msgstr "E353: У регістрі %s нічого немає" msgid "" "\n" -"--- Registers ---" +"Type Name Content" msgstr "" "\n" -"--- Регістри ---" +"Тип Наз. Вміст " msgid "" "E883: search pattern and expression register may not contain two or more " @@ -4184,9 +4185,6 @@ msgstr "E537: 'commentstring' має бути порожньою чи місти msgid "E540: Unclosed expression sequence" msgstr "E540: Послідовність виразів не завершено" -msgid "E541: too many items" -msgstr "E541: Забагато елементів" - msgid "E542: unbalanced groups" msgstr "E542: Групи не збалансовано" @@ -4274,6 +4272,9 @@ msgstr "" msgid "E5677: Error writing input to shell-command: %s" msgstr "E5677: Не вдалося записати на вхід команди оболонки: %s" +msgid "%a %b %d %H:%M:%S %Y" +msgstr "%H:%M:%S %a, %d %B %Y р." + #, c-format msgid "E447: Can't find file \"%s\" in path" msgstr "E447: Файл «%s» не знайдено у шляху пошуку" @@ -4281,8 +4282,11 @@ msgstr "E447: Файл «%s» не знайдено у шляху пошуку" msgid "E553: No more items" msgstr "E553: Немає більше елементів" +msgid "E925: Current quickfix list was changed" +msgstr "E925: Поточний список quickfix змінився" + msgid "E926: Current location list was changed" -msgstr "E926: Цей список місць було змінено" +msgstr "E926: Поточний список місць змінився" #, c-format msgid "E372: Too many %%%c in format string" @@ -4316,9 +4320,6 @@ msgstr "E379: Пропущена чи порожня назва каталогу msgid "E924: Current window was closed" msgstr "E924: Активне вікно було закрито" -msgid "E925: Current quickfix was changed" -msgstr "E925: Цей quickfix було змінено" - #, c-format msgid "(%d of %d)%s%s: " msgstr "(%d з %d)%s%s: " @@ -4346,6 +4347,9 @@ msgstr "E683: Пропущено назву файлу чи некоректни msgid "Cannot open file \"%s\"" msgstr "Не вдалося відкрити файл «%s»" +msgid "cannot have both a list and a \"what\" argument" +msgstr "не можна задавати одночасно список і аргумент «що»" + msgid "E681: Buffer is not loaded" msgstr "E681: Буфер не завантажено" @@ -4466,6 +4470,18 @@ msgstr "" msgid "Switching to backtracking RE engine for pattern: " msgstr "Перемикання до простого рушія регулярних виразів: " +#, c-format +msgid "Searching for \"%s\" in \"%s\"" +msgstr "Пошук «%s» в «%s»" + +#, c-format +msgid "Searching for \"%s\"" +msgstr "Пошук «%s»" + +#, c-format +msgid "not found in '%s': \"%s\"" +msgstr "не знайдено в '%s': «%s»" + msgid " TERMINAL" msgstr " ТЕРМІНАЛ" @@ -5249,6 +5265,9 @@ msgstr "синхронізується по коментарях стилю С" msgid "no syncing" msgstr "без синхронізації" +msgid "syncing starts at the first line" +msgstr "синхронізація починається з першого рядка" + msgid "syncing starts " msgstr "починається синхронізація за " @@ -5280,6 +5299,9 @@ msgstr "" msgid "E392: No such syntax cluster: %s" msgstr "E392: Немає такого синтаксичного кластера: %s" +msgid "from the first line" +msgstr "з першого рядка" + msgid "minimal " msgstr "мінімальний " diff --git a/src/nvim/spell.c b/src/nvim/spell.c index 5714f5e425..6425c9fed5 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -3123,6 +3123,7 @@ spell_find_suggest ( static bool expr_busy = false; int c; langp_T *lp; + bool did_intern = false; // Set the info in "*su". memset(su, 0, sizeof(suginfo_T)); @@ -3206,14 +3207,16 @@ spell_find_suggest ( spell_suggest_expr(su, buf + 5); expr_busy = false; } - } else if (STRNCMP(buf, "file:", 5) == 0) + } else if (STRNCMP(buf, "file:", 5) == 0) { // Use list of suggestions in a file. spell_suggest_file(su, buf + 5); - else { - // Use internal method. + } else if (!did_intern) { + // Use internal method once. spell_suggest_intern(su, interactive); - if (sps_flags & SPS_DOUBLE) + if (sps_flags & SPS_DOUBLE) { do_combine = true; + } + did_intern = true; } } diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim index 180170fe9a..815827e224 100644 --- a/src/nvim/testdir/test_filetype.vim +++ b/src/nvim/testdir/test_filetype.vim @@ -692,6 +692,23 @@ func Test_ts_file() filetype off endfunc +func Test_ttl_file() + filetype on + + call writefile(['@base <http://example.org/> .'], 'Xfile.ttl') + split Xfile.ttl + call assert_equal('turtle', &filetype) + bwipe! + + call writefile(['looks like Tera Term Language'], 'Xfile.ttl') + split Xfile.ttl + call assert_equal('teraterm', &filetype) + bwipe! + + call delete('Xfile.ttl') + filetype off +endfunc + func Test_pp_file() filetype on diff --git a/src/nvim/testdir/test_fold.vim b/src/nvim/testdir/test_fold.vim index 88ce64b9eb..18f328acf4 100644 --- a/src/nvim/testdir/test_fold.vim +++ b/src/nvim/testdir/test_fold.vim @@ -822,4 +822,39 @@ func Test_fold_create_delete() bwipe! endfunc +func Test_fold_relative_move() + enew! + set fdm=indent sw=2 wrap tw=80 + + let content = [ ' foo', ' bar', ' baz', + \ repeat('x', 100), + \ ' foo', ' bar', ' baz' + \ ] + call append(0, content) + + normal zM + + call cursor(3, 1) + call assert_true(foldclosed(line('.'))) + normal gj + call assert_equal(2, winline()) + + call cursor(2, 1) + call assert_true(foldclosed(line('.'))) + normal 2gj + call assert_equal(3, winline()) + + call cursor(5, 1) + call assert_true(foldclosed(line('.'))) + normal gk + call assert_equal(3, winline()) + + call cursor(6, 1) + call assert_true(foldclosed(line('.'))) + normal 2gk + call assert_equal(2, winline()) + + set fdm& sw& wrap& tw& +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_highlight.vim b/src/nvim/testdir/test_highlight.vim index 8f6834c2ab..4cc4d775d1 100644 --- a/src/nvim/testdir/test_highlight.vim +++ b/src/nvim/testdir/test_highlight.vim @@ -2,6 +2,7 @@ source view_util.vim source screendump.vim +source check.vim func Test_highlight() " basic test if ":highlight" doesn't crash @@ -610,3 +611,16 @@ func Test_1_highlight_Normalgroup_exists() call assert_match('hi Normal\s*font=.*', hlNormal) endif endfunc + +" Test for using RGB color values in a highlight group +func Test_xxlast_highlight_RGB_color() + CheckCanRunGui + gui -f + hi MySearch guifg=#110000 guibg=#001100 guisp=#000011 + call assert_equal('#110000', synIDattr(synIDtrans(hlID('MySearch')), 'fg#')) + call assert_equal('#001100', synIDattr(synIDtrans(hlID('MySearch')), 'bg#')) + call assert_equal('#000011', synIDattr(synIDtrans(hlID('MySearch')), 'sp#')) + hi clear +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index ab913ba4a4..d2b555ee5b 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -1389,6 +1389,40 @@ describe('API/extmarks', function() undo]],false) eq(2, meths.eval('1+1')) -- did not crash end) + + it('works with left and right gravity', function() + -- right gravity should move with inserted text, while + -- left gravity should stay in place. + curbufmeths.set_extmark(ns, 0, 5, {right_gravity = false}) + curbufmeths.set_extmark(ns, 0, 5, {right_gravity = true}) + feed([[Aasdfasdf]]) + + eq({ {1, 0, 5}, {2, 0, 13} }, + curbufmeths.get_extmarks(ns, 0, -1, {})) + + -- but both move when text is inserted before + feed([[<esc>Iasdf<esc>]]) + -- eq({}, curbufmeths.get_lines(0, -1, true)) + eq({ {1, 0, 9}, {2, 0, 17} }, + curbufmeths.get_extmarks(ns, 0, -1, {})) + + -- clear text + curbufmeths.set_text(0, 0, 0, 17, {}) + + -- handles set_text correctly as well + eq({ {1, 0, 0}, {2, 0, 0} }, + meths.buf_get_extmarks(0, ns, 0, -1, {})) + curbufmeths.set_text(0, 0, 0, 0, {'asdfasdf'}) + eq({ {1, 0, 0}, {2, 0, 8} }, + curbufmeths.get_extmarks(ns, 0, -1, {})) + + feed('u') + -- handles pasting + meths.exec([[let @a='asdfasdf']], false) + feed([["ap]]) + eq({ {1, 0, 0}, {2, 0, 8} }, + meths.buf_get_extmarks(0, ns, 0, -1, {})) + end) end) describe('Extmarks buffer api with many marks', function() diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 30128e9c40..3ff3efb8c9 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -2002,4 +2002,77 @@ describe('API', function() }, meths.get_option_info'showcmd') end) end) + + describe('nvim_echo', function() + local screen + + before_each(function() + clear() + screen = Screen.new(40, 8) + screen:attach() + screen:set_default_attr_ids({ + [0] = {bold=true, foreground=Screen.colors.Blue}, + [1] = {bold = true, foreground = Screen.colors.SeaGreen}, + [2] = {bold = true, reverse = true}, + [3] = {foreground = Screen.colors.Brown, bold = true}, -- Statement + [4] = {foreground = Screen.colors.SlateBlue}, -- Special + }) + command('highlight Statement gui=bold guifg=Brown') + command('highlight Special guifg=SlateBlue') + end) + + it('should clear cmdline message before echo', function() + feed(':call nvim_echo([["msg"]], v:false, {})<CR>') + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + msg | + ]]} + end) + + it('can show highlighted line', function() + nvim_async("echo", {{"msg_a"}, {"msg_b", "Statement"}, {"msg_c", "Special"}}, true, {}) + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + msg_a{3:msg_b}{4:msg_c} | + ]]} + end) + + it('can show highlighted multiline', function() + nvim_async("echo", {{"msg_a\nmsg_a", "Statement"}, {"msg_b", "Special"}}, true, {}) + screen:expect{grid=[[ + | + {0:~ }| + {0:~ }| + {0:~ }| + {2: }| + {3:msg_a} | + {3:msg_a}{4:msg_b} | + {1:Press ENTER or type command to continue}^ | + ]]} + end) + + it('can save message history', function() + nvim('command', 'set cmdheight=2') -- suppress Press ENTER + nvim("echo", {{"msg\nmsg"}, {"msg"}}, true, {}) + eq("msg\nmsgmsg", meths.exec('messages', true)) + end) + + it('can disable saving message history', function() + nvim('command', 'set cmdheight=2') -- suppress Press ENTER + nvim_async("echo", {{"msg\nmsg"}, {"msg"}}, false, {}) + eq("", meths.exec("messages", true)) + end) + end) end) |