aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJustin M. Keyes <justinkz@gmail.com>2018-12-27 22:49:44 +0100
committerJustin M. Keyes <justinkz@gmail.com>2018-12-27 22:49:44 +0100
commitc1015121ec626cab6cb384f544bc0be1a1760c0e (patch)
tree6cc9a5d1899a4486a24c491e07d17a7dd01f9503 /src
parent4f030ec24e0e148bbb83aedaef7dd629e5fef130 (diff)
parente1876c7ad1b5e30c0a9919e2c4587d11550c8507 (diff)
downloadrneovim-c1015121ec626cab6cb384f544bc0be1a1760c0e.tar.gz
rneovim-c1015121ec626cab6cb384f544bc0be1a1760c0e.tar.bz2
rneovim-c1015121ec626cab6cb384f544bc0be1a1760c0e.zip
Merge 'upstream/master' into pr-win-erw7
Diffstat (limited to 'src')
-rw-r--r--src/.clang-format18
-rw-r--r--src/nvim/CMakeLists.txt10
-rw-r--r--src/nvim/api/buffer.c119
-rw-r--r--src/nvim/api/vim.c66
-rw-r--r--src/nvim/api/vim.h4
-rw-r--r--src/nvim/api/window.c36
-rw-r--r--src/nvim/aucmd.c1
-rw-r--r--src/nvim/auevents.lua2
-rw-r--r--src/nvim/buffer.c10
-rw-r--r--src/nvim/buffer_defs.h75
-rw-r--r--src/nvim/channel.c18
-rw-r--r--src/nvim/diff.c956
-rw-r--r--src/nvim/edit.c13
-rw-r--r--src/nvim/eval.c48
-rw-r--r--src/nvim/eval/encode.c2
-rw-r--r--src/nvim/eval/typval.c4
-rw-r--r--src/nvim/ex_cmds.c23
-rw-r--r--src/nvim/ex_cmds.lua58
-rw-r--r--src/nvim/ex_cmds2.c32
-rw-r--r--src/nvim/ex_docmd.c24
-rw-r--r--src/nvim/ex_getln.c31
-rw-r--r--src/nvim/fileio.c107
-rw-r--r--src/nvim/fold.c10
-rw-r--r--src/nvim/globals.h3
-rw-r--r--src/nvim/highlight.c21
-rw-r--r--src/nvim/highlight_defs.h17
-rw-r--r--src/nvim/main.c50
-rw-r--r--src/nvim/map.c1
-rw-r--r--src/nvim/map.h1
-rw-r--r--src/nvim/memory.c2
-rw-r--r--src/nvim/message.c15
-rw-r--r--src/nvim/misc1.c33
-rw-r--r--src/nvim/move.c4
-rw-r--r--src/nvim/msgpack_rpc/channel.c11
-rw-r--r--src/nvim/normal.c8
-rw-r--r--src/nvim/option.c64
-rw-r--r--src/nvim/options.lua6
-rw-r--r--src/nvim/os/fs.c21
-rw-r--r--src/nvim/os/lang.c34
-rw-r--r--src/nvim/os/pty_process_unix.c2
-rw-r--r--src/nvim/po/CMakeLists.txt1
-rw-r--r--src/nvim/po/da.po7088
-rw-r--r--src/nvim/po/uk.po352
-rw-r--r--src/nvim/quickfix.c16
-rw-r--r--src/nvim/regexp.c27
-rw-r--r--src/nvim/regexp.h21
-rw-r--r--src/nvim/regexp_nfa.c24
-rw-r--r--src/nvim/screen.c172
-rw-r--r--src/nvim/strings.c22
-rw-r--r--src/nvim/syntax.c8
-rw-r--r--src/nvim/terminal.c3
-rw-r--r--src/nvim/testdir/runtest.vim1
-rw-r--r--src/nvim/testdir/shared.vim20
-rw-r--r--src/nvim/testdir/test_alot.vim1
-rw-r--r--src/nvim/testdir/test_arglist.vim12
-rw-r--r--src/nvim/testdir/test_autocmd.vim15
-rw-r--r--src/nvim/testdir/test_compiler.vim5
-rw-r--r--src/nvim/testdir/test_diffmode.vim157
-rw-r--r--src/nvim/testdir/test_eval_stuff.vim10
-rw-r--r--src/nvim/testdir/test_expr.vim31
-rw-r--r--src/nvim/testdir/test_filetype.vim4
-rw-r--r--src/nvim/testdir/test_fold.vim46
-rw-r--r--src/nvim/testdir/test_functions.vim19
-rw-r--r--src/nvim/testdir/test_history.vim5
-rw-r--r--src/nvim/testdir/test_ins_complete.vim13
-rw-r--r--src/nvim/testdir/test_lambda.vim6
-rw-r--r--src/nvim/testdir/test_messages.vim5
-rw-r--r--src/nvim/testdir/test_move.vim40
-rw-r--r--src/nvim/testdir/test_popup.vim25
-rw-r--r--src/nvim/testdir/test_python2.vim27
-rw-r--r--src/nvim/testdir/test_python3.vim27
-rw-r--r--src/nvim/testdir/test_quickfix.vim56
-rw-r--r--src/nvim/testdir/test_quotestar.vim12
-rw-r--r--src/nvim/testdir/test_scriptnames.vim26
-rw-r--r--src/nvim/testdir/test_signs.vim27
-rw-r--r--src/nvim/testdir/test_spell.vim30
-rw-r--r--src/nvim/testdir/test_startup.vim77
-rw-r--r--src/nvim/testdir/test_stat.vim54
-rw-r--r--src/nvim/testdir/test_syntax.vim21
-rw-r--r--src/nvim/testdir/test_timers.vim7
-rw-r--r--src/nvim/testdir/test_undo.vim2
-rw-r--r--src/nvim/testdir/test_usercommands.vim12
-rw-r--r--src/nvim/tui/terminfo.c19
-rw-r--r--src/nvim/tui/tui.c288
-rw-r--r--src/nvim/ugrid.c25
-rw-r--r--src/nvim/ugrid.h14
-rw-r--r--src/nvim/ui_bridge.c3
-rw-r--r--src/nvim/version.c36
-rw-r--r--src/nvim/xdiff/COPYING504
-rw-r--r--src/nvim/xdiff/README.txt16
-rw-r--r--src/nvim/xdiff/xdiff.h143
-rw-r--r--src/nvim/xdiff/xdiffi.c1043
-rw-r--r--src/nvim/xdiff/xdiffi.h64
-rw-r--r--src/nvim/xdiff/xemit.c332
-rw-r--r--src/nvim/xdiff/xemit.h36
-rw-r--r--src/nvim/xdiff/xhistogram.c386
-rw-r--r--src/nvim/xdiff/xinclude.h61
-rw-r--r--src/nvim/xdiff/xmacros.h54
-rw-r--r--src/nvim/xdiff/xpatience.c393
-rw-r--r--src/nvim/xdiff/xprepare.c483
-rw-r--r--src/nvim/xdiff/xprepare.h34
-rw-r--r--src/nvim/xdiff/xtypes.h67
-rw-r--r--src/nvim/xdiff/xutils.c425
-rw-r--r--src/nvim/xdiff/xutils.h47
104 files changed, 13822 insertions, 1138 deletions
diff --git a/src/.clang-format b/src/.clang-format
deleted file mode 100644
index 5a910ff34b..0000000000
--- a/src/.clang-format
+++ /dev/null
@@ -1,18 +0,0 @@
-BasedOnStyle: Google
-Language: Cpp
-ColumnLimit: 80
-IndentWidth: 2
-TabWidth: 2
-UseTab: Never
-IndentCaseLabels: true
-BreakBeforeBraces: Linux
-AlignEscapedNewlinesLeft: false
-AllowShortFunctionsOnASingleLine: false
-SpacesBeforeTrailingComments: 2
-PenaltyReturnTypeOnItsOwnLine: 200
-AllowAllParametersOfDeclarationOnNextLine: false
-AllowShortIfStatementsOnASingleLine: false
-AllowShortLoopsOnASingleLine: false
-BinPackParameters: false
-BreakBeforeBinaryOperators: true
-ContinuationIndentWidth: 4
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index 29a4e1e163..a2c4e677d4 100644
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -79,6 +79,8 @@ file(MAKE_DIRECTORY ${LINT_SUPPRESSES_ROOT}/src)
file(GLOB NVIM_SOURCES *.c)
file(GLOB NVIM_HEADERS *.h)
+file(GLOB XDIFF_SOURCES xdiff/*.c)
+file(GLOB XDIFF_HEADERS xdiff/*.h)
foreach(subdir
os
@@ -148,12 +150,13 @@ set(CONV_SOURCES
syntax.c
tag.c
window.c)
-
foreach(sfile ${CONV_SOURCES})
if(NOT EXISTS "${CMAKE_CURRENT_LIST_DIR}/${sfile}")
message(FATAL_ERROR "${sfile} doesn't exist (it was added to CONV_SOURCES)")
endif()
endforeach()
+# xdiff: inlined external project, we don't maintain it. #9306
+list(APPEND CONV_SOURCES ${XDIFF_SOURCES})
if(NOT MSVC)
set_source_files_properties(
@@ -404,7 +407,8 @@ if(POLICY CMP0069)
endif()
add_executable(nvim ${NVIM_GENERATED_FOR_SOURCES} ${NVIM_GENERATED_FOR_HEADERS}
- ${NVIM_GENERATED_SOURCES} ${NVIM_SOURCES} ${NVIM_HEADERS})
+ ${NVIM_GENERATED_SOURCES} ${NVIM_SOURCES} ${NVIM_HEADERS}
+ ${XDIFF_SOURCES} ${XDIFF_HEADERS})
target_link_libraries(nvim ${NVIM_EXEC_LINK_LIBRARIES})
install_helper(TARGETS nvim)
@@ -490,6 +494,7 @@ add_library(
EXCLUDE_FROM_ALL
${NVIM_SOURCES} ${NVIM_GENERATED_SOURCES}
${NVIM_HEADERS} ${NVIM_GENERATED_FOR_SOURCES} ${NVIM_GENERATED_FOR_HEADERS}
+ ${XDIFF_SOURCES} ${XDIFF_HEADERS}
)
set_property(TARGET libnvim APPEND PROPERTY
INCLUDE_DIRECTORIES ${LUA_PREFERRED_INCLUDE_DIRS})
@@ -514,6 +519,7 @@ else()
EXCLUDE_FROM_ALL
${NVIM_SOURCES} ${NVIM_GENERATED_SOURCES}
${NVIM_HEADERS} ${NVIM_GENERATED_FOR_SOURCES} ${NVIM_GENERATED_FOR_HEADERS}
+ ${XDIFF_SOURCES} ${XDIFF_HEADERS}
${UNIT_TEST_FIXTURES}
)
target_link_libraries(nvim-test ${NVIM_TEST_LINK_LIBRARIES})
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index 39330690e8..5df0f0bb47 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -51,8 +51,7 @@
///
/// @param buffer Buffer handle
/// @param[out] err Error details, if any
-/// @return Line count, or \`0` if the buffer has been unloaded (see
-/// |api-buffer|).
+/// @return Line count, or 0 for unloaded buffer. |api-buffer|
Integer nvim_buf_line_count(Buffer buffer, Error *err)
FUNC_API_SINCE(1)
{
@@ -227,8 +226,7 @@ ArrayOf(String) buffer_get_line_slice(Buffer buffer,
/// @param end Last line index (exclusive)
/// @param strict_indexing Whether out-of-bounds should be an error.
/// @param[out] err Error details, if any
-/// @return Array of lines. If the buffer has been unloaded then an empty array
-/// will be returned instead. (See |api-buffer|.)
+/// @return Array of lines, or empty array for unloaded buffer.
ArrayOf(String) nvim_buf_get_lines(uint64_t channel_id,
Buffer buffer,
Integer start,
@@ -491,12 +489,12 @@ end:
try_end(err);
}
-/// Return the byte offset for a line.
-//
-/// The first line returns 0. UTF-8 bytes are counted, and EOL counts as one
-/// byte. 'fileformat' and 'fileencoding' are ignored. Sending in the index
-/// just below the last line gives the total byte count for the entire buffer.
-/// A final EOL is included if it would be written, see 'eol'.
+/// Returns the byte offset for a line.
+///
+/// Line 1 (index=0) has offset 0. UTF-8 bytes are counted. EOL is one byte.
+/// 'fileformat' and 'fileencoding' are ignored. The line index just after the
+/// last line gives the total byte-count of the buffer. A final EOL byte is
+/// counted if it would be written, see 'eol'.
///
/// Unlike |line2byte()|, throws error for out-of-bounds indexing.
/// Returns -1 for unloaded buffer.
@@ -504,7 +502,7 @@ end:
/// @param buffer Buffer handle
/// @param index Line index
/// @param[out] err Error details, if any
-/// @return Integer Byte offset
+/// @return Integer byte offset, or -1 for unloaded buffer.
Integer nvim_buf_get_offset(Buffer buffer, Integer index, Error *err)
FUNC_API_SINCE(5)
{
@@ -907,34 +905,34 @@ ArrayOf(Integer, 2) nvim_buf_get_mark(Buffer buffer, String name, Error *err)
///
/// Useful for plugins that dynamically generate highlights to a buffer
/// (like a semantic highlighter or linter). The function adds a single
-/// highlight to a buffer. Unlike matchaddpos() highlights follow changes to
+/// highlight to a buffer. Unlike |matchaddpos()| highlights follow changes to
/// line numbering (as lines are inserted/removed above the highlighted line),
/// like signs and marks do.
///
-/// `src_id` is useful for batch deletion/updating of a set of highlights. When
-/// called with `src_id = 0`, an unique source id is generated and returned.
-/// Successive calls can pass that `src_id` to associate new highlights with
-/// the same source group. All highlights in the same group can be cleared
-/// with `nvim_buf_clear_highlight`. If the highlight never will be manually
-/// deleted, pass `src_id = -1`.
+/// Namespaces are used for batch deletion/updating of a set of highlights. To
+/// create a namespace, use |nvim_create_namespace| which returns a namespace
+/// id. Pass it in to this function as `ns_id` to add highlights to the
+/// namespace. All highlights in the same namespace can then be cleared with
+/// single call to |nvim_buf_clear_namespace|. If the highlight never will be
+/// deleted by an API call, pass `ns_id = -1`.
///
-/// If `hl_group` is the empty string no highlight is added, but a new `src_id`
-/// is still returned. This is useful for an external plugin to synchrounously
-/// request an unique `src_id` at initialization, and later asynchronously add
-/// and clear highlights in response to buffer changes.
+/// As a shorthand, `ns_id = 0` can be used to create a new namespace for the
+/// highlight, the allocated id is then returned. If `hl_group` is the empty
+/// string no highlight is added, but a new `ns_id` is still returned. This is
+/// supported for backwards compatibility, new code should use
+/// |nvim_create_namespace| to create a new empty namespace.
///
/// @param buffer Buffer handle
-/// @param src_id Source group to use or 0 to use a new group,
-/// or -1 for ungrouped highlight
+/// @param ns_id namespace to use or -1 for ungrouped highlight
/// @param hl_group Name of the highlight group to use
/// @param line Line to highlight (zero-indexed)
/// @param col_start Start of (byte-indexed) column range to highlight
/// @param col_end End of (byte-indexed) column range to highlight,
/// or -1 to highlight to end of line
/// @param[out] err Error details, if any
-/// @return The src_id that was used
+/// @return The ns_id that was used
Integer nvim_buf_add_highlight(Buffer buffer,
- Integer src_id,
+ Integer ns_id,
String hl_group,
Integer line,
Integer col_start,
@@ -964,28 +962,28 @@ Integer nvim_buf_add_highlight(Buffer buffer,
hlg_id = syn_check_group((char_u *)hl_group.data, (int)hl_group.size);
}
- src_id = bufhl_add_hl(buf, (int)src_id, hlg_id, (linenr_T)line+1,
- (colnr_T)col_start+1, (colnr_T)col_end);
- return src_id;
+ ns_id = bufhl_add_hl(buf, (int)ns_id, hlg_id, (linenr_T)line+1,
+ (colnr_T)col_start+1, (colnr_T)col_end);
+ return ns_id;
}
-/// Clears highlights and virtual text from a given source id and range of lines
+/// Clears namespaced objects, highlights and virtual text, from a line range
///
-/// To clear a source group in the entire buffer, pass in 0 and -1 to
+/// To clear the namespace in the entire buffer, pass in 0 and -1 to
/// line_start and line_end respectively.
///
/// @param buffer Buffer handle
-/// @param src_id Highlight source group to clear, or -1 to clear all.
+/// @param ns_id Namespace to clear, or -1 to clear all namespaces.
/// @param line_start Start of range of lines to clear
/// @param line_end End of range of lines to clear (exclusive) or -1 to clear
-/// to end of file.
+/// to end of buffer.
/// @param[out] err Error details, if any
-void nvim_buf_clear_highlight(Buffer buffer,
- Integer src_id,
+void nvim_buf_clear_namespace(Buffer buffer,
+ Integer ns_id,
Integer line_start,
Integer line_end,
Error *err)
- FUNC_API_SINCE(1)
+ FUNC_API_SINCE(5)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
if (!buf) {
@@ -1000,7 +998,27 @@ void nvim_buf_clear_highlight(Buffer buffer,
line_end = MAXLNUM;
}
- bufhl_clear_line_range(buf, (int)src_id, (int)line_start+1, (int)line_end);
+ bufhl_clear_line_range(buf, (int)ns_id, (int)line_start+1, (int)line_end);
+}
+
+/// Clears highlights and virtual text from namespace and range of lines
+///
+/// @deprecated use |nvim_buf_clear_namespace|.
+///
+/// @param buffer Buffer handle
+/// @param ns_id Namespace to clear, or -1 to clear all.
+/// @param line_start Start of range of lines to clear
+/// @param line_end End of range of lines to clear (exclusive) or -1 to clear
+/// to end of file.
+/// @param[out] err Error details, if any
+void nvim_buf_clear_highlight(Buffer buffer,
+ Integer ns_id,
+ Integer line_start,
+ Integer line_end,
+ Error *err)
+ FUNC_API_SINCE(1)
+{
+ nvim_buf_clear_namespace(buffer, ns_id, line_start, line_end, err);
}
@@ -1009,15 +1027,20 @@ void nvim_buf_clear_highlight(Buffer buffer,
/// By default (and currently the only option) the text will be placed after
/// the buffer text. Virtual text will never cause reflow, rather virtual
/// text will be truncated at the end of the screen line. The virtual text will
-/// begin after one cell to the right of the ordinary text, this will contain
-/// the |lcs-eol| char if set, otherwise just be a space.
+/// begin one cell (|lcs-eol| or space) after the ordinary text.
+///
+/// Namespaces are used to support batch deletion/updating of virtual text.
+/// To create a namespace, use |nvim_create_namespace|. Virtual text is
+/// cleared using |nvim_buf_clear_namespace|. The same `ns_id` can be used for
+/// both virtual text and highlights added by |nvim_buf_add_highlight|, both
+/// can then be cleared with a single call to |nvim_buf_clear_namespace|. If the
+/// virtual text never will be cleared by an API call, pass `ns_id = -1`.
///
-/// The same src_id can be used for both virtual text and highlights added by
-/// nvim_buf_add_highlight. Virtual text is cleared using
-/// nvim_buf_clear_highlight.
+/// As a shorthand, `ns_id = 0` can be used to create a new namespace for the
+/// virtual text, the allocated id is then returned.
///
/// @param buffer Buffer handle
-/// @param src_id Source group to use or 0 to use a new group,
+/// @param ns_id Namespace to use or 0 to create a namespace,
/// or -1 for a ungrouped annotation
/// @param line Line to annotate with virtual text (zero-indexed)
/// @param chunks A list of [text, hl_group] arrays, each representing a
@@ -1025,9 +1048,9 @@ void nvim_buf_clear_highlight(Buffer buffer,
/// can be omitted for no highlight.
/// @param opts Optional parameters. Currently not used.
/// @param[out] err Error details, if any
-/// @return The src_id that was used
+/// @return The ns_id that was used
Integer nvim_buf_set_virtual_text(Buffer buffer,
- Integer src_id,
+ Integer ns_id,
Integer line,
Array chunks,
Dictionary opts,
@@ -1077,9 +1100,9 @@ Integer nvim_buf_set_virtual_text(Buffer buffer,
kv_push(virt_text, ((VirtTextChunk){ .text = text, .hl_id = hl_id }));
}
- src_id = bufhl_add_virt_text(buf, (int)src_id, (linenr_T)line+1,
- virt_text);
- return src_id;
+ ns_id = bufhl_add_virt_text(buf, (int)ns_id, (linenr_T)line+1,
+ virt_text);
+ return ns_id;
free_exit:
kv_destroy(virt_text);
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index fed20a272a..4da61a30ef 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -46,6 +46,24 @@
# include "api/vim.c.generated.h"
#endif
+void api_vim_init(void)
+ FUNC_API_NOEXPORT
+{
+ namespace_ids = map_new(String, handle_T)();
+}
+
+void api_vim_free_all_mem(void)
+ FUNC_API_NOEXPORT
+{
+ String name;
+ handle_T id;
+ map_foreach(namespace_ids, name, id, {
+ (void)id;
+ xfree(name.data);
+ })
+ map_free(String, handle_T)(namespace_ids);
+}
+
/// Executes an ex-command.
///
/// On execution error: fails with VimL error, does not update v:errmsg.
@@ -725,6 +743,9 @@ void nvim_err_writeln(String str)
/// Gets the current list of buffer handles
///
+/// Includes unlisted (unloaded/deleted) buffers, like `:ls!`.
+/// Use |nvim_buf_is_loaded()| to check if a buffer is loaded.
+///
/// @return List of buffer handles
ArrayOf(Buffer) nvim_list_bufs(void)
FUNC_API_SINCE(1)
@@ -884,6 +905,49 @@ void nvim_set_current_tabpage(Tabpage tabpage, Error *err)
}
}
+/// create a new namespace, or get one with an exisiting name
+///
+/// Namespaces are currently used for buffer highlighting and virtual text, see
+/// |nvim_buf_add_highlight| and |nvim_buf_set_virtual_text|.
+///
+/// Namespaces can have a name of be anonymous. If `name` is a non-empty string,
+/// and a namespace already exists with that name,the existing namespace id is
+/// returned. If an empty string is used, a new anonymous namespace is returned.
+///
+/// @param name Name of the namespace or empty string
+/// @return the namespace id
+Integer nvim_create_namespace(String name)
+ FUNC_API_SINCE(5)
+{
+ handle_T id = map_get(String, handle_T)(namespace_ids, name);
+ if (id > 0) {
+ return id;
+ }
+ id = next_namespace_id++;
+ if (name.size > 0) {
+ String name_alloc = copy_string(name);
+ map_put(String, handle_T)(namespace_ids, name_alloc, id);
+ }
+ return (Integer)id;
+}
+
+/// Get existing named namespaces
+///
+/// @return dict that maps from names to namespace ids.
+Dictionary nvim_get_namespaces(void)
+ FUNC_API_SINCE(5)
+{
+ Dictionary retval = ARRAY_DICT_INIT;
+ String name;
+ handle_T id;
+
+ map_foreach(namespace_ids, name, id, {
+ PUT(retval, name.data, INTEGER_OBJ(id));
+ })
+
+ return retval;
+}
+
/// Subscribes to event broadcasts
///
/// @param channel_id Channel id (passed automatically by the dispatcher)
@@ -1028,7 +1092,7 @@ Array nvim_get_api_info(uint64_t channel_id)
/// @param attributes Informal attributes describing the client. Clients might
/// define their own keys, but the following are suggested:
/// - "website" Website of client (for instance github repository)
-/// - "license" Informal descripton of the license, such as "Apache 2",
+/// - "license" Informal description of the license, such as "Apache 2",
/// "GPLv3" or "MIT"
/// - "logo" URI or path to image, preferably small logo or icon.
/// .png or .svg format is preferred.
diff --git a/src/nvim/api/vim.h b/src/nvim/api/vim.h
index 5e0b35b562..d6873da6d2 100644
--- a/src/nvim/api/vim.h
+++ b/src/nvim/api/vim.h
@@ -4,6 +4,10 @@
#include <stdint.h>
#include "nvim/api/private/defs.h"
+#include "nvim/map.h"
+
+EXTERN Map(String, handle_T) *namespace_ids INIT(= NULL);
+EXTERN handle_T next_namespace_id INIT(= 1);
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "api/vim.h.generated.h"
diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c
index 5281a7c1f4..cf1d1f5e45 100644
--- a/src/nvim/api/window.c
+++ b/src/nvim/api/window.c
@@ -10,6 +10,7 @@
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
#include "nvim/vim.h"
+#include "nvim/buffer.h"
#include "nvim/cursor.h"
#include "nvim/window.h"
#include "nvim/screen.h"
@@ -33,6 +34,41 @@ Buffer nvim_win_get_buf(Window window, Error *err)
return win->w_buffer->handle;
}
+/// Sets the current buffer in a window, without side-effects
+///
+/// @param window Window handle
+/// @param buffer Buffer handle
+/// @param[out] err Error details, if any
+void nvim_win_set_buf(Window window, Buffer buffer, Error *err)
+ FUNC_API_SINCE(5)
+{
+ win_T *win = find_window_by_handle(window, err), *save_curwin = curwin;
+ buf_T *buf = find_buffer_by_handle(buffer, err);
+ tabpage_T *tab = win_find_tabpage(win), *save_curtab = curtab;
+
+ if (!win || !buf) {
+ return;
+ }
+
+ if (switch_win(&save_curwin, &save_curtab, win, tab, false) == FAIL) {
+ api_set_error(err,
+ kErrorTypeException,
+ "Failed to switch to window %d",
+ window);
+ }
+
+ try_start();
+ int result = do_buffer(DOBUF_GOTO, DOBUF_FIRST, FORWARD, buf->b_fnum, 0);
+ if (!try_end(err) && result == FAIL) {
+ api_set_error(err,
+ kErrorTypeException,
+ "Failed to set buffer %d",
+ buffer);
+ }
+
+ restore_win(save_curwin, save_curtab, false);
+}
+
/// Gets the cursor position in the window
///
/// @param window Window handle
diff --git a/src/nvim/aucmd.c b/src/nvim/aucmd.c
index fc421116ea..9ad3414b79 100644
--- a/src/nvim/aucmd.c
+++ b/src/nvim/aucmd.c
@@ -26,7 +26,6 @@ void aucmd_schedule_focusgained(bool gained)
}
static void do_autocmd_focusgained(bool gained)
- FUNC_ATTR_NONNULL_ALL
{
static bool recursive = false;
diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua
index a6290aaac1..3cffd66dee 100644
--- a/src/nvim/auevents.lua
+++ b/src/nvim/auevents.lua
@@ -21,6 +21,7 @@ return {
'BufWritePre', -- before writing a buffer
'ChanInfo', -- info was received about channel
'ChanOpen', -- channel was opened
+ 'CmdLineChanged', -- command line was modified
'CmdLineEnter', -- after entering cmdline mode
'CmdLineLeave', -- before leaving cmdline mode
'CmdUndefined', -- command undefined
@@ -33,6 +34,7 @@ return {
'CursorHoldI', -- idem, in Insert mode
'CursorMoved', -- cursor was moved
'CursorMovedI', -- cursor was moved in Insert mode
+ 'DiffUpdated', -- diffs have been updated
'DirChanged', -- directory changed
'EncodingChanged', -- after changing the 'encoding' option
'ExitPre', -- before exiting
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index cd77f48320..8b107041b1 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -26,6 +26,7 @@
#include "nvim/api/private/handle.h"
#include "nvim/api/private/helpers.h"
+#include "nvim/api/vim.h"
#include "nvim/ascii.h"
#include "nvim/assert.h"
#include "nvim/vim.h"
@@ -5327,10 +5328,10 @@ int bufhl_add_hl(buf_T *buf,
int hl_id,
linenr_T lnum,
colnr_T col_start,
- colnr_T col_end) {
- static int next_src_id = 1;
+ colnr_T col_end)
+{
if (src_id == 0) {
- src_id = next_src_id++;
+ src_id = (int)nvim_create_namespace((String)STRING_INIT);
}
if (hl_id <= 0) {
// no highlight group or invalid line, just return src_id
@@ -5395,9 +5396,8 @@ int bufhl_add_virt_text(buf_T *buf,
linenr_T lnum,
VirtText virt_text)
{
- static int next_src_id = 1;
if (src_id == 0) {
- src_id = next_src_id++;
+ src_id = (int)nvim_create_namespace((String)STRING_INIT);
}
BufhlLine *lineinfo = bufhl_tree_ref(&buf->b_bufhl_info, lnum, true);
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index e86eaf010f..d270714611 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -58,10 +58,10 @@ typedef struct {
* functions that set or reset the flags.
*
* VALID_BOTLINE VALID_BOTLINE_AP
- * on on w_botline valid
- * off on w_botline approximated
- * off off w_botline not valid
- * on off not possible
+ * on on w_botline valid
+ * off on w_botline approximated
+ * off off w_botline not valid
+ * on off not possible
*/
#define VALID_WROW 0x01 /* w_wrow (window row) is valid */
#define VALID_WCOL 0x02 /* w_wcol (window col) is valid */
@@ -159,7 +159,7 @@ typedef struct {
int wo_arab;
# define w_p_arab w_onebuf_opt.wo_arab /* 'arabic' */
int wo_bri;
-# define w_p_bri w_onebuf_opt.wo_bri /* 'breakindent' */
+# define w_p_bri w_onebuf_opt.wo_bri // 'breakindent'
char_u *wo_briopt;
# define w_p_briopt w_onebuf_opt.wo_briopt /* 'breakindentopt' */
int wo_diff;
@@ -412,13 +412,13 @@ typedef struct {
* syntax state too often.
* b_sst_array[] is allocated to hold the state for all displayed lines,
* and states for 1 out of about 20 other lines.
- * b_sst_array pointer to an array of synstate_T
- * b_sst_len number of entries in b_sst_array[]
- * b_sst_first pointer to first used entry in b_sst_array[] or NULL
- * b_sst_firstfree pointer to first free entry in b_sst_array[] or NULL
- * b_sst_freecount number of free entries in b_sst_array[]
- * b_sst_check_lnum entries after this lnum need to be checked for
- * validity (MAXLNUM means no check needed)
+ * b_sst_array pointer to an array of synstate_T
+ * b_sst_len number of entries in b_sst_array[]
+ * b_sst_first pointer to first used entry in b_sst_array[] or NULL
+ * b_sst_firstfree pointer to first free entry in b_sst_array[] or NULL
+ * b_sst_freecount number of free entries in b_sst_array[]
+ * b_sst_check_lnum entries after this lnum need to be checked for
+ * validity (MAXLNUM means no check needed)
*/
synstate_T *b_sst_array;
int b_sst_len;
@@ -475,15 +475,15 @@ struct file_buffer {
int b_locked; // Buffer is being closed or referenced, don't
// let autocommands wipe it out.
- /*
- * b_ffname has the full path of the file (NULL for no name).
- * b_sfname is the name as the user typed it (or NULL).
- * b_fname is the same as b_sfname, unless ":cd" has been done,
- * then it is the same as b_ffname (NULL for no name).
- */
- char_u *b_ffname; /* full path file name */
- char_u *b_sfname; /* short file name */
- char_u *b_fname; /* current file name */
+ //
+ // b_ffname has the full path of the file (NULL for no name).
+ // b_sfname is the name as the user typed it (or NULL).
+ // b_fname is the same as b_sfname, unless ":cd" has been done,
+ // then it is the same as b_ffname (NULL for no name).
+ //
+ char_u *b_ffname; // full path file name
+ char_u *b_sfname; // short file name
+ char_u *b_fname; // current file name
bool file_id_valid;
FileID file_id;
@@ -587,12 +587,12 @@ struct file_buffer {
bool b_scanned; /* ^N/^P have scanned this buffer */
- /* flags for use of ":lmap" and IM control */
- long b_p_iminsert; /* input mode for insert */
- long b_p_imsearch; /* input mode for search */
-#define B_IMODE_USE_INSERT -1 /* Use b_p_iminsert value for search */
-#define B_IMODE_NONE 0 /* Input via none */
-#define B_IMODE_LMAP 1 /* Input via langmap */
+ // flags for use of ":lmap" and IM control
+ long b_p_iminsert; // input mode for insert
+ long b_p_imsearch; // input mode for search
+#define B_IMODE_USE_INSERT -1 // Use b_p_iminsert value for search
+#define B_IMODE_NONE 0 // Input via none
+#define B_IMODE_LMAP 1 // Input via langmap
# define B_IMODE_LAST 1
short b_kmap_state; /* using "lmap" mappings */
@@ -760,7 +760,7 @@ struct file_buffer {
/* Two special kinds of buffers:
* help buffer - used for help files, won't use a swap file.
* spell buffer - used for spell info, never displayed and doesn't have a
- * file name.
+ * file name.
*/
bool b_help; /* TRUE for help file buffer (when set b_p_bt
is "help") */
@@ -787,6 +787,8 @@ struct file_buffer {
// array of channelids which have asked to receive updates for this
// buffer.
kvec_t(uint64_t) update_channels;
+
+ int b_diff_failed; // internal diff failed for this buffer
};
/*
@@ -840,6 +842,7 @@ struct tabpage_S {
diff_T *tp_first_diff;
buf_T *(tp_diffbuf[DB_COUNT]);
int tp_diff_invalid; ///< list of diffs is outdated
+ int tp_diff_update; ///< update diffs before redrawing
frame_T *(tp_snapshot[SNAP_COUNT]); ///< window layout snapshots
ScopeDictDictItem tp_winvar; ///< Variable for "t:" Dictionary.
dict_T *tp_vars; ///< Internal variables, local to tab page.
@@ -916,9 +919,9 @@ typedef struct {
/// Same as lpos_T, but with additional field len.
typedef struct
{
- linenr_T lnum; ///< line number
- colnr_T col; ///< column number
- int len; ///< length: 0 - to the end of line
+ linenr_T lnum; ///< line number
+ colnr_T col; ///< column number
+ int len; ///< length: 0 - to the end of line
} llpos_T;
/// posmatch_T provides an array for storing match items for matchaddpos()
@@ -926,10 +929,10 @@ typedef struct
typedef struct posmatch posmatch_T;
struct posmatch
{
- llpos_T pos[MAXPOSMATCH]; ///< array of positions
- int cur; ///< internal position counter
- linenr_T toplnum; ///< top buffer line
- linenr_T botlnum; ///< bottom buffer line
+ llpos_T pos[MAXPOSMATCH]; ///< array of positions
+ int cur; ///< internal position counter
+ linenr_T toplnum; ///< top buffer line
+ linenr_T botlnum; ///< bottom buffer line
};
/*
@@ -1036,7 +1039,7 @@ struct window_S {
* Recomputing is minimized by storing the result of computations.
* Use functions in screen.c to check if they are valid and to update.
* w_valid is a bitfield of flags, which indicate if specific values are
- * valid or need to be recomputed.
+ * valid or need to be recomputed.
*/
int w_valid;
pos_T w_valid_cursor; /* last known position of w_cursor, used
diff --git a/src/nvim/channel.c b/src/nvim/channel.c
index 259f1cc600..8b8d27affd 100644
--- a/src/nvim/channel.c
+++ b/src/nvim/channel.c
@@ -161,7 +161,6 @@ void channel_init(void)
channels = pmap_new(uint64_t)();
channel_alloc(kChannelStreamStderr);
rpc_init();
- remote_ui_init();
}
/// Allocates a channel.
@@ -284,6 +283,8 @@ Channel *channel_job_start(char **argv, CallbackReader on_stdout,
uint16_t pty_width, uint16_t pty_height,
char *term_name, varnumber_T *status_out)
{
+ assert(cwd == NULL || os_isdir_executable(cwd));
+
Channel *chan = channel_alloc(kChannelStreamProc);
chan->on_stdout = on_stdout;
chan->on_stderr = on_stderr;
@@ -605,12 +606,15 @@ static void on_channel_output(Stream *stream, Channel *chan, RBuffer *buf,
}
rbuffer_consumed(buf, count);
- // if buffer wasn't consumed, a pending callback is stalled. Aggregate the
- // received data and avoid a "burst" of multiple callbacks.
- bool buffer_set = reader->buffer.ga_len > 0;
- ga_concat_len(&reader->buffer, ptr, count);
- if (!reader->buffered && !buffer_set && callback_reader_set(*reader)) {
- process_channel_event(chan, &reader->cb, type, reader, 0);
+
+ if (callback_reader_set(*reader) || reader->buffered) {
+ // if buffer wasn't consumed, a pending callback is stalled. Aggregate the
+ // received data and avoid a "burst" of multiple callbacks.
+ bool buffer_set = reader->buffer.ga_len > 0;
+ ga_concat_len(&reader->buffer, ptr, count);
+ if (callback_reader_set(*reader) && !reader->buffered && !buffer_set) {
+ process_channel_event(chan, &reader->cb, type, reader, 0);
+ }
}
}
diff --git a/src/nvim/diff.c b/src/nvim/diff.c
index 4bfe67c9d3..2e0b198c13 100644
--- a/src/nvim/diff.c
+++ b/src/nvim/diff.c
@@ -4,11 +4,17 @@
/// @file diff.c
///
/// Code for diff'ing two, three or four buffers.
+///
+/// There are three ways to diff:
+/// - Shell out to an external diff program, using files.
+/// - Use the compiled-in xdiff library.
+/// - Let 'diffexpr' do the work, using files.
#include <inttypes.h>
#include <stdbool.h>
#include "nvim/vim.h"
+#include "xdiff/xdiff.h"
#include "nvim/ascii.h"
#include "nvim/diff.h"
#include "nvim/buffer.h"
@@ -36,16 +42,24 @@
#include "nvim/os/os.h"
#include "nvim/os/shell.h"
-static int diff_busy = FALSE; // ex_diffgetput() is busy
+static int diff_busy = false; // using diff structs, don't change them
+static int diff_need_update = false; // ex_diffupdate needs to be called
// Flags obtained from the 'diffopt' option
-#define DIFF_FILLER 1 // display filler lines
-#define DIFF_ICASE 2 // ignore case
-#define DIFF_IWHITE 4 // ignore change in white space
-#define DIFF_HORIZONTAL 8 // horizontal splits
-#define DIFF_VERTICAL 16 // vertical splits
-#define DIFF_HIDDEN_OFF 32 // diffoff when hidden
-static int diff_flags = DIFF_FILLER;
+#define DIFF_FILLER 0x001 // display filler lines
+#define DIFF_IBLANK 0x002 // ignore empty lines
+#define DIFF_ICASE 0x004 // ignore case
+#define DIFF_IWHITE 0x008 // ignore change in white space
+#define DIFF_IWHITEALL 0x010 // ignore all white space changes
+#define DIFF_IWHITEEOL 0x020 // ignore change in white space at EOL
+#define DIFF_HORIZONTAL 0x040 // horizontal splits
+#define DIFF_VERTICAL 0x080 // vertical splits
+#define DIFF_HIDDEN_OFF 0x100 // diffoff when hidden
+#define DIFF_INTERNAL 0x200 // use internal xdiff algorithm
+#define ALL_WHITE_DIFF (DIFF_IWHITE | DIFF_IWHITEALL | DIFF_IWHITEEOL)
+static int diff_flags = DIFF_INTERNAL | DIFF_FILLER;
+
+static long diff_algorithm = 0;
#define LBUFLEN 50 // length of line in diff file
@@ -53,6 +67,25 @@ static int diff_flags = DIFF_FILLER;
// kNone when not checked yet
static TriState diff_a_works = kNone;
+// used for diff input
+typedef struct {
+ char_u *din_fname; // used for external diff
+ mmfile_t din_mmfile; // used for internal diff
+} diffin_T;
+
+// used for diff result
+typedef struct {
+ char_u *dout_fname; // used for external diff
+ garray_T dout_ga; // used for internal diff
+} diffout_T;
+
+// two diff inputs and one result
+typedef struct {
+ diffin_T dio_orig; // original file input
+ diffin_T dio_new; // new file input
+ diffout_T dio_diff; // diff result
+ int dio_internal; // using internal diff
+} diffio_T;
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "diff.c.generated.h"
@@ -68,10 +101,10 @@ void diff_buf_delete(buf_T *buf)
if (i != DB_COUNT) {
tp->tp_diffbuf[i] = NULL;
- tp->tp_diff_invalid = TRUE;
+ tp->tp_diff_invalid = true;
if (tp == curtab) {
- diff_redraw(TRUE);
+ diff_redraw(true);
}
}
}
@@ -98,8 +131,8 @@ void diff_buf_adjust(win_T *win)
int i = diff_buf_idx(win->w_buffer);
if (i != DB_COUNT) {
curtab->tp_diffbuf[i] = NULL;
- curtab->tp_diff_invalid = TRUE;
- diff_redraw(TRUE);
+ curtab->tp_diff_invalid = true;
+ diff_redraw(true);
}
}
} else {
@@ -127,8 +160,8 @@ void diff_buf_add(buf_T *buf)
for (i = 0; i < DB_COUNT; ++i) {
if (curtab->tp_diffbuf[i] == NULL) {
curtab->tp_diffbuf[i] = buf;
- curtab->tp_diff_invalid = TRUE;
- diff_redraw(TRUE);
+ curtab->tp_diff_invalid = true;
+ diff_redraw(true);
return;
}
}
@@ -192,9 +225,9 @@ void diff_invalidate(buf_T *buf)
FOR_ALL_TABS(tp) {
int i = diff_buf_idx_tp(buf, tp);
if (i != DB_COUNT) {
- tp->tp_diff_invalid = TRUE;
+ tp->tp_diff_invalid = true;
if (tp == curtab) {
- diff_redraw(TRUE);
+ diff_redraw(true);
}
}
}
@@ -234,6 +267,15 @@ void diff_mark_adjust(linenr_T line1, linenr_T line2, long amount,
static void diff_mark_adjust_tp(tabpage_T *tp, int idx, linenr_T line1,
linenr_T line2, long amount, long amount_after)
{
+ if (diff_internal()) {
+ // Will update diffs before redrawing. Set _invalid to update the
+ // diffs themselves, set _update to also update folds properly just
+ // before redrawing.
+ // Do update marks here, it is needed for :%diffput.
+ tp->tp_diff_invalid = true;
+ tp->tp_diff_update = true;
+ }
+
int inserted;
int deleted;
if (line2 == MAXLNUM) {
@@ -293,14 +335,14 @@ static void diff_mark_adjust_tp(tabpage_T *tp, int idx, linenr_T line1,
//
// Check for these situations:
- // 1 2 3
- // 1 2 3
- // line1 2 3 4 5
- // 2 3 4 5
- // 2 3 4 5
- // line2 2 3 4 5
- // 3 5 6
- // 3 5 6
+ // 1 2 3
+ // 1 2 3
+ // line1 2 3 4 5
+ // 2 3 4 5
+ // 2 3 4 5
+ // line2 2 3 4 5
+ // 3 5 6
+ // 3 5 6
// compute last line of this change
last = dp->df_lnum[idx] + dp->df_count[idx] - 1;
@@ -316,7 +358,7 @@ static void diff_mark_adjust_tp(tabpage_T *tp, int idx, linenr_T line1,
}
dp->df_lnum[idx] += amount_after;
} else {
- int check_unchanged = FALSE;
+ int check_unchanged = false;
// 2. 3. 4. 5.: inserted/deleted lines touching this diff.
if (deleted > 0) {
@@ -341,7 +383,7 @@ static void diff_mark_adjust_tp(tabpage_T *tp, int idx, linenr_T line1,
// 5. delete lines at or just before top of diff
n = off;
dp->df_count[idx] -= line2 - dp->df_lnum[idx] + 1;
- check_unchanged = TRUE;
+ check_unchanged = true;
}
dp->df_lnum[idx] = line1;
} else {
@@ -361,7 +403,7 @@ static void diff_mark_adjust_tp(tabpage_T *tp, int idx, linenr_T line1,
} else {
n = line2 - last;
}
- check_unchanged = TRUE;
+ check_unchanged = true;
} else {
// 3. delete lines inside the diff
n = 0;
@@ -380,7 +422,7 @@ static void diff_mark_adjust_tp(tabpage_T *tp, int idx, linenr_T line1,
if (dp->df_lnum[idx] <= line1) {
// inserted lines somewhere in this diff
dp->df_count[idx] += inserted;
- check_unchanged = TRUE;
+ check_unchanged = true;
} else {
// inserted lines somewhere above this diff
dp->df_lnum[idx] += inserted;
@@ -447,12 +489,12 @@ static void diff_mark_adjust_tp(tabpage_T *tp, int idx, linenr_T line1,
}
if (tp == curtab) {
- diff_redraw(TRUE);
+ diff_redraw(true);
// Need to recompute the scroll binding, may remove or add filler
// lines (e.g., when adding lines above w_topline). But it's slow when
// making many changes, postpone until redrawing.
- diff_need_scrollbind = TRUE;
+ diff_need_scrollbind = true;
}
}
@@ -519,7 +561,7 @@ static void diff_check_unchanged(tabpage_T *tp, diff_T *dp)
}
char_u *line_org = vim_strsave(ml_get_buf(tp->tp_diffbuf[i_org],
dp->df_lnum[i_org] + off_org,
- FALSE));
+ false));
int i_new;
for (i_new = i_org + 1; i_new < DB_COUNT; ++i_new) {
@@ -538,7 +580,7 @@ static void diff_check_unchanged(tabpage_T *tp, diff_T *dp)
if (diff_cmp(line_org, ml_get_buf(tp->tp_diffbuf[i_new],
dp->df_lnum[i_new] + off_new,
- FALSE)) != 0) {
+ false)) != 0) {
break;
}
}
@@ -612,42 +654,243 @@ static void diff_redraw(int dofold)
} else if ((n > 0) && (n > wp->w_topfill)) {
wp->w_topfill = n;
}
- check_topfill(wp, FALSE);
+ check_topfill(wp, false);
+ }
+ }
+}
+
+static void clear_diffin(diffin_T *din)
+{
+ if (din->din_fname == NULL) {
+ xfree(din->din_mmfile.ptr);
+ din->din_mmfile.ptr = NULL;
+ } else {
+ os_remove((char *)din->din_fname);
+ }
+}
+
+static void clear_diffout(diffout_T *dout)
+{
+ if (dout->dout_fname == NULL) {
+ ga_clear_strings(&dout->dout_ga);
+ } else {
+ os_remove((char *)dout->dout_fname);
+ }
+}
+
+/// Write buffer "buf" to a memory buffer.
+///
+/// @param buf
+/// @param din
+///
+/// @return FAIL for failure.
+static int diff_write_buffer(buf_T *buf, diffin_T *din)
+{
+ linenr_T lnum;
+ char_u *s;
+ long len = 0;
+ char_u *ptr;
+
+ // xdiff requires one big block of memory with all the text.
+ for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++) {
+ len += (long)STRLEN(ml_get_buf(buf, lnum, false)) + 1;
+ }
+ ptr = xmalloc(len);
+ if (ptr == NULL) {
+ // Allocating memory failed. This can happen, because we try to read
+ // the whole buffer text into memory. Set the failed flag, the diff
+ // will be retried with external diff. The flag is never reset.
+ buf->b_diff_failed = true;
+ if (p_verbose > 0) {
+ verbose_enter();
+ smsg(_("Not enough memory to use internal diff for buffer \"%s\""),
+ buf->b_fname);
+ verbose_leave();
+ }
+ return FAIL;
+ }
+ din->din_mmfile.ptr = (char *)ptr;
+ din->din_mmfile.size = len;
+
+ len = 0;
+ for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++) {
+ for (s = ml_get_buf(buf, lnum, false); *s != NUL; ) {
+ if (diff_flags & DIFF_ICASE) {
+ int c;
+
+ // xdiff doesn't support ignoring case, fold-case the text.
+ int orig_len;
+ char_u cbuf[MB_MAXBYTES + 1];
+
+ c = PTR2CHAR(s);
+ c = enc_utf8 ? utf_fold(c) : TOLOWER_LOC(c);
+ orig_len = MB_PTR2LEN(s);
+ if (utf_char2bytes(c, cbuf) != orig_len) {
+ // TODO(Bram): handle byte length difference
+ memmove(ptr + len, s, orig_len);
+ } else {
+ memmove(ptr + len, cbuf, orig_len);
+ }
+
+ s += orig_len;
+ len += orig_len;
+ } else {
+ ptr[len++] = *s++;
+ }
}
+ ptr[len++] = NL;
}
+ return OK;
}
-/// Write buffer "buf" to file "name".
+/// Write buffer "buf" to file or memory buffer.
///
/// Always use 'fileformat' set to "unix".
///
/// @param buf
-/// @param fname
+/// @param din
///
/// @return FAIL for failure
-static int diff_write(buf_T *buf, char_u *fname)
+static int diff_write(buf_T *buf, diffin_T *din)
{
+ if (din->din_fname == NULL) {
+ return diff_write_buffer(buf, din);
+ }
+
+ // Always use 'fileformat' set to "unix".
char_u *save_ff = buf->b_p_ff;
buf->b_p_ff = vim_strsave((char_u *)FF_UNIX);
- int r = buf_write(buf, fname, NULL, (linenr_T)1, buf->b_ml.ml_line_count,
- NULL, FALSE, FALSE, FALSE, TRUE);
+ int r = buf_write(buf, din->din_fname, NULL,
+ (linenr_T)1, buf->b_ml.ml_line_count,
+ NULL, false, false, false, true);
free_string_option(buf->b_p_ff);
buf->b_p_ff = save_ff;
return r;
}
+///
+/// Update the diffs for all buffers involved.
+///
+/// @param dio
+/// @param idx_orig
+/// @param eap can be NULL
+static void diff_try_update(diffio_T *dio,
+ int idx_orig,
+ exarg_T *eap)
+{
+ buf_T *buf;
+ int idx_new;
+
+ if (dio->dio_internal) {
+ ga_init(&dio->dio_diff.dout_ga, sizeof(char *), 1000);
+ } else {
+ // We need three temp file names.
+ dio->dio_orig.din_fname = vim_tempname();
+ dio->dio_new.din_fname = vim_tempname();
+ dio->dio_diff.dout_fname = vim_tempname();
+ if (dio->dio_orig.din_fname == NULL
+ || dio->dio_new.din_fname == NULL
+ || dio->dio_diff.dout_fname == NULL) {
+ goto theend;
+ }
+ }
+
+ // Check external diff is actually working.
+ if (!dio->dio_internal && check_external_diff(dio) == FAIL) {
+ goto theend;
+ }
+
+ // :diffupdate!
+ if (eap != NULL && eap->forceit) {
+ for (idx_new = idx_orig; idx_new < DB_COUNT; idx_new++) {
+ buf = curtab->tp_diffbuf[idx_new];
+ if (buf_valid(buf)) {
+ buf_check_timestamp(buf, false);
+ }
+ }
+ }
+
+ // Write the first buffer to a tempfile or mmfile_t.
+ buf = curtab->tp_diffbuf[idx_orig];
+ if (diff_write(buf, &dio->dio_orig) == FAIL) {
+ goto theend;
+ }
+
+ // Make a difference between the first buffer and every other.
+ for (idx_new = idx_orig + 1; idx_new < DB_COUNT; idx_new++) {
+ buf = curtab->tp_diffbuf[idx_new];
+ if (buf == NULL || buf->b_ml.ml_mfp == NULL) {
+ continue; // skip buffer that isn't loaded
+ }
+
+ // Write the other buffer and diff with the first one.
+ if (diff_write(buf, &dio->dio_new) == FAIL) {
+ continue;
+ }
+ if (diff_file(dio) == FAIL) {
+ continue;
+ }
+
+ // Read the diff output and add each entry to the diff list.
+ diff_read(idx_orig, idx_new, &dio->dio_diff);
+
+ clear_diffin(&dio->dio_new);
+ clear_diffout(&dio->dio_diff);
+ }
+ clear_diffin(&dio->dio_orig);
+
+theend:
+ xfree(dio->dio_orig.din_fname);
+ xfree(dio->dio_new.din_fname);
+ xfree(dio->dio_diff.dout_fname);
+}
+
+///
+/// Return true if the options are set to use the internal diff library.
+/// Note that if the internal diff failed for one of the buffers, the external
+/// diff will be used anyway.
+///
+int diff_internal(void)
+{
+ return (diff_flags & DIFF_INTERNAL) != 0 && *p_dex == NUL;
+}
+
+///
+/// Return true if the internal diff failed for one of the diff buffers.
+///
+static int diff_internal_failed(void)
+{
+ int idx;
+
+ // Only need to do something when there is another buffer.
+ for (idx = 0; idx < DB_COUNT; idx++) {
+ if (curtab->tp_diffbuf[idx] != NULL
+ && curtab->tp_diffbuf[idx]->b_diff_failed) {
+ return true;
+ }
+ }
+ return false;
+}
+
/// Completely update the diffs for the buffers involved.
///
-/// This uses the ordinary "diff" command.
-/// The buffers are written to a file, also for unmodified buffers (the file
-/// could have been produced by autocommands, e.g. the netrw plugin).
+/// When using the external "diff" command the buffers are written to a file,
+/// also for unmodified buffers (the file could have been produced by
+/// autocommands, e.g. the netrw plugin).
///
/// @param eap can be NULL
void ex_diffupdate(exarg_T *eap)
{
+ if (diff_busy) {
+ diff_need_update = true;
+ return;
+ }
+
+ int had_diffs = curtab->tp_first_diff != NULL;
+
// Delete all diffblocks.
diff_clear(curtab);
- curtab->tp_diff_invalid = FALSE;
+ curtab->tp_diff_invalid = false;
// Use the first buffer as the original text.
int idx_orig;
@@ -658,7 +901,7 @@ void ex_diffupdate(exarg_T *eap)
}
if (idx_orig == DB_COUNT) {
- return;
+ goto theend;
}
// Only need to do something when there is another buffer.
@@ -670,49 +913,70 @@ void ex_diffupdate(exarg_T *eap)
}
if (idx_new == DB_COUNT) {
- return;
+ goto theend;
}
- // We need three temp file names.
- char *tmp_orig = (char *) vim_tempname();
- char *tmp_new = (char *) vim_tempname();
- char *tmp_diff = (char *) vim_tempname();
+ // Only use the internal method if it did not fail for one of the buffers.
+ diffio_T diffio;
+ memset(&diffio, 0, sizeof(diffio));
+ diffio.dio_internal = diff_internal() && !diff_internal_failed();
- if ((tmp_orig == NULL) || (tmp_new == NULL) || (tmp_diff == NULL)) {
- goto theend;
+ diff_try_update(&diffio, idx_orig, eap);
+ if (diffio.dio_internal && diff_internal_failed()) {
+ // Internal diff failed, use external diff instead.
+ memset(&diffio, 0, sizeof(diffio));
+ diff_try_update(&diffio, idx_orig, eap);
+ }
+
+ // force updating cursor position on screen
+ curwin->w_valid_cursor.lnum = 0;
+
+theend:
+ // A redraw is needed if there were diffs and they were cleared, or there
+ // are diffs now, which means they got updated.
+ if (had_diffs || curtab->tp_first_diff != NULL) {
+ diff_redraw(true);
+ apply_autocmds(EVENT_DIFFUPDATED, NULL, NULL, false, curbuf);
}
+}
- // Do a quick test if "diff" really works. Otherwise it looks like there
- // are no differences. Can't use the return value, it's non-zero when
- // there are differences.
+///
+/// Do a quick test if "diff" really works. Otherwise it looks like there
+/// are no differences. Can't use the return value, it's non-zero when
+/// there are differences.
+///
+static int check_external_diff(diffio_T *diffio)
+{
// May try twice, first with "-a" and then without.
int io_error = false;
TriState ok = kFalse;
for (;;) {
ok = kFalse;
- FILE *fd = mch_fopen(tmp_orig, "w");
+ FILE *fd = mch_fopen((char *)diffio->dio_orig.din_fname, "w");
if (fd == NULL) {
- io_error = TRUE;
+ io_error = true;
} else {
if (fwrite("line1\n", (size_t)6, (size_t)1, fd) != 1) {
- io_error = TRUE;
+ io_error = true;
}
fclose(fd);
- fd = mch_fopen(tmp_new, "w");
+ fd = mch_fopen((char *)diffio->dio_new.din_fname, "w");
if (fd == NULL) {
- io_error = TRUE;
+ io_error = true;
} else {
if (fwrite("line2\n", (size_t)6, (size_t)1, fd) != 1) {
- io_error = TRUE;
+ io_error = true;
}
fclose(fd);
- diff_file(tmp_orig, tmp_new, tmp_diff);
- fd = mch_fopen(tmp_diff, "r");
+ fd = NULL;
+ if (diff_file(diffio) == OK) {
+ fd = mch_fopen((char *)diffio->dio_diff.dout_fname, "r");
+ }
if (fd == NULL) {
- io_error = TRUE;
+ io_error = true;
} else {
char_u linebuf[LBUFLEN];
@@ -728,10 +992,10 @@ void ex_diffupdate(exarg_T *eap)
}
fclose(fd);
}
- os_remove(tmp_diff);
- os_remove(tmp_new);
+ os_remove((char *)diffio->dio_diff.dout_fname);
+ os_remove((char *)diffio->dio_new.din_fname);
}
- os_remove(tmp_orig);
+ os_remove((char *)diffio->dio_orig.din_fname);
}
// When using 'diffexpr' break here.
@@ -757,83 +1021,92 @@ void ex_diffupdate(exarg_T *eap)
}
EMSG(_("E97: Cannot create diffs"));
diff_a_works = kNone;
- goto theend;
- }
-
- // :diffupdate!
- if ((eap != NULL) && eap->forceit) {
- for (idx_new = idx_orig; idx_new < DB_COUNT; ++idx_new) {
- buf_T *buf = curtab->tp_diffbuf[idx_new];
- if (buf_valid(buf)) {
- buf_check_timestamp(buf, FALSE);
- }
- }
+ return FAIL;
}
+ return OK;
+}
- // Write the first buffer to a tempfile.
- buf_T *buf = curtab->tp_diffbuf[idx_orig];
- if (diff_write(buf, (char_u *) tmp_orig) == FAIL) {
- goto theend;
- }
+///
+/// Invoke the xdiff function.
+///
+static int diff_file_internal(diffio_T *diffio)
+{
+ xpparam_t param;
+ xdemitconf_t emit_cfg;
+ xdemitcb_t emit_cb;
- // Make a difference between the first buffer and every other.
- for (idx_new = idx_orig + 1; idx_new < DB_COUNT; ++idx_new) {
- buf_T *buf = curtab->tp_diffbuf[idx_new];
- if (buf == NULL || buf->b_ml.ml_mfp == NULL) {
- continue; // skip buffer that isn't loaded
- }
+ memset(&param, 0, sizeof(param));
+ memset(&emit_cfg, 0, sizeof(emit_cfg));
+ memset(&emit_cb, 0, sizeof(emit_cb));
- if (diff_write(buf, (char_u *) tmp_new) == FAIL) {
- continue;
- }
- diff_file(tmp_orig, tmp_new, tmp_diff);
+ param.flags = diff_algorithm;
- // Read the diff output and add each entry to the diff list.
- diff_read(idx_orig, idx_new, (char_u *) tmp_diff);
- os_remove(tmp_diff);
- os_remove(tmp_new);
+ if (diff_flags & DIFF_IWHITE) {
+ param.flags |= XDF_IGNORE_WHITESPACE_CHANGE;
+ }
+ if (diff_flags & DIFF_IWHITEALL) {
+ param.flags |= XDF_IGNORE_WHITESPACE;
+ }
+ if (diff_flags & DIFF_IWHITEEOL) {
+ param.flags |= XDF_IGNORE_WHITESPACE_AT_EOL;
+ }
+ if (diff_flags & DIFF_IBLANK) {
+ param.flags |= XDF_IGNORE_BLANK_LINES;
}
- os_remove(tmp_orig);
-
- // force updating cursor position on screen
- curwin->w_valid_cursor.lnum = 0;
-
- diff_redraw(TRUE);
-theend:
- xfree(tmp_orig);
- xfree(tmp_new);
- xfree(tmp_diff);
+ emit_cfg.ctxlen = 0; // don't need any diff_context here
+ emit_cb.priv = &diffio->dio_diff;
+ emit_cb.outf = xdiff_out;
+ if (xdl_diff(&diffio->dio_orig.din_mmfile,
+ &diffio->dio_new.din_mmfile,
+ &param, &emit_cfg, &emit_cb) < 0) {
+ EMSG(_("E960: Problem creating the internal diff"));
+ return FAIL;
+ }
+ return OK;
}
/// Make a diff between files "tmp_orig" and "tmp_new", results in "tmp_diff".
///
-/// @param tmp_orig
-/// @param tmp_new
-/// @param tmp_diff
-static void diff_file(const char *const tmp_orig, const char *const tmp_new,
- const char *const tmp_diff)
+/// @param dio
+///
+/// @return OK or FAIL
+static int diff_file(diffio_T *dio)
{
+ char *tmp_orig = (char *)dio->dio_orig.din_fname;
+ char *tmp_new = (char *)dio->dio_new.din_fname;
+ char *tmp_diff = (char *)dio->dio_diff.dout_fname;
if (*p_dex != NUL) {
// Use 'diffexpr' to generate the diff file.
eval_diff(tmp_orig, tmp_new, tmp_diff);
+ return OK;
+ }
+ // Use xdiff for generating the diff.
+ if (dio->dio_internal) {
+ return diff_file_internal(dio);
} else {
const size_t len = (strlen(tmp_orig) + strlen(tmp_new) + strlen(tmp_diff)
+ STRLEN(p_srr) + 27);
char *const cmd = xmalloc(len);
+ if (cmd == NULL) {
+ return FAIL;
+ }
- /* We don't want $DIFF_OPTIONS to get in the way. */
+ // We don't want $DIFF_OPTIONS to get in the way.
if (os_getenv("DIFF_OPTIONS")) {
os_unsetenv("DIFF_OPTIONS");
}
- /* Build the diff command and execute it. Always use -a, binary
- * differences are of no use. Ignore errors, diff returns
- * non-zero when differences have been found. */
- vim_snprintf(cmd, len, "diff %s%s%s%s%s %s",
+ // Build the diff command and execute it. Always use -a, binary
+ // differences are of no use. Ignore errors, diff returns
+ // non-zero when differences have been found.
+ vim_snprintf((char *)cmd, len, "diff %s%s%s%s%s%s%s%s %s",
diff_a_works == kFalse ? "" : "-a ",
"",
(diff_flags & DIFF_IWHITE) ? "-b " : "",
+ (diff_flags & DIFF_IWHITEALL) ? "-w " : "",
+ (diff_flags & DIFF_IWHITEEOL) ? "-Z " : "",
+ (diff_flags & DIFF_IBLANK) ? "-B " : "",
(diff_flags & DIFF_ICASE) ? "-i " : "",
tmp_orig, tmp_new);
append_redir(cmd, len, (char *) p_srr, tmp_diff);
@@ -843,6 +1116,7 @@ static void diff_file(const char *const tmp_orig, const char *const tmp_new,
NULL);
unblock_autocmds();
xfree(cmd);
+ return OK;
}
}
@@ -876,7 +1150,7 @@ void ex_diffpatch(exarg_T *eap)
// Write the current buffer to "tmp_orig".
if (buf_write(curbuf, tmp_orig, NULL,
(linenr_T)1, curbuf->b_ml.ml_line_count,
- NULL, FALSE, FALSE, FALSE, TRUE) == FAIL) {
+ NULL, false, false, false, true) == FAIL) {
goto theend;
}
@@ -907,7 +1181,7 @@ void ex_diffpatch(exarg_T *eap)
tempdir = "/tmp";
}
os_chdir(tempdir);
- shorten_fnames(TRUE);
+ shorten_fnames(true);
}
#endif
@@ -934,7 +1208,7 @@ void ex_diffpatch(exarg_T *eap)
if (os_chdir((char *)dirbuf) != 0) {
EMSG(_(e_prev_dir));
}
- shorten_fnames(TRUE);
+ shorten_fnames(true);
}
#endif
@@ -971,8 +1245,8 @@ void ex_diffpatch(exarg_T *eap)
// check that split worked and editing tmp_new
if ((curwin != old_curwin) && win_valid(old_curwin)) {
// Set 'diff', 'scrollbind' on and 'wrap' off.
- diff_win_options(curwin, TRUE);
- diff_win_options(old_curwin, TRUE);
+ diff_win_options(curwin, true);
+ diff_win_options(old_curwin, true);
if (newname != NULL) {
// do a ":file filename.new" on the patched buffer
@@ -1025,7 +1299,7 @@ void ex_diffsplit(exarg_T *eap)
if (win_split(0, (diff_flags & DIFF_VERTICAL) ? WSP_VERT : 0) != FAIL) {
// Pretend it was a ":split fname" command
eap->cmdidx = CMD_split;
- curwin->w_p_diff = TRUE;
+ curwin->w_p_diff = true;
do_exedit(eap, old_curwin);
// split must have worked
@@ -1052,7 +1326,7 @@ void ex_diffsplit(exarg_T *eap)
void ex_diffthis(exarg_T *eap)
{
// Set 'diff', 'scrollbind' on and 'wrap' off.
- diff_win_options(curwin, TRUE);
+ diff_win_options(curwin, true);
}
static void set_diff_option(win_T *wp, int value)
@@ -1085,12 +1359,12 @@ void diff_win_options(win_T *wp, int addbuf)
if (!wp->w_p_diff) {
wp->w_p_scb_save = wp->w_p_scb;
}
- wp->w_p_scb = TRUE;
+ wp->w_p_scb = true;
if (!wp->w_p_diff) {
wp->w_p_crb_save = wp->w_p_crb;
}
- wp->w_p_crb = TRUE;
+ wp->w_p_crb = true;
if (!wp->w_p_diff) {
wp->w_p_wrap_save = wp->w_p_wrap;
@@ -1116,7 +1390,7 @@ void diff_win_options(win_T *wp, int addbuf)
wp->w_p_fdl_save = wp->w_p_fdl;
}
wp->w_p_fdc = diff_foldcolumn;
- wp->w_p_fen = TRUE;
+ wp->w_p_fen = true;
wp->w_p_fdl = 0;
foldUpdateAll(wp);
@@ -1211,88 +1485,97 @@ void ex_diffoff(exarg_T *eap)
///
/// @param idx_orig idx of original file
/// @param idx_new idx of new file
-/// @param fname name of diff output file
-static void diff_read(int idx_orig, int idx_new, char_u *fname)
+/// @dout diff output
+static void diff_read(int idx_orig, int idx_new, diffout_T *dout)
{
- FILE *fd;
+ FILE *fd = NULL;
+ int line_idx = 0;
diff_T *dprev = NULL;
diff_T *dp = curtab->tp_first_diff;
diff_T *dn, *dpl;
- long f1, l1, f2, l2;
- char_u linebuf[LBUFLEN]; // only need to hold the diff line
- int difftype;
- char_u *p;
+ char_u linebuf[LBUFLEN]; // only need to hold the diff line
+ char_u *line;
long off;
int i;
linenr_T lnum_orig, lnum_new;
long count_orig, count_new;
- int notset = TRUE; // block "*dp" not set yet
-
- fd = mch_fopen((char *)fname, "r");
-
- if (fd == NULL) {
- EMSG(_("E98: Cannot read diff output"));
- return;
+ int notset = true; // block "*dp" not set yet
+ enum {
+ DIFF_ED,
+ DIFF_UNIFIED,
+ DIFF_NONE
+ } diffstyle = DIFF_NONE;
+
+ if (dout->dout_fname == NULL) {
+ diffstyle = DIFF_UNIFIED;
+ } else {
+ fd = mch_fopen((char *)dout->dout_fname, "r");
+ if (fd == NULL) {
+ EMSG(_("E98: Cannot read diff output"));
+ return;
+ }
}
for (;;) {
- if (vim_fgets(linebuf, LBUFLEN, fd)) {
- // end of file
- break;
- }
-
- if (!isdigit(*linebuf)) {
- // not the start of a diff block
- continue;
- }
-
- // This line must be one of three formats:
- // {first}[,{last}]c{first}[,{last}]
- // {first}a{first}[,{last}]
- // {first}[,{last}]d{first}
- p = linebuf;
- f1 = getdigits_long(&p);
-
- if (*p == ',') {
- ++p;
- l1 = getdigits_long(&p);
- } else {
- l1 = f1;
- }
-
- if ((*p != 'a') && (*p != 'c') && (*p != 'd')) {
- // invalid diff format
- continue;
- }
- difftype = *p++;
- f2 = getdigits_long(&p);
-
- if (*p == ',') {
- ++p;
- l2 = getdigits_long(&p);
- } else {
- l2 = f2;
- }
-
- if ((l1 < f1) || (l2 < f2)) {
- // invalid line range
- continue;
- }
-
- if (difftype == 'a') {
- lnum_orig = f1 + 1;
- count_orig = 0;
+ if (fd == NULL) {
+ if (line_idx >= dout->dout_ga.ga_len) {
+ break; // did last line
+ }
+ line = ((char_u **)dout->dout_ga.ga_data)[line_idx++];
} else {
- lnum_orig = f1;
- count_orig = l1 - f1 + 1;
+ if (vim_fgets(linebuf, LBUFLEN, fd)) {
+ break; // end of file
+ }
+ line = linebuf;
+ }
+
+ if (diffstyle == DIFF_NONE) {
+ // Determine diff style.
+ // ed like diff looks like this:
+ // {first}[,{last}]c{first}[,{last}]
+ // {first}a{first}[,{last}]
+ // {first}[,{last}]d{first}
+ //
+ // unified diff looks like this:
+ // --- file1 2018-03-20 13:23:35.783153140 +0100
+ // +++ file2 2018-03-20 13:23:41.183156066 +0100
+ // @@ -1,3 +1,5 @@
+ if (isdigit(*line)) {
+ diffstyle = DIFF_ED;
+ } else if ((STRNCMP(line, "@@ ", 3) == 0)) {
+ diffstyle = DIFF_UNIFIED;
+ } else if ((STRNCMP(line, "--- ", 4) == 0)
+ && (vim_fgets(linebuf, LBUFLEN, fd) == 0)
+ && (STRNCMP(line, "+++ ", 4) == 0)
+ && (vim_fgets(linebuf, LBUFLEN, fd) == 0)
+ && (STRNCMP(line, "@@ ", 3) == 0)) {
+ diffstyle = DIFF_UNIFIED;
+ } else {
+ // Format not recognized yet, skip over this line. Cygwin diff
+ // may put a warning at the start of the file.
+ continue;
+ }
}
- if (difftype == 'd') {
- lnum_new = f2 + 1;
- count_new = 0;
+ if (diffstyle == DIFF_ED) {
+ if (!isdigit(*line)) {
+ continue; // not the start of a diff block
+ }
+ if (parse_diff_ed(line, &lnum_orig, &count_orig,
+ &lnum_new, &count_new) == FAIL) {
+ continue;
+ }
+ } else if (diffstyle == DIFF_UNIFIED) {
+ if (STRNCMP(line, "@@ ", 3) != 0) {
+ continue; // not the start of a diff block
+ }
+ if (parse_diff_unified(line, &lnum_orig, &count_orig,
+ &lnum_new, &count_new) == FAIL) {
+ continue;
+ }
} else {
- lnum_new = f2;
- count_new = l2 - f2 + 1;
+ EMSG(_("E959: Invalid diff format."));
+ break;
}
// Go over blocks before the change, for which orig and new are equal.
@@ -1304,7 +1587,7 @@ static void diff_read(int idx_orig, int idx_new, char_u *fname)
}
dprev = dp;
dp = dp->df_next;
- notset = TRUE;
+ notset = true;
}
if ((dp != NULL)
@@ -1391,7 +1674,7 @@ static void diff_read(int idx_orig, int idx_new, char_u *fname)
}
}
}
- notset = FALSE; // "*dp" has been set
+ notset = false; // "*dp" has been set
}
// for remaining diff blocks orig and new are equal
@@ -1401,10 +1684,12 @@ static void diff_read(int idx_orig, int idx_new, char_u *fname)
}
dprev = dp;
dp = dp->df_next;
- notset = TRUE;
+ notset = true;
}
- fclose(fd);
+ if (fd != NULL) {
+ fclose(fd);
+ }
}
/// Copy an entry at "dp" from "idx_orig" to "idx_new".
@@ -1503,23 +1788,23 @@ int diff_check(win_T *wp, linenr_T lnum)
}
if (lnum < dp->df_lnum[idx] + dp->df_count[idx]) {
- int zero = FALSE;
+ int zero = false;
// Changed or inserted line. If the other buffers have a count of
// zero, the lines were inserted. If the other buffers have the same
// count, check if the lines are identical.
- cmp = FALSE;
+ cmp = false;
for (i = 0; i < DB_COUNT; ++i) {
if ((i != idx) && (curtab->tp_diffbuf[i] != NULL)) {
if (dp->df_count[i] == 0) {
- zero = TRUE;
+ zero = true;
} else {
if (dp->df_count[i] != dp->df_count[idx]) {
// nr of lines changed.
return -1;
}
- cmp = TRUE;
+ cmp = true;
}
}
}
@@ -1543,7 +1828,7 @@ int diff_check(win_T *wp, linenr_T lnum)
// the difference. Can't remove the entry here, we might be halfway
// through updating the window. Just report the text as unchanged.
// Other windows might still show the change though.
- if (zero == FALSE) {
+ if (zero == false) {
return 0;
}
return -2;
@@ -1635,20 +1920,28 @@ static bool diff_equal_char(const char_u *const p1, const char_u *const p2,
/// @return on-zero if the two strings are different.
static int diff_cmp(char_u *s1, char_u *s2)
{
- if ((diff_flags & (DIFF_ICASE | DIFF_IWHITE)) == 0) {
+ if ((diff_flags & DIFF_IBLANK)
+ && (*skipwhite(s1) == NUL || *skipwhite(s2) == NUL)) {
+ return 0;
+ }
+
+ if ((diff_flags & (DIFF_ICASE | ALL_WHITE_DIFF)) == 0) {
return STRCMP(s1, s2);
}
- if ((diff_flags & DIFF_ICASE) && !(diff_flags & DIFF_IWHITE)) {
+ if ((diff_flags & DIFF_ICASE) && !(diff_flags & ALL_WHITE_DIFF)) {
return mb_stricmp((const char *)s1, (const char *)s2);
}
- // Ignore white space changes and possibly ignore case.
char_u *p1 = s1;
char_u *p2 = s2;
+ // Ignore white space changes and possibly ignore case.
while (*p1 != NUL && *p2 != NUL) {
- if (ascii_iswhite(*p1) && ascii_iswhite(*p2)) {
+ if (((diff_flags & DIFF_IWHITE)
+ && ascii_iswhite(*p1) && ascii_iswhite(*p2))
+ || ((diff_flags & DIFF_IWHITEALL)
+ && (ascii_iswhite(*p1) || ascii_iswhite(*p2)))) {
p1 = skipwhite(p1);
p2 = skipwhite(p2);
} else {
@@ -1815,6 +2108,8 @@ int diffopt_changed(void)
int diff_context_new = 6;
int diff_flags_new = 0;
int diff_foldcolumn_new = 2;
+ long diff_algorithm_new = 0;
+ long diff_indent_heuristic = 0;
char_u *p = p_dip;
while (*p != NUL) {
@@ -1824,9 +2119,18 @@ int diffopt_changed(void)
} else if ((STRNCMP(p, "context:", 8) == 0) && ascii_isdigit(p[8])) {
p += 8;
diff_context_new = getdigits_int(&p);
+ } else if (STRNCMP(p, "iblank", 6) == 0) {
+ p += 6;
+ diff_flags_new |= DIFF_IBLANK;
} else if (STRNCMP(p, "icase", 5) == 0) {
p += 5;
diff_flags_new |= DIFF_ICASE;
+ } else if (STRNCMP(p, "iwhiteall", 9) == 0) {
+ p += 9;
+ diff_flags_new |= DIFF_IWHITEALL;
+ } else if (STRNCMP(p, "iwhiteeol", 9) == 0) {
+ p += 9;
+ diff_flags_new |= DIFF_IWHITEEOL;
} else if (STRNCMP(p, "iwhite", 6) == 0) {
p += 6;
diff_flags_new |= DIFF_IWHITE;
@@ -1842,6 +2146,29 @@ int diffopt_changed(void)
} else if (STRNCMP(p, "hiddenoff", 9) == 0) {
p += 9;
diff_flags_new |= DIFF_HIDDEN_OFF;
+ } else if (STRNCMP(p, "indent-heuristic", 16) == 0) {
+ p += 16;
+ diff_indent_heuristic = XDF_INDENT_HEURISTIC;
+ } else if (STRNCMP(p, "internal", 8) == 0) {
+ p += 8;
+ diff_flags_new |= DIFF_INTERNAL;
+ } else if (STRNCMP(p, "algorithm:", 10) == 0) {
+ p += 10;
+ if (STRNCMP(p, "myers", 5) == 0) {
+ p += 5;
+ diff_algorithm_new = 0;
+ } else if (STRNCMP(p, "minimal", 7) == 0) {
+ p += 7;
+ diff_algorithm_new = XDF_NEED_MINIMAL;
+ } else if (STRNCMP(p, "patience", 8) == 0) {
+ p += 8;
+ diff_algorithm_new = XDF_PATIENCE_DIFF;
+ } else if (STRNCMP(p, "histogram", 9) == 0) {
+ p += 9;
+ diff_algorithm_new = XDF_HISTOGRAM_DIFF;
+ } else {
+ return FAIL;
+ }
}
if ((*p != ',') && (*p != NUL)) {
@@ -1853,23 +2180,27 @@ int diffopt_changed(void)
}
}
+ diff_algorithm_new |= diff_indent_heuristic;
+
// Can't have both "horizontal" and "vertical".
if ((diff_flags_new & DIFF_HORIZONTAL) && (diff_flags_new & DIFF_VERTICAL)) {
return FAIL;
}
- // If "icase" or "iwhite" was added or removed, need to update the diff.
- if (diff_flags != diff_flags_new) {
+ // If flags were added or removed, or the algorithm was changed, need to
+ // update the diff.
+ if (diff_flags != diff_flags_new || diff_algorithm != diff_algorithm_new) {
FOR_ALL_TABS(tp) {
- tp->tp_diff_invalid = TRUE;
+ tp->tp_diff_invalid = true;
}
}
diff_flags = diff_flags_new;
diff_context = diff_context_new;
diff_foldcolumn = diff_foldcolumn_new;
+ diff_algorithm = diff_algorithm_new;
- diff_redraw(TRUE);
+ diff_redraw(true);
// recompute the scroll binding with the new option value, may
// remove or add filler lines
@@ -1910,7 +2241,7 @@ bool diff_find_change(win_T *wp, linenr_T lnum, int *startp, int *endp)
int l;
// Make a copy of the line, the next ml_get() will invalidate it.
- char_u *line_org = vim_strsave(ml_get_buf(wp->w_buffer, lnum, FALSE));
+ char_u *line_org = vim_strsave(ml_get_buf(wp->w_buffer, lnum, false));
int idx = diff_buf_idx(wp->w_buffer);
if (idx == DB_COUNT) {
@@ -1942,15 +2273,18 @@ bool diff_find_change(win_T *wp, linenr_T lnum, int *startp, int *endp)
}
added = false;
line_new = ml_get_buf(curtab->tp_diffbuf[i],
- dp->df_lnum[i] + off, FALSE);
+ dp->df_lnum[i] + off, false);
// Search for start of difference
si_org = si_new = 0;
while (line_org[si_org] != NUL) {
- if ((diff_flags & DIFF_IWHITE)
- && ascii_iswhite(line_org[si_org])
- && ascii_iswhite(line_new[si_new])) {
+ if (((diff_flags & DIFF_IWHITE)
+ && ascii_iswhite(line_org[si_org])
+ && ascii_iswhite(line_new[si_new]))
+ || ((diff_flags & DIFF_IWHITEALL)
+ && (ascii_iswhite(line_org[si_org])
+ || ascii_iswhite(line_new[si_new])))) {
si_org = (int)(skipwhite(line_org + si_org) - line_org);
si_new = (int)(skipwhite(line_new + si_new) - line_new);
} else {
@@ -1980,9 +2314,12 @@ bool diff_find_change(win_T *wp, linenr_T lnum, int *startp, int *endp)
&& ei_new >= si_new
&& ei_org >= 0
&& ei_new >= 0) {
- if ((diff_flags & DIFF_IWHITE)
- && ascii_iswhite(line_org[ei_org])
- && ascii_iswhite(line_new[ei_new])) {
+ if (((diff_flags & DIFF_IWHITE)
+ && ascii_iswhite(line_org[ei_org])
+ && ascii_iswhite(line_new[ei_new]))
+ || ((diff_flags & DIFF_IWHITEALL)
+ && (ascii_iswhite(line_org[ei_org])
+ || ascii_iswhite(line_new[ei_new])))) {
while (ei_org >= *startp && ascii_iswhite(line_org[ei_org])) {
ei_org--;
}
@@ -2117,7 +2454,7 @@ void ex_diffgetput(exarg_T *eap)
int start_skip, end_skip;
int new_count;
int buf_empty;
- int found_not_ma = FALSE;
+ int found_not_ma = false;
int idx_other;
int idx_from;
int idx_to;
@@ -2138,7 +2475,7 @@ void ex_diffgetput(exarg_T *eap)
|| MODIFIABLE(curtab->tp_diffbuf[idx_other])) {
break;
}
- found_not_ma = TRUE;
+ found_not_ma = true;
}
}
@@ -2176,7 +2513,7 @@ void ex_diffgetput(exarg_T *eap)
// digits only
i = atol((char *)eap->arg);
} else {
- i = buflist_findpat(eap->arg, p, FALSE, TRUE, FALSE);
+ i = buflist_findpat(eap->arg, p, false, true, false);
if (i < 0) {
// error message already given
@@ -2202,7 +2539,7 @@ void ex_diffgetput(exarg_T *eap)
}
}
- diff_busy = TRUE;
+ diff_busy = true;
// When no range given include the line above or below the cursor.
if (eap->addr_count == 0) {
@@ -2239,7 +2576,7 @@ void ex_diffgetput(exarg_T *eap)
change_warning(0);
if (diff_buf_idx(curbuf) != idx_to) {
EMSG(_("E787: Buffer changed unexpectedly"));
- return;
+ goto theend;
}
}
@@ -2308,7 +2645,7 @@ void ex_diffgetput(exarg_T *eap)
for (i = 0; i < count; ++i) {
// remember deleting the last line of the buffer
buf_empty = curbuf->b_ml.ml_line_count == 1;
- ml_delete(lnum, FALSE);
+ ml_delete(lnum, false);
added--;
}
@@ -2317,15 +2654,15 @@ void ex_diffgetput(exarg_T *eap)
if (nr > curtab->tp_diffbuf[idx_from]->b_ml.ml_line_count) {
break;
}
- p = vim_strsave(ml_get_buf(curtab->tp_diffbuf[idx_from], nr, FALSE));
- ml_append(lnum + i - 1, p, 0, FALSE);
+ p = vim_strsave(ml_get_buf(curtab->tp_diffbuf[idx_from], nr, false));
+ ml_append(lnum + i - 1, p, 0, false);
xfree(p);
added++;
if (buf_empty && (curbuf->b_ml.ml_line_count == 2)) {
// Added the first line into an empty buffer, need to
// delete the dummy empty line.
- buf_empty = FALSE;
- ml_delete((linenr_T)2, FALSE);
+ buf_empty = false;
+ ml_delete((linenr_T)2, false);
}
}
new_count = dp->df_count[idx_to] + added;
@@ -2399,20 +2736,31 @@ void ex_diffgetput(exarg_T *eap)
// another buffer. Sync undo if the command was typed. This isn't
// 100% right when ":diffput" is used in a function or mapping.
if (KeyTyped) {
- u_sync(FALSE);
+ u_sync(false);
}
aucmd_restbuf(&aco);
}
- diff_busy = FALSE;
+theend:
+ diff_busy = false;
+ if (diff_need_update) {
+ ex_diffupdate(NULL);
+ }
- // Check that the cursor is on a valid character and update it's position.
- // When there were filler lines the topline has become invalid.
+ // Check that the cursor is on a valid character and update its
+ // position. When there were filler lines the topline has become
+ // invalid.
check_cursor();
changed_line_abv_curs();
- // Also need to redraw the other buffers.
- diff_redraw(FALSE);
+ if (diff_need_update) {
+ // redraw already done by ex_diffupdate()
+ diff_need_update = false;
+ } else {
+ // Also need to redraw the other buffers.
+ diff_redraw(false);
+ apply_autocmds(EVENT_DIFFUPDATED, NULL, NULL, false, curbuf);
+ }
}
/// Update folds for all diff buffers for entry "dp".
@@ -2637,3 +2985,145 @@ linenr_T diff_lnum_win(linenr_T lnum, win_T *wp)
}
return n;
}
+
+///
+/// Handle an ED style diff line.
+/// Return FAIL if the line does not contain diff info.
+///
+static int parse_diff_ed(char_u *line,
+ linenr_T *lnum_orig,
+ long *count_orig,
+ linenr_T *lnum_new,
+ long *count_new)
+{
+ char_u *p;
+ long f1, l1, f2, l2;
+ int difftype;
+
+ // The line must be one of three formats:
+ // change: {first}[,{last}]c{first}[,{last}]
+ // append: {first}a{first}[,{last}]
+ // delete: {first}[,{last}]d{first}
+ p = line;
+ f1 = getdigits(&p);
+ if (*p == ',') {
+ p++;
+ l1 = getdigits(&p);
+ } else {
+ l1 = f1;
+ }
+ if (*p != 'a' && *p != 'c' && *p != 'd') {
+ return FAIL; // invalid diff format
+ }
+ difftype = *p++;
+ f2 = getdigits(&p);
+ if (*p == ',') {
+ p++;
+ l2 = getdigits(&p);
+ } else {
+ l2 = f2;
+ }
+ if (l1 < f1 || l2 < f2) {
+ return FAIL;
+ }
+
+ if (difftype == 'a') {
+ *lnum_orig = f1 + 1;
+ *count_orig = 0;
+ } else {
+ *lnum_orig = f1;
+ *count_orig = l1 - f1 + 1;
+ }
+ if (difftype == 'd') {
+ *lnum_new = f2 + 1;
+ *count_new = 0;
+ } else {
+ *lnum_new = f2;
+ *count_new = l2 - f2 + 1;
+ }
+ return OK;
+}
+
+///
+/// Parses unified diff with zero(!) context lines.
+/// Return FAIL if there is no diff information in "line".
+///
+static int parse_diff_unified(char_u *line,
+ linenr_T *lnum_orig,
+ long *count_orig,
+ linenr_T *lnum_new,
+ long *count_new)
+{
+ char_u *p;
+ long oldline, oldcount, newline, newcount;
+
+ // Parse unified diff hunk header:
+ // @@ -oldline,oldcount +newline,newcount @@
+ p = line;
+ if (*p++ == '@' && *p++ == '@' && *p++ == ' ' && *p++ == '-') {
+ oldline = getdigits(&p);
+ if (*p == ',') {
+ p++;
+ oldcount = getdigits(&p);
+ } else {
+ oldcount = 1;
+ }
+ if (*p++ == ' ' && *p++ == '+') {
+ newline = getdigits(&p);
+ if (*p == ',') {
+ p++;
+ newcount = getdigits(&p);
+ } else {
+ newcount = 1;
+ }
+ } else {
+ return FAIL; // invalid diff format
+ }
+
+ if (oldcount == 0) {
+ oldline += 1;
+ }
+ if (newcount == 0) {
+ newline += 1;
+ }
+ if (newline == 0) {
+ newline = 1;
+ }
+
+ *lnum_orig = oldline;
+ *count_orig = oldcount;
+ *lnum_new = newline;
+ *count_new = newcount;
+
+ return OK;
+ }
+
+ return FAIL;
+}
+
+///
+/// Callback function for the xdl_diff() function.
+/// Stores the diff output in a grow array.
+///
+static int xdiff_out(void *priv, mmbuffer_t *mb, int nbuf)
+{
+ diffout_T *dout = (diffout_T *)priv;
+ char_u *p;
+
+ // The header line always comes by itself, text lines in at least two
+ // parts. We drop the text part.
+ if (nbuf > 1) {
+ return 0;
+ }
+
+ // sanity check
+ if (STRNCMP(mb[0].ptr, "@@ ", 3) != 0) {
+ return 0;
+ }
+
+ ga_grow(&dout->dout_ga, 1);
+
+ p = vim_strnsave((char_u *)mb[0].ptr, mb[0].size);
+ ((char_u **)dout->dout_ga.ga_data)[dout->dout_ga.ga_len++] = p;
+ return 0;
+}
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index d20660bfb9..c04190eaba 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -3127,10 +3127,16 @@ static void ins_compl_restart(void)
*/
static void ins_compl_set_original_text(char_u *str)
{
- /* Replace the original text entry. */
- if (compl_first_match->cp_flags & ORIGINAL_TEXT) { /* safety check */
+ // Replace the original text entry.
+ // The ORIGINAL_TEXT flag is either at the first item or might possibly be
+ // at the last item for backward completion
+ if (compl_first_match->cp_flags & ORIGINAL_TEXT) { // safety check
xfree(compl_first_match->cp_str);
compl_first_match->cp_str = vim_strsave(str);
+ } else if (compl_first_match->cp_prev != NULL
+ && (compl_first_match->cp_prev->cp_flags & ORIGINAL_TEXT)) {
+ xfree(compl_first_match->cp_prev->cp_str);
+ compl_first_match->cp_prev->cp_str = vim_strsave(str);
}
}
@@ -3189,7 +3195,8 @@ static bool ins_compl_prep(int c)
/* Ignore end of Select mode mapping and mouse scroll buttons. */
if (c == K_SELECT || c == K_MOUSEDOWN || c == K_MOUSEUP
- || c == K_MOUSELEFT || c == K_MOUSERIGHT || c == K_EVENT) {
+ || c == K_MOUSELEFT || c == K_MOUSERIGHT || c == K_EVENT
+ || c == K_COMMAND) {
return retval;
}
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 4e0e3f6f1f..d67818aa81 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -2728,6 +2728,12 @@ void ex_call(exarg_T *eap)
lnum = eap->line1;
for (; lnum <= eap->line2; lnum++) {
if (eap->addr_count > 0) { // -V560
+ if (lnum > curbuf->b_ml.ml_line_count) {
+ // If the function deleted lines or switched to another buffer
+ // the line number may become invalid.
+ EMSG(_(e_invrange));
+ break;
+ }
curwin->w_cursor.lnum = lnum;
curwin->w_cursor.col = 0;
curwin->w_cursor.coladd = 0;
@@ -8119,6 +8125,7 @@ static void f_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr)
const int save_msg_silent = msg_silent;
const int save_emsg_silent = emsg_silent;
const bool save_emsg_noredir = emsg_noredir;
+ const bool save_redir_off = redir_off;
garray_T *const save_capture_ga = capture_ga;
if (check_secure()) {
@@ -8146,6 +8153,7 @@ static void f_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr)
garray_T capture_local;
ga_init(&capture_local, (int)sizeof(char), 80);
capture_ga = &capture_local;
+ redir_off = false;
if (argvars[0].v_type != VAR_LIST) {
do_cmdline_cmd(tv_get_string(&argvars[0]));
@@ -8163,6 +8171,7 @@ static void f_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr)
msg_silent = save_msg_silent;
emsg_silent = save_emsg_silent;
emsg_noredir = save_emsg_noredir;
+ redir_off = save_redir_off;
ga_append(capture_ga, NUL);
rettv->v_type = VAR_STRING;
@@ -10326,10 +10335,10 @@ static void f_getwininfo(typval_T *argvars, typval_T *rettv, FunPtr fptr)
tabnr++;
int16_t winnr = 0;
FOR_ALL_WINDOWS_IN_TAB(wp, tp) {
+ winnr++;
if (wparg != NULL && wp != wparg) {
continue;
}
- winnr++;
dict_T *const d = get_win_info(wp, tabnr, winnr);
tv_list_append_dict(rettv->vval.v_list, d);
if (wparg != NULL) {
@@ -10793,17 +10802,6 @@ static void f_has(typval_T *argvars, typval_T *rettv, FunPtr fptr)
n = true;
}
- if (STRICMP(name, "ruby") == 0 && n == true) {
- char *rubyhost = call_func_retstr("provider#ruby#Detect", 0, NULL, true);
- if (rubyhost) {
- if (*rubyhost == NUL) {
- // Invalid rubyhost executable. Gem is probably not installed.
- n = false;
- }
- xfree(rubyhost);
- }
- }
-
rettv->vval.v_number = n;
}
@@ -11718,7 +11716,7 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (new_cwd && strlen(new_cwd) > 0) {
cwd = new_cwd;
// The new cwd must be a directory.
- if (!os_isdir((char_u *)cwd)) {
+ if (!os_isdir_executable((const char *)cwd)) {
EMSG2(_(e_invarg2), "expected valid directory");
shell_free_argv(argv);
return;
@@ -16763,7 +16761,7 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (new_cwd && *new_cwd != NUL) {
cwd = new_cwd;
// The new cwd must be a directory.
- if (!os_isdir((const char_u *)cwd)) {
+ if (!os_isdir_executable((const char *)cwd)) {
EMSG2(_(e_invarg2), "expected valid directory");
shell_free_argv(argv);
return;
@@ -19244,7 +19242,8 @@ static void set_var(const char *name, const size_t name_len, typval_T *const tv,
}
return;
} else if (v->di_tv.v_type != tv->v_type) {
- internal_error("set_var()");
+ EMSG2(_("E963: setting %s to value with wrong type"), name);
+ return;
}
}
@@ -19532,6 +19531,7 @@ void ex_echo(exarg_T *eap)
typval_T rettv;
bool needclr = true;
bool atstart = true;
+ const int did_emsg_before = did_emsg;
if (eap->skip)
++emsg_skip;
@@ -19546,7 +19546,7 @@ void ex_echo(exarg_T *eap)
// Report the invalid expression unless the expression evaluation
// has been cancelled due to an aborting error, an interrupt, or an
// exception.
- if (!aborting()) {
+ if (!aborting() && did_emsg == did_emsg_before) {
EMSG2(_(e_invexpr2), p);
}
need_clr_eos = false;
@@ -19635,7 +19635,7 @@ void ex_execute(exarg_T *eap)
int ret = OK;
char_u *p;
garray_T ga;
- int save_did_emsg;
+ int save_did_emsg = did_emsg;
ga_init(&ga, 1, 80);
@@ -19649,8 +19649,9 @@ void ex_execute(exarg_T *eap)
* has been cancelled due to an aborting error, an interrupt, or an
* exception.
*/
- if (!aborting())
+ if (!aborting() && did_emsg == save_did_emsg) {
EMSG2(_(e_invexpr2), p);
+ }
ret = FAIL;
break;
}
@@ -22758,7 +22759,18 @@ bool eval_has_provider(const char *name)
CHECK_PROVIDER(python);
return has_python;
} else if (strequal(name, "ruby")) {
+ bool need_check_ruby = (has_ruby == -1);
CHECK_PROVIDER(ruby);
+ if (need_check_ruby && has_ruby == 1) {
+ char *rubyhost = call_func_retstr("provider#ruby#Detect", 0, NULL, true);
+ if (rubyhost) {
+ if (*rubyhost == NUL) {
+ // Invalid rubyhost executable. Gem is probably not installed.
+ has_ruby = 0;
+ }
+ xfree(rubyhost);
+ }
+ }
return has_ruby;
}
diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c
index 2563e38258..e9ab6cd3e2 100644
--- a/src/nvim/eval/encode.c
+++ b/src/nvim/eval/encode.c
@@ -933,7 +933,7 @@ char *encode_tv2json(typval_T *tv, size_t *len)
#define TYPVAL_ENCODE_CONV_BOOL(tv, num) \
do { \
- if ((num)) { \
+ if (num) { \
msgpack_pack_true(packer); \
} else { \
msgpack_pack_false(packer); \
diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c
index 6a93b20345..912aecafec 100644
--- a/src/nvim/eval/typval.c
+++ b/src/nvim/eval/typval.c
@@ -2850,7 +2850,7 @@ const char *tv_get_string_buf_chk(const typval_T *const tv, char *const buf)
/// Get the string value of a "stringish" VimL object.
///
/// @warning For number and special values it uses a single, static buffer. It
-/// may be used only once, next call to get_tv_string may reuse it. Use
+/// may be used only once, next call to tv_get_string may reuse it. Use
/// tv_get_string_buf() if you need to use tv_get_string() output after
/// calling it again.
///
@@ -2869,7 +2869,7 @@ const char *tv_get_string_chk(const typval_T *const tv)
/// Get the string value of a "stringish" VimL object.
///
/// @warning For number and special values it uses a single, static buffer. It
-/// may be used only once, next call to get_tv_string may reuse it. Use
+/// may be used only once, next call to tv_get_string may reuse it. Use
/// tv_get_string_buf() if you need to use tv_get_string() output after
/// calling it again.
///
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index dc942eb0b3..36c4e333cf 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -816,10 +816,23 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest)
linenr_T last_line; // Last line in file after adding new text
if (dest >= line1 && dest < line2) {
- EMSG(_("E134: Move lines into themselves"));
+ EMSG(_("E134: Cannot move a range of lines into itself"));
return FAIL;
}
+ // Do nothing if we are not actually moving any lines. This will prevent
+ // the 'modified' flag from being set without cause.
+ if (dest == line1 - 1 || dest == line2) {
+ // Move the cursor as if lines were moved (see below) to be backwards
+ // compatible.
+ if (dest >= line1) {
+ curwin->w_cursor.lnum = dest;
+ } else {
+ curwin->w_cursor.lnum = dest + (line2 - line1) + 1;
+ }
+ return OK;
+ }
+
num_lines = line2 - line1 + 1;
/*
@@ -5672,6 +5685,14 @@ void ex_sign(exarg_T *eap)
int len;
arg += 5;
+ for (s = arg; s + 1 < p; s++) {
+ if (*s == '\\') {
+ // Remove a backslash, so that it is possible
+ // to use a space.
+ STRMOVE(s, s + 1);
+ p--;
+ }
+ }
// Count cells and check for non-printable chars
cells = 0;
diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua
index df1aa938ed..79ca5363e0 100644
--- a/src/nvim/ex_cmds.lua
+++ b/src/nvim/ex_cmds.lua
@@ -28,15 +28,15 @@ local FILES = bit.bor(XFILE, EXTRA)
local WORD1 = bit.bor(EXTRA, NOSPC)
local FILE1 = bit.bor(FILES, NOSPC)
-local ADDR_LINES = 0
-local ADDR_WINDOWS = 1
-local ADDR_ARGUMENTS = 2
-local ADDR_LOADED_BUFFERS = 3
-local ADDR_BUFFERS = 4
-local ADDR_TABS = 5
-local ADDR_TABS_RELATIVE = 6
-local ADDR_QUICKFIX = 7
-local ADDR_OTHER = 99
+local ADDR_LINES = 0 -- buffer line numbers
+local ADDR_WINDOWS = 1 -- window number
+local ADDR_ARGUMENTS = 2 -- argument number
+local ADDR_LOADED_BUFFERS = 3 -- buffer number of loaded buffer
+local ADDR_BUFFERS = 4 -- buffer number
+local ADDR_TABS = 5 -- tab page number
+local ADDR_TABS_RELATIVE = 6 -- Tab page that only relative
+local ADDR_QUICKFIX = 7 -- quickfix list entry number
+local ADDR_OTHER = 99 -- something else
-- The following table is described in ex_cmds_defs.h file.
return {
@@ -1707,24 +1707,6 @@ return {
func='ex_next',
},
{
- command='nbkey',
- flags=bit.bor(EXTRA, NOTADR, NEEDARG),
- addr_type=ADDR_LINES,
- func='ex_ni',
- },
- {
- command='nbclose',
- flags=bit.bor(TRLBAR, CMDWIN),
- addr_type=ADDR_LINES,
- func='ex_ni',
- },
- {
- command='nbstart',
- flags=bit.bor(WORD1, TRLBAR, CMDWIN),
- addr_type=ADDR_LINES,
- func='ex_ni',
- },
- {
command='new',
flags=bit.bor(BANG, FILE1, RANGE, NOTADR, EDITCMD, ARGOPT, TRLBAR),
addr_type=ADDR_LINES,
@@ -1959,18 +1941,6 @@ return {
func='ex_previous',
},
{
- command='promptfind',
- flags=bit.bor(EXTRA, NOTRLCOM, CMDWIN),
- addr_type=ADDR_LINES,
- func='ex_ni',
- },
- {
- command='promptrepl',
- flags=bit.bor(EXTRA, NOTRLCOM, CMDWIN),
- addr_type=ADDR_LINES,
- func='ex_ni',
- },
- {
command='profile',
flags=bit.bor(BANG, EXTRA, TRLBAR, CMDWIN),
addr_type=ADDR_LINES,
@@ -2326,8 +2296,8 @@ return {
},
{
command='scriptnames',
- flags=bit.bor(TRLBAR, CMDWIN),
- addr_type=ADDR_LINES,
+ flags=bit.bor(BANG, RANGE, NOTADR, COUNT, TRLBAR, CMDWIN),
+ addr_type=ADDR_OTHER,
func='ex_scriptnames',
},
{
@@ -3117,12 +3087,6 @@ return {
func='do_wqall',
},
{
- command='wsverb',
- flags=bit.bor(EXTRA, NOTADR, NEEDARG),
- addr_type=ADDR_LINES,
- func='ex_ni',
- },
- {
command='wshada',
flags=bit.bor(BANG, FILE1, TRLBAR, CMDWIN),
addr_type=ADDR_LINES,
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index 90fb7b8bc3..c9b6d19aaa 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -3069,6 +3069,17 @@ theend:
/// ":scriptnames"
void ex_scriptnames(exarg_T *eap)
{
+ if (eap->addr_count > 0) {
+ // :script {scriptId}: edit the script
+ if (eap->line2 < 1 || eap->line2 > script_items.ga_len) {
+ EMSG(_(e_invarg));
+ } else {
+ eap->arg = SCRIPT_ITEM(eap->line2).sn_name;
+ do_exedit(eap, NULL);
+ }
+ return;
+ }
+
for (int i = 1; i <= script_items.ga_len && !got_int; i++) {
if (SCRIPT_ITEM(i).sn_name != NULL) {
home_replace(NULL, SCRIPT_ITEM(i).sn_name,
@@ -3506,7 +3517,12 @@ static char *get_locale_val(int what)
}
#endif
-
+// Return true when "lang" starts with a valid language name.
+// Rejects NULL, empty string, "C", "C.UTF-8" and others.
+static bool is_valid_mess_lang(char *lang)
+{
+ return lang != NULL && ASCII_ISALPHA(lang[0]) && ASCII_ISALPHA(lang[1]);
+}
/// Obtain the current messages language. Used to set the default for
/// 'helplang'. May return NULL or an empty string.
@@ -3526,14 +3542,14 @@ char *get_mess_lang(void)
# endif
# else
p = os_getenv("LC_ALL");
- if (p == NULL) {
+ if (!is_valid_mess_lang(p)) {
p = os_getenv("LC_MESSAGES");
- if (p == NULL) {
+ if (!is_valid_mess_lang(p)) {
p = os_getenv("LANG");
}
}
# endif
- return p;
+ return is_valid_mess_lang(p) ? p : NULL;
}
// Complicated #if; matches with where get_mess_env() is used below.
@@ -3812,7 +3828,13 @@ static void script_host_execute(char *name, exarg_T *eap)
// current range
tv_list_append_number(args, (int)eap->line1);
tv_list_append_number(args, (int)eap->line2);
- (void)eval_call_provider(name, "execute", args);
+
+ if (!eval_has_provider(name)) {
+ emsgf("E319: No \"%s\" provider found. Run \":checkhealth provider\"",
+ name);
+ } else {
+ (void)eval_call_provider(name, "execute", args);
+ }
}
}
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 6ac7656a2f..4ef332186e 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -1804,15 +1804,19 @@ static char_u * do_one_cmd(char_u **cmdlinep,
errormsg = (char_u *)_(get_text_locked_msg());
goto doend;
}
- /* Disallow editing another buffer when "curbuf_lock" is set.
- * Do allow ":edit" (check for argument later).
- * Do allow ":checktime" (it's postponed). */
+
+ // Disallow editing another buffer when "curbuf_lock" is set.
+ // Do allow ":checktime" (it is postponed).
+ // Do allow ":edit" (check for an argument later).
+ // Do allow ":file" with no arguments (check for an argument later).
if (!(ea.argt & CMDWIN)
- && ea.cmdidx != CMD_edit
&& ea.cmdidx != CMD_checktime
+ && ea.cmdidx != CMD_edit
+ && ea.cmdidx != CMD_file
&& !IS_USER_CMDIDX(ea.cmdidx)
- && curbuf_locked())
+ && curbuf_locked()) {
goto doend;
+ }
if (!ni && !(ea.argt & RANGE) && ea.addr_count > 0) {
/* no range allowed */
@@ -1884,6 +1888,11 @@ static char_u * do_one_cmd(char_u **cmdlinep,
else
ea.arg = skipwhite(p);
+ // ":file" cannot be run with an argument when "curbuf_lock" is set
+ if (ea.cmdidx == CMD_file && *ea.arg != NUL && curbuf_locked()) {
+ goto doend;
+ }
+
/*
* Check for "++opt=val" argument.
* Must be first, allow ":w ++enc=utf8 !cmd"
@@ -8645,7 +8654,10 @@ eval_vars (
break;
case SPEC_AFILE: // file name for autocommand
- if (autocmd_fname != NULL && !path_is_absolute(autocmd_fname)) {
+ if (autocmd_fname != NULL
+ && !path_is_absolute(autocmd_fname)
+ // For CmdlineEnter and related events, <afile> is not a path! #9348
+ && !strequal("/", (char *)autocmd_fname)) {
// Still need to turn the fname into a full path. It was
// postponed to avoid a delay when <afile> is not used.
result = (char_u *)FullName_save((char *)autocmd_fname, false);
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 19a52c913a..bfc32887ca 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -1804,6 +1804,37 @@ static int empty_pattern(char_u *p)
static int command_line_changed(CommandLineState *s)
{
+ // Trigger CmdlineChanged autocommands.
+ if (has_event(EVENT_CMDLINECHANGED)) {
+ TryState tstate;
+ Error err = ERROR_INIT;
+ bool tl_ret = true;
+ dict_T *dict = get_vim_var_dict(VV_EVENT);
+
+ char firstcbuf[2];
+ firstcbuf[0] = s->firstc > 0 ? s->firstc : '-';
+ firstcbuf[1] = 0;
+
+ // set v:event to a dictionary with information about the commandline
+ tv_dict_add_str(dict, S_LEN("cmdtype"), firstcbuf);
+ tv_dict_add_nr(dict, S_LEN("cmdlevel"), ccline.level);
+ tv_dict_set_keys_readonly(dict);
+ try_enter(&tstate);
+
+ apply_autocmds(EVENT_CMDLINECHANGED, (char_u *)firstcbuf,
+ (char_u *)firstcbuf, false, curbuf);
+ tv_dict_clear(dict);
+
+ tl_ret = try_leave(&tstate, &err);
+ if (!tl_ret && ERROR_SET(&err)) {
+ msg_putchar('\n');
+ msg_printf_attr(HL_ATTR(HLF_E)|MSG_HIST, (char *)e_autocmd_err, err.msg);
+ api_clear_error(&err);
+ redrawcmd();
+ }
+ tl_ret = true;
+ }
+
// 'incsearch' highlighting.
if (p_is && !cmd_silent && (s->firstc == '/' || s->firstc == '?')) {
pos_T end_pos;
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index d0e30ddbd3..fe12a69801 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -1739,13 +1739,13 @@ failed:
close(0);
#ifndef WIN32
// On Unix, use stderr for stdin, makes shell commands work.
- ignored = dup(2);
+ vim_ignored = dup(2);
#else
// On Windows, use the console input handle for stdin.
HANDLE conin = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ, (LPSECURITY_ATTRIBUTES)NULL,
OPEN_EXISTING, 0, (HANDLE)NULL);
- ignored = _open_osfhandle(conin, _O_RDONLY);
+ vim_ignored = _open_osfhandle(conin, _O_RDONLY);
#endif
}
@@ -4531,48 +4531,83 @@ bool vim_fgets(char_u *buf, int size, FILE *fp) FUNC_ATTR_NONNULL_ALL
}
/// Read 2 bytes from "fd" and turn them into an int, MSB first.
+/// Returns -1 when encountering EOF.
int get2c(FILE *fd)
{
- int n;
-
- n = getc(fd);
- n = (n << 8) + getc(fd);
- return n;
+ const int n = getc(fd);
+ if (n == EOF) {
+ return -1;
+ }
+ const int c = getc(fd);
+ if (c == EOF) {
+ return -1;
+ }
+ return (n << 8) + c;
}
/// Read 3 bytes from "fd" and turn them into an int, MSB first.
+/// Returns -1 when encountering EOF.
int get3c(FILE *fd)
{
- int n;
-
- n = getc(fd);
- n = (n << 8) + getc(fd);
- n = (n << 8) + getc(fd);
- return n;
+ int n = getc(fd);
+ if (n == EOF) {
+ return -1;
+ }
+ int c = getc(fd);
+ if (c == EOF) {
+ return -1;
+ }
+ n = (n << 8) + c;
+ c = getc(fd);
+ if (c == EOF) {
+ return -1;
+ }
+ return (n << 8) + c;
}
/// Read 4 bytes from "fd" and turn them into an int, MSB first.
+/// Returns -1 when encountering EOF.
int get4c(FILE *fd)
{
// Use unsigned rather than int otherwise result is undefined
// when left-shift sets the MSB.
unsigned n;
- n = (unsigned)getc(fd);
- n = (n << 8) + (unsigned)getc(fd);
- n = (n << 8) + (unsigned)getc(fd);
- n = (n << 8) + (unsigned)getc(fd);
+ int c = getc(fd);
+ if (c == EOF) {
+ return -1;
+ }
+ n = (unsigned)c;
+ c = getc(fd);
+ if (c == EOF) {
+ return -1;
+ }
+ n = (n << 8) + (unsigned)c;
+ c = getc(fd);
+ if (c == EOF) {
+ return -1;
+ }
+ n = (n << 8) + (unsigned)c;
+ c = getc(fd);
+ if (c == EOF) {
+ return -1;
+ }
+ n = (n << 8) + (unsigned)c;
return (int)n;
}
/// Read 8 bytes from `fd` and turn them into a time_t, MSB first.
+/// Returns -1 when encountering EOF.
time_t get8ctime(FILE *fd)
{
time_t n = 0;
- int i;
- for (i = 0; i < 8; i++) {
- n = (n << 8) + getc(fd);
+ for (int i = 0; i < 8; i++) {
+ const int c = getc(fd);
+ if (c == EOF) {
+ return -1;
+ }
+ n = (n << 8) + c;
}
return n;
}
@@ -5932,19 +5967,19 @@ void au_event_restore(char_u *old_ei)
* will be automatically executed for <event>
* when editing a file matching <pat>, in
* the current group.
- * :autocmd <event> <pat> Show the auto-commands associated with
+ * :autocmd <event> <pat> Show the autocommands associated with
* <event> and <pat>.
- * :autocmd <event> Show the auto-commands associated with
+ * :autocmd <event> Show the autocommands associated with
* <event>.
- * :autocmd Show all auto-commands.
- * :autocmd! <event> <pat> <cmd> Remove all auto-commands associated with
+ * :autocmd Show all autocommands.
+ * :autocmd! <event> <pat> <cmd> Remove all autocommands associated with
* <event> and <pat>, and add the command
* <cmd>, for the current group.
- * :autocmd! <event> <pat> Remove all auto-commands associated with
+ * :autocmd! <event> <pat> Remove all autocommands associated with
* <event> and <pat> for the current group.
- * :autocmd! <event> Remove all auto-commands associated with
+ * :autocmd! <event> Remove all autocommands associated with
* <event> for the current group.
- * :autocmd! Remove ALL auto-commands for the current
+ * :autocmd! Remove ALL autocommands for the current
* group.
*
* Multiple events and patterns may be given separated by commas. Here are
@@ -6037,8 +6072,8 @@ void do_autocmd(char_u *arg_in, int forceit)
* Print header when showing autocommands.
*/
if (!forceit && *cmd == NUL) {
- /* Highlight title */
- MSG_PUTS_TITLE(_("\n--- Auto-Commands ---"));
+ // Highlight title
+ MSG_PUTS_TITLE(_("\n--- Autocommands ---"));
}
/*
@@ -6868,7 +6903,13 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io,
} else {
sfname = vim_strsave(fname);
// Don't try expanding the following events.
- if (event == EVENT_COLORSCHEME
+ if (event == EVENT_CMDLINECHANGED
+ || event == EVENT_CMDLINEENTER
+ || event == EVENT_CMDLINELEAVE
+ || event == EVENT_CMDWINENTER
+ || event == EVENT_CMDWINLEAVE
+ || event == EVENT_CMDUNDEFINED
+ || event == EVENT_COLORSCHEME
|| event == EVENT_COLORSCHEMEPRE
|| event == EVENT_DIRCHANGED
|| event == EVENT_FILETYPE
@@ -6907,8 +6948,8 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io,
autocmd_match = fname;
- /* Don't redraw while doing auto commands. */
- ++RedrawingDisabled;
+ // Don't redraw while doing autocommands.
+ RedrawingDisabled++;
save_sourcing_name = sourcing_name;
sourcing_name = NULL; /* don't free this one */
save_sourcing_lnum = sourcing_lnum;
@@ -7119,7 +7160,7 @@ auto_next_pat (
apc->tail, ap->allow_dirs)
: ap->buflocal_nr == apc->arg_bufnr) {
const char *const name = event_nr2name(apc->event);
- s = _("%s Auto commands for \"%s\"");
+ s = _("%s Autocommands for \"%s\"");
const size_t sourcing_name_len = (STRLEN(s) + strlen(name) + ap->patlen
+ 1);
sourcing_name = xmalloc(sourcing_name_len);
diff --git a/src/nvim/fold.c b/src/nvim/fold.c
index 53a3218c51..39975308d7 100644
--- a/src/nvim/fold.c
+++ b/src/nvim/fold.c
@@ -171,9 +171,8 @@ bool hasFoldingWin(
int low_level = 0;
checkupdate(win);
- /*
- * Return quickly when there is no folding at all in this window.
- */
+
+ // Return quickly when there is no folding at all in this window.
if (!hasAnyFolding(win)) {
if (infop != NULL)
infop->fi_level = 0;
@@ -2851,8 +2850,9 @@ static void foldlevelIndent(fline_T *flp)
flp->lvl = 0;
else
flp->lvl = -1;
- } else
- flp->lvl = get_indent_buf(buf, lnum) / get_sw_value(curbuf);
+ } else {
+ flp->lvl = get_indent_buf(buf, lnum) / get_sw_value(buf);
+ }
if (flp->lvl > flp->wp->w_p_fdn) {
flp->lvl = (int) MAX(0, flp->wp->w_p_fdn);
}
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index df74e8b2ff..04ff1320ce 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -1125,8 +1125,7 @@ EXTERN FILE *time_fd INIT(= NULL); /* where to write startup timing */
* can't do anything useful with the value. Assign to this variable to avoid
* the warning.
*/
-EXTERN int ignored;
-EXTERN char *ignoredp;
+EXTERN int vim_ignored;
// Start a msgpack-rpc channel over stdin/stdout.
EXTERN bool embedded_mode INIT(= false);
diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c
index a104137d9e..5a9727f46e 100644
--- a/src/nvim/highlight.c
+++ b/src/nvim/highlight.c
@@ -177,8 +177,27 @@ void update_window_hl(win_T *wp, bool invalid)
}
}
+/// Gets HL_UNDERLINE highlight.
+int hl_get_underline(void)
+{
+ return get_attr_entry((HlEntry){
+ .attr = (HlAttrs){
+ .cterm_ae_attr = (int16_t)HL_UNDERLINE,
+ .cterm_fg_color = 0,
+ .cterm_bg_color = 0,
+ .rgb_ae_attr = (int16_t)HL_UNDERLINE,
+ .rgb_fg_color = -1,
+ .rgb_bg_color = -1,
+ .rgb_sp_color = -1,
+ },
+ .kind = kHlUI,
+ .id1 = 0,
+ .id2 = 0,
+ });
+}
+
/// Get attribute code for forwarded :terminal highlights.
-int get_term_attr_entry(HlAttrs *aep)
+int hl_get_term_attr(HlAttrs *aep)
{
return get_attr_entry((HlEntry){ .attr= *aep, .kind = kHlTerminal,
.id1 = 0, .id2 = 0 });
diff --git a/src/nvim/highlight_defs.h b/src/nvim/highlight_defs.h
index 09d20c75ea..40025fcbbb 100644
--- a/src/nvim/highlight_defs.h
+++ b/src/nvim/highlight_defs.h
@@ -22,7 +22,7 @@ typedef enum {
/// Stores a complete highlighting entry, including colors and attributes
/// for both TUI and GUI.
typedef struct attr_entry {
- int16_t rgb_ae_attr, cterm_ae_attr; // HL_BOLD, etc.
+ int16_t rgb_ae_attr, cterm_ae_attr; ///< HlAttrFlags
RgbValue rgb_fg_color, rgb_bg_color, rgb_sp_color;
int cterm_fg_color, cterm_bg_color;
} HlAttrs;
@@ -37,17 +37,6 @@ typedef struct attr_entry {
.cterm_bg_color = 0, \
}
-// sentinel value that compares unequal to any valid highlight
-#define HLATTRS_INVALID (HlAttrs) { \
- .rgb_ae_attr = -1, \
- .cterm_ae_attr = -1, \
- .rgb_fg_color = -1, \
- .rgb_bg_color = -1, \
- .rgb_sp_color = -1, \
- .cterm_fg_color = 0, \
- .cterm_bg_color = 0, \
-}
-
/// Values for index in highlight_attr[].
/// When making changes, also update hlf_names below!
typedef enum {
@@ -94,8 +83,8 @@ typedef enum {
, HLF_TP // tabpage line
, HLF_TPS // tabpage line selected
, HLF_TPF // tabpage line filler
- , HLF_CUC // 'cursurcolumn'
- , HLF_CUL // 'cursurline'
+ , HLF_CUC // 'cursorcolumn'
+ , HLF_CUL // 'cursorline'
, HLF_MC // 'colorcolumn'
, HLF_QFL // selected quickfix line
, HLF_0 // Whitespace
diff --git a/src/nvim/main.c b/src/nvim/main.c
index af54e62393..8a40577e8f 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -73,6 +73,7 @@
#ifndef WIN32
# include "nvim/os/pty_process_unix.h"
#endif
+#include "nvim/api/vim.h"
// Maximum number of commands from + or -c arguments.
#define MAX_ARG_CMDS 10
@@ -150,6 +151,8 @@ void event_init(void)
signal_init();
// finish mspgack-rpc initialization
channel_init();
+ remote_ui_init();
+ api_vim_init();
terminal_init();
}
@@ -1719,6 +1722,48 @@ static void exe_commands(mparm_T *parmp)
TIME_MSG("executing command arguments");
}
+/// Source system-wide vimrc if built with one defined
+///
+/// Does one of the following things, stops after whichever succeeds:
+///
+/// 1. Source system vimrc file from $XDG_CONFIG_DIRS/nvim/sysinit.vim
+/// 2. Source system vimrc file from $VIM
+static void do_system_initialization(void)
+{
+ char *const config_dirs = stdpaths_get_xdg_var(kXDGConfigDirs);
+ if (config_dirs != NULL) {
+ const void *iter = NULL;
+ const char path_tail[] = {
+ 'n', 'v', 'i', 'm', PATHSEP,
+ 's', 'y', 's', 'i', 'n', 'i', 't', '.', 'v', 'i', 'm', NUL
+ };
+ do {
+ const char *dir;
+ size_t dir_len;
+ iter = vim_env_iter(':', config_dirs, iter, &dir, &dir_len);
+ if (dir == NULL || dir_len == 0) {
+ break;
+ }
+ char *vimrc = xmalloc(dir_len + sizeof(path_tail) + 1);
+ memcpy(vimrc, dir, dir_len);
+ vimrc[dir_len] = PATHSEP;
+ memcpy(vimrc + dir_len + 1, path_tail, sizeof(path_tail));
+ if (do_source((char_u *)vimrc, false, DOSO_NONE) != FAIL) {
+ xfree(vimrc);
+ xfree(config_dirs);
+ return;
+ }
+ xfree(vimrc);
+ } while (iter != NULL);
+ xfree(config_dirs);
+ }
+
+#ifdef SYS_VIMRC_FILE
+ // Get system wide defaults, if the file name is defined.
+ (void)do_source((char_u *)SYS_VIMRC_FILE, false, DOSO_NONE);
+#endif
+}
+
/// Source vimrc or do other user initialization
///
/// Does one of the following things, stops after whichever succeeds:
@@ -1801,10 +1846,7 @@ static void source_startup_scripts(const mparm_T *const parmp)
}
}
} else if (!silent_mode) {
-#ifdef SYS_VIMRC_FILE
- // Get system wide defaults, if the file name is defined.
- (void) do_source((char_u *)SYS_VIMRC_FILE, false, DOSO_NONE);
-#endif
+ do_system_initialization();
if (do_user_initialization()) {
// Read initialization commands from ".vimrc" or ".exrc" in current
diff --git a/src/nvim/map.c b/src/nvim/map.c
index cc264f3729..53ab734802 100644
--- a/src/nvim/map.c
+++ b/src/nvim/map.c
@@ -166,3 +166,4 @@ MAP_IMPL(handle_T, ptr_t, DEFAULT_INITIALIZER)
MAP_IMPL(String, MsgpackRpcRequestHandler, MSGPACK_HANDLER_INITIALIZER)
#define KVEC_INITIALIZER { .size = 0, .capacity = 0, .items = NULL }
MAP_IMPL(HlEntry, int, DEFAULT_INITIALIZER)
+MAP_IMPL(String, handle_T, 0)
diff --git a/src/nvim/map.h b/src/nvim/map.h
index 65204a798b..0e4308b953 100644
--- a/src/nvim/map.h
+++ b/src/nvim/map.h
@@ -37,6 +37,7 @@ MAP_DECLS(uint64_t, ptr_t)
MAP_DECLS(handle_T, ptr_t)
MAP_DECLS(String, MsgpackRpcRequestHandler)
MAP_DECLS(HlEntry, int)
+MAP_DECLS(String, handle_T)
#define map_new(T, U) map_##T##_##U##_new
#define map_free(T, U) map_##T##_##U##_free
diff --git a/src/nvim/memory.c b/src/nvim/memory.c
index 8789075c44..6b96a3b070 100644
--- a/src/nvim/memory.c
+++ b/src/nvim/memory.c
@@ -16,6 +16,7 @@
#include "nvim/message.h"
#include "nvim/misc1.h"
#include "nvim/ui.h"
+#include "nvim/api/vim.h"
#ifdef HAVE_JEMALLOC
// Force je_ prefix on jemalloc functions.
@@ -681,6 +682,7 @@ void free_all_mem(void)
break;
eval_clear();
+ api_vim_free_all_mem();
// Free all buffers. Reset 'autochdir' to avoid accessing things that
// were freed already.
diff --git a/src/nvim/message.c b/src/nvim/message.c
index edce30e6fa..6de81a8aaf 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -505,7 +505,7 @@ int emsg(const char_u *s_)
*/
if (cause_errthrow((char_u *)s, severe, &ignore) == true) {
if (!ignore) {
- did_emsg = true;
+ did_emsg++;
}
return true;
}
@@ -554,7 +554,7 @@ int emsg(const char_u *s_)
} else {
flush_buffers(FLUSH_MINIMAL); // flush internal buffers
}
- did_emsg = true; // flag for DoOneCmd()
+ did_emsg++; // flag for DoOneCmd()
}
emsg_on_display = true; // remember there is an error message
@@ -1896,6 +1896,9 @@ static void msg_scroll_up(void)
} else {
screen_del_lines(0, 1, (int)Rows, 0, Columns);
}
+ // TODO(bfredl): when msgsep display is properly batched, this fill should be
+ // eliminated.
+ screen_fill(Rows-1, Rows, 0, (int)Columns, ' ', ' ', 0);
}
/*
@@ -2311,6 +2314,7 @@ static int do_more_prompt(int typed_char)
if (toscroll == -1
&& screen_ins_lines(0, 1, (int)Rows, 0, (int)Columns) == OK) {
+ screen_fill(0, 1, 0, (int)Columns, ' ', ' ', 0);
// display line at top
(void)disp_sb_line(0, mp);
} else {
@@ -2821,7 +2825,6 @@ do_dialog (
Ex command */
)
{
- int oldState;
int retval = 0;
char_u *hotkeys;
int c;
@@ -2834,7 +2837,10 @@ do_dialog (
}
- oldState = State;
+ int save_msg_silent = msg_silent;
+ int oldState = State;
+
+ msg_silent = 0; // If dialog prompts for input, user needs to see it! #8788
State = CONFIRM;
setmouse();
@@ -2887,6 +2893,7 @@ do_dialog (
xfree(hotkeys);
+ msg_silent = save_msg_silent;
State = oldState;
setmouse();
--no_wait_return;
diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c
index 4032210213..ffe2d11f08 100644
--- a/src/nvim/misc1.c
+++ b/src/nvim/misc1.c
@@ -52,6 +52,7 @@
#include "nvim/window.h"
#include "nvim/os/os.h"
#include "nvim/os/shell.h"
+#include "nvim/os/signal.h"
#include "nvim/os/input.h"
#include "nvim/os/time.h"
#include "nvim/event/stream.h"
@@ -1121,8 +1122,9 @@ int get_last_leader_offset(char_u *line, char_u **flags)
if (ascii_iswhite(string[0])) {
if (i == 0 || !ascii_iswhite(line[i - 1]))
continue;
- while (ascii_iswhite(string[0]))
- ++string;
+ while (ascii_iswhite(*string)) {
+ string++;
+ }
}
for (j = 0; string[j] != NUL && string[j] == line[i + j]; ++j)
/* do nothing */;
@@ -1138,6 +1140,19 @@ int get_last_leader_offset(char_u *line, char_u **flags)
continue;
}
+ if (vim_strchr(part_buf, COM_MIDDLE) != NULL) {
+ // For a middlepart comment, only consider it to match if
+ // everything before the current position in the line is
+ // whitespace. Otherwise we would think we are inside a
+ // comment if the middle part appears somewhere in the middle
+ // of the line. E.g. for C the "*" appears often.
+ for (j = 0; ascii_iswhite(line[j]) && j <= i; j++) {
+ }
+ if (j < i) {
+ continue;
+ }
+ }
+
/*
* We have found a match, stop searching.
*/
@@ -1936,10 +1951,10 @@ changed_lines(
{
changed_lines_buf(curbuf, lnum, lnume, xtra);
- if (xtra == 0 && curwin->w_p_diff) {
- /* When the number of lines doesn't change then mark_adjust() isn't
- * called and other diff buffers still need to be marked for
- * displaying. */
+ if (xtra == 0 && curwin->w_p_diff && !diff_internal()) {
+ // When the number of lines doesn't change then mark_adjust() isn't
+ // called and other diff buffers still need to be marked for
+ // displaying.
linenr_T wlnum;
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
@@ -2008,6 +2023,10 @@ static void changed_common(linenr_T lnum, colnr_T col, linenr_T lnume, long xtra
/* mark the buffer as modified */
changed();
+ if (curwin->w_p_diff && diff_internal()) {
+ curtab->tp_diff_update = true;
+ }
+
/* set the '. mark */
if (!cmdmod.keepjumps) {
RESET_FMARK(&curbuf->b_last_change, ((pos_T) {lnum, col, 0}), 0);
@@ -2653,6 +2672,8 @@ void preserve_exit(void)
}
really_exiting = true;
+ // Ignore SIGHUP while we are already exiting. #9274
+ signal_reject_deadly();
mch_errmsg(IObuff);
mch_errmsg("\n");
ui_flush();
diff --git a/src/nvim/move.c b/src/nvim/move.c
index bddcefc8ec..3a29851ee6 100644
--- a/src/nvim/move.c
+++ b/src/nvim/move.c
@@ -918,9 +918,9 @@ void curs_columns(
extra = ((int)prev_skipcol - (int)curwin->w_skipcol) / width;
if (extra > 0) {
- win_ins_lines(curwin, 0, extra, false);
+ win_ins_lines(curwin, 0, extra);
} else if (extra < 0) {
- win_del_lines(curwin, 0, -extra, false);
+ win_del_lines(curwin, 0, -extra);
}
} else {
curwin->w_skipcol = 0;
diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c
index 3356cdc61e..46a9e95b91 100644
--- a/src/nvim/msgpack_rpc/channel.c
+++ b/src/nvim/msgpack_rpc/channel.c
@@ -641,7 +641,16 @@ static WBuffer *serialize_response(uint64_t channel_id,
{
msgpack_packer pac;
msgpack_packer_init(&pac, sbuffer, msgpack_sbuffer_write);
- msgpack_rpc_serialize_response(response_id, err, arg, &pac);
+ if (ERROR_SET(err) && response_id == NO_RESPONSE) {
+ Array args = ARRAY_DICT_INIT;
+ ADD(args, INTEGER_OBJ(err->type));
+ ADD(args, STRING_OBJ(cstr_to_string(err->msg)));
+ msgpack_rpc_serialize_request(0, cstr_as_string("nvim_error_event"),
+ args, &pac);
+ api_free_array(args);
+ } else {
+ msgpack_rpc_serialize_response(response_id, err, arg, &pac);
+ }
log_server_msg(channel_id, sbuffer);
WBuffer *rv = wstream_new_buffer(xmemdup(sbuffer->data, sbuffer->size),
sbuffer->size,
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index f87de52a82..38ee0936aa 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -1325,6 +1325,14 @@ static int normal_check(VimState *state)
normal_check_cursor_moved(s);
normal_check_text_changed(s);
+ // Updating diffs from changed() does not always work properly,
+ // esp. updating folds. Do an update just before redrawing if
+ // needed.
+ if (curtab->tp_diff_update || curtab->tp_diff_invalid) {
+ ex_diffupdate(NULL);
+ curtab->tp_diff_update = false;
+ }
+
// Scroll-binding for diff mode may have been postponed until
// here. Avoids doing it for every change.
if (diff_need_scrollbind) {
diff --git a/src/nvim/option.c b/src/nvim/option.c
index a0fb2d9e36..11f3df7cfa 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -1068,6 +1068,10 @@ void set_helplang_default(const char *lang)
if (STRNICMP(p_hlg, "zh_", 3) == 0 && STRLEN(p_hlg) >= 5) {
p_hlg[0] = (char_u)TOLOWER_ASC(p_hlg[3]);
p_hlg[1] = (char_u)TOLOWER_ASC(p_hlg[4]);
+ } else if (STRLEN(p_hlg) >= 1 && *p_hlg == 'C') {
+ // any C like setting, such as C.UTF-8, becomes "en"
+ p_hlg[0] = 'e';
+ p_hlg[1] = 'n';
}
p_hlg[2] = NUL;
options[idx].flags |= P_ALLOCED;
@@ -1769,14 +1773,13 @@ do_set (
// Set the new value.
*(char_u **)(varp) = newval;
- if (!starting && origval != NULL && newval != NULL) {
- // origval may be freed by
- // did_set_string_option(), make a copy.
- saved_origval = xstrdup((char *)origval);
- // newval (and varp) may become invalid if the
- // buffer is closed by autocommands.
- saved_newval = xstrdup((char *)newval);
- }
+ // origval may be freed by
+ // did_set_string_option(), make a copy.
+ saved_origval = (origval != NULL) ? xstrdup((char *)origval) : 0;
+
+ // newval (and varp) may become invalid if the
+ // buffer is closed by autocommands.
+ saved_newval = (newval != NULL) ? xstrdup((char *)newval) : 0;
// Handle side effects, and set the global value for
// ":set" on local options. Note: when setting 'syntax'
@@ -1786,8 +1789,14 @@ do_set (
new_value_alloced, oldval, errbuf, opt_flags);
if (errmsg == NULL) {
- trigger_optionsset_string(opt_idx, opt_flags, saved_origval,
- saved_newval);
+ if (!starting) {
+ trigger_optionsset_string(opt_idx, opt_flags, saved_origval,
+ saved_newval);
+ }
+ if (options[opt_idx].flags & P_UI_OPTION) {
+ ui_call_option_set(cstr_as_string(options[opt_idx].fullname),
+ STRING_OBJ(cstr_as_string(saved_newval)));
+ }
}
xfree(saved_origval);
xfree(saved_newval);
@@ -2378,8 +2387,8 @@ static char *set_string_option(const int opt_idx, const char *const value,
char *const oldval = *varp;
*varp = s;
- char *const saved_oldval = (starting ? NULL : xstrdup(oldval));
- char *const saved_newval = (starting ? NULL : xstrdup(s));
+ char *const saved_oldval = xstrdup(oldval);
+ char *const saved_newval = xstrdup(s);
char *const r = (char *)did_set_string_option(
opt_idx, (char_u **)varp, (int)true, (char_u *)oldval, NULL, opt_flags);
@@ -2389,8 +2398,13 @@ static char *set_string_option(const int opt_idx, const char *const value,
// call autocommand after handling side effects
if (r == NULL) {
- trigger_optionsset_string(opt_idx, opt_flags,
- saved_oldval, saved_newval);
+ if (!starting) {
+ trigger_optionsset_string(opt_idx, opt_flags, saved_oldval, saved_newval);
+ }
+ if (options[opt_idx].flags & P_UI_OPTION) {
+ ui_call_option_set(cstr_as_string(options[opt_idx].fullname),
+ STRING_OBJ(cstr_as_string(saved_newval)));
+ }
}
xfree(saved_oldval);
xfree(saved_newval);
@@ -4056,10 +4070,11 @@ static char *set_bool_option(const int opt_idx, char_u *const varp,
(char_u *) options[opt_idx].fullname,
NULL, false, NULL);
reset_v_option_vars();
- if (options[opt_idx].flags & P_UI_OPTION) {
- ui_call_option_set(cstr_as_string(options[opt_idx].fullname),
- BOOLEAN_OBJ(value));
- }
+ }
+
+ if (options[opt_idx].flags & P_UI_OPTION) {
+ ui_call_option_set(cstr_as_string(options[opt_idx].fullname),
+ BOOLEAN_OBJ(value));
}
comp_col(); /* in case 'ruler' or 'showcmd' changed */
@@ -4429,10 +4444,11 @@ static char *set_num_option(int opt_idx, char_u *varp, long value,
(char_u *) options[opt_idx].fullname,
NULL, false, NULL);
reset_v_option_vars();
- if (options[opt_idx].flags & P_UI_OPTION) {
- ui_call_option_set(cstr_as_string(options[opt_idx].fullname),
- INTEGER_OBJ(value));
- }
+ }
+
+ if (errmsg == NULL && options[opt_idx].flags & P_UI_OPTION) {
+ ui_call_option_set(cstr_as_string(options[opt_idx].fullname),
+ INTEGER_OBJ(value));
}
comp_col(); /* in case 'columns' or 'ls' changed */
@@ -4461,10 +4477,6 @@ static void trigger_optionsset_string(int opt_idx, int opt_flags,
apply_autocmds(EVENT_OPTIONSET,
(char_u *)options[opt_idx].fullname, NULL, false, NULL);
reset_v_option_vars();
- if (options[opt_idx].flags & P_UI_OPTION) {
- ui_call_option_set(cstr_as_string(options[opt_idx].fullname),
- STRING_OBJ(cstr_as_string(newval)));
- }
}
}
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index bc7f1a2b0a..0cc6f58c5f 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -132,10 +132,10 @@ return {
{
full_name='background', abbreviation='bg',
type='string', scope={'global'},
- vi_def=true,
+ vim=true,
redraw={'all_windows'},
varname='p_bg',
- defaults={if_true={vi="light"}}
+ defaults={if_true={vi="light",vim="dark"}}
},
{
full_name='backspace', abbreviation='bs',
@@ -615,7 +615,7 @@ return {
alloced=true,
redraw={'current_window'},
varname='p_dip',
- defaults={if_true={vi="filler"}}
+ defaults={if_true={vi="internal,filler"}}
},
{
full_name='digraph', abbreviation='dg',
diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c
index cf00fd4f82..9a4391a0ae 100644
--- a/src/nvim/os/fs.c
+++ b/src/nvim/os/fs.c
@@ -110,7 +110,7 @@ bool os_isrealdir(const char *name)
/// Check if the given path is a directory or not.
///
-/// @return `true` if `fname` is a directory.
+/// @return `true` if `name` is a directory.
bool os_isdir(const char_u *name)
FUNC_ATTR_NONNULL_ALL
{
@@ -126,6 +126,25 @@ bool os_isdir(const char_u *name)
return true;
}
+/// Check if the given path is a directory and is executable.
+/// Gives the same results as `os_isdir()` on Windows.
+///
+/// @return `true` if `name` is a directory and executable.
+bool os_isdir_executable(const char *name)
+ FUNC_ATTR_NONNULL_ALL
+{
+ int32_t mode = os_getperm((const char *)name);
+ if (mode < 0) {
+ return false;
+ }
+
+#ifdef WIN32
+ return (S_ISDIR(mode));
+#else
+ return (S_ISDIR(mode) && (S_IXUSR & mode));
+#endif
+}
+
/// Check what `name` is:
/// @return NODE_NORMAL: file or directory (or doesn't exist)
/// NODE_WRITABLE: writable device, socket, fifo, etc.
diff --git a/src/nvim/os/lang.c b/src/nvim/os/lang.c
index 6b2a54ddbe..108a9c6c39 100644
--- a/src/nvim/os/lang.c
+++ b/src/nvim/os/lang.c
@@ -17,14 +17,31 @@ void lang_init(void)
{
#ifdef __APPLE__
if (os_getenv("LANG") == NULL) {
+ const char *lang_region = NULL;
+ CFTypeRef cf_lang_region = NULL;
+
CFLocaleRef cf_locale = CFLocaleCopyCurrent();
- CFTypeRef cf_lang_region = CFLocaleGetValue(cf_locale,
- kCFLocaleIdentifier);
- CFRetain(cf_lang_region);
- CFRelease(cf_locale);
+ if (cf_locale) {
+ cf_lang_region = CFLocaleGetValue(cf_locale, kCFLocaleIdentifier);
+ CFRetain(cf_lang_region);
+ lang_region = CFStringGetCStringPtr(cf_lang_region,
+ kCFStringEncodingUTF8);
+ CFRelease(cf_locale);
+ } else {
+ // Use the primary language defined in Preferences -> Language & Region
+ CFArrayRef cf_langs = CFLocaleCopyPreferredLanguages();
+ if (cf_langs && CFArrayGetCount(cf_langs) > 0) {
+ cf_lang_region = CFArrayGetValueAtIndex(cf_langs, 0);
+ CFRetain(cf_lang_region);
+ CFRelease(cf_langs);
+ lang_region = CFStringGetCStringPtr(cf_lang_region,
+ kCFStringEncodingUTF8);
+ } else {
+ ELOG("$LANG is empty and your primary language cannot be inferred.");
+ return;
+ }
+ }
- const char *lang_region = CFStringGetCStringPtr(cf_lang_region,
- kCFStringEncodingUTF8);
if (lang_region) {
os_setenv("LANG", lang_region, true);
} else {
@@ -37,6 +54,11 @@ void lang_init(void)
CFRelease(cf_lang_region);
# ifdef HAVE_LOCALE_H
setlocale(LC_ALL, "");
+
+# ifdef LC_NUMERIC
+ // Make sure strtod() uses a decimal point, not a comma.
+ setlocale(LC_NUMERIC, "C");
+# endif
# endif
}
#endif
diff --git a/src/nvim/os/pty_process_unix.c b/src/nvim/os/pty_process_unix.c
index bafbfe1e4b..bcf57e1b5b 100644
--- a/src/nvim/os/pty_process_unix.c
+++ b/src/nvim/os/pty_process_unix.c
@@ -12,7 +12,7 @@
#include <sys/ioctl.h>
// forkpty is not in POSIX, so headers are platform-specific
-#if defined(__FreeBSD__) || defined (__DragonFly__)
+#if defined(__FreeBSD__) || defined(__DragonFly__)
# include <libutil.h>
#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
# include <util.h>
diff --git a/src/nvim/po/CMakeLists.txt b/src/nvim/po/CMakeLists.txt
index 6811f99add..3a70264dd1 100644
--- a/src/nvim/po/CMakeLists.txt
+++ b/src/nvim/po/CMakeLists.txt
@@ -8,6 +8,7 @@ if(NOT LANGUAGES)
af
ca
cs
+ da
de
en_GB
eo
diff --git a/src/nvim/po/da.po b/src/nvim/po/da.po
new file mode 100644
index 0000000000..58cd19210b
--- /dev/null
+++ b/src/nvim/po/da.po
@@ -0,0 +1,7088 @@
+# Danish translation for Vim
+# Copyright (C) 2018 The Vim authors
+# This file is distributed under the same license as the vim package.
+# scootergrisen, 2018.
+msgid ""
+msgstr ""
+"Project-Id-Version: Vim 8.1\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2018-06-08 22:09+0200\n"
+"PO-Revision-Date: 2018-06-23 23:30+0200\n"
+"Last-Translator: scootergrisen\n"
+"Language-Team: Danish\n"
+"Language: da\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+msgid "E831: bf_key_init() called with empty password"
+msgstr "E831: bf_key_init() kaldt med tom adgangskode"
+
+msgid "E820: sizeof(uint32_t) != 4"
+msgstr "E820: sizeof(uint32_t) != 4"
+
+msgid "E817: Blowfish big/little endian use wrong"
+msgstr "E817: Forkert brug af stor/lille byterækkefølge for blowfish"
+
+msgid "E818: sha256 test failed"
+msgstr "E818: sha256-test mislykkede"
+
+msgid "E819: Blowfish test failed"
+msgstr "E819: Blowfish-test mislykkede"
+
+msgid "[Location List]"
+msgstr "[Placeringsliste]"
+
+msgid "[Quickfix List]"
+msgstr "[Quickfix-liste]"
+
+msgid "E855: Autocommands caused command to abort"
+msgstr "E855: Autokommandoer forårsagede afbrydelse af kommando"
+
+msgid "E82: Cannot allocate any buffer, exiting..."
+msgstr "E82: Kan ikke allokere buffer, afslutter..."
+
+msgid "E83: Cannot allocate buffer, using other one..."
+msgstr "E83: Kan ikke allokere buffer, bruger en anden..."
+
+msgid "E931: Buffer cannot be registered"
+msgstr "E931: Buffer kan ikke registreres"
+
+msgid "E937: Attempt to delete a buffer that is in use"
+msgstr "E937: Forsøg på at slette en buffer som er i brug"
+
+msgid "E515: No buffers were unloaded"
+msgstr "E515: Ingen buffere blev udlæst"
+
+msgid "E516: No buffers were deleted"
+msgstr "E516: Ingen brugere blev slettet"
+
+msgid "E517: No buffers were wiped out"
+msgstr "E517: Ingen buffere blev ryddet"
+
+msgid "1 buffer unloaded"
+msgstr "1 buffer udlæst"
+
+#, c-format
+msgid "%d buffers unloaded"
+msgstr "%d buffere udlæst"
+
+msgid "1 buffer deleted"
+msgstr "1 buffer slettet"
+
+#, c-format
+msgid "%d buffers deleted"
+msgstr "%d buffere slettet"
+
+msgid "1 buffer wiped out"
+msgstr "1 buffer ryddet"
+
+#, c-format
+msgid "%d buffers wiped out"
+msgstr "%d buffere ryddet"
+
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: Kan ikke udlæse sidste buffer"
+
+msgid "E84: No modified buffer found"
+msgstr "E84: Fandt ingen ændret buffer"
+
+msgid "E85: There is no listed buffer"
+msgstr "E85: Der er ingen oplistet buffer"
+
+msgid "E87: Cannot go beyond last buffer"
+msgstr "E87: Kan ikke gå over sidste buffer"
+
+msgid "E88: Cannot go before first buffer"
+msgstr "E88: Kan ikke gå før første buffer"
+
+#, c-format
+msgid "E89: No write since last change for buffer %ld (add ! to override)"
+msgstr ""
+"E89: Ingen skrivning siden sidste ændring for bufferen %ld (tilføj ! for at "
+"tilsidesætte)"
+
+msgid "E948: Job still running (add ! to end the job)"
+msgstr "E948: Job kører stadig (tilføj ! for at afslutte jobbet)"
+
+msgid "E37: No write since last change (add ! to override)"
+msgstr ""
+"E37: Ingen skrivning siden sidste ændring (tilføj ! for at tilsidesætte)"
+
+msgid "E948: Job still running"
+msgstr "E948: Job kører stadig"
+
+msgid "E37: No write since last change"
+msgstr "E37: Ingen skrivning siden sidste ændring"
+
+msgid "W14: Warning: List of file names overflow"
+msgstr "W14: Advarsel: Overløb i liste over filnavne"
+
+#, c-format
+msgid "E92: Buffer %ld not found"
+msgstr "E92: Bufferen %ld blev ikke fundet"
+
+#, c-format
+msgid "E93: More than one match for %s"
+msgstr "E93: Flere end ét match for %s"
+
+#, c-format
+msgid "E94: No matching buffer for %s"
+msgstr "E94: Ingen matchende buffer for %s"
+
+#, c-format
+msgid "line %ld"
+msgstr "linje %ld"
+
+msgid "E95: Buffer with this name already exists"
+msgstr "E95: Buffer med dette navn findes allerede"
+
+msgid " [Modified]"
+msgstr " [Ændret]"
+
+msgid "[Not edited]"
+msgstr "[Ikke redigeret]"
+
+msgid "[New file]"
+msgstr "[Ny fil]"
+
+msgid "[Read errors]"
+msgstr "[Læsefejl]"
+
+msgid "[RO]"
+msgstr "[SB]"
+
+msgid "[readonly]"
+msgstr "[skrivebeskyttet]"
+
+#, c-format
+msgid "1 line --%d%%--"
+msgstr "1 linje --%d%%--"
+
+#, c-format
+msgid "%ld lines --%d%%--"
+msgstr "%ld linjer --%d%%--"
+
+#, c-format
+msgid "line %ld of %ld --%d%%-- col "
+msgstr "linje %ld af %ld --%d%%-- kol "
+
+msgid "[No Name]"
+msgstr "[Intet navn]"
+
+msgid "help"
+msgstr "hjælp"
+
+msgid "[Help]"
+msgstr "[Hjælp]"
+
+msgid "[Preview]"
+msgstr "[Forhåndsvisning]"
+
+msgid "All"
+msgstr "Alt"
+
+msgid "Bot"
+msgstr "Ned"
+
+msgid "Top"
+msgstr "Øve"
+
+msgid ""
+"\n"
+"# Buffer list:\n"
+msgstr ""
+"\n"
+"# Bufferliste:\n"
+
+msgid "E382: Cannot write, 'buftype' option is set"
+msgstr "E382: Kan ikke skrive, 'buftype'-tilvalget er sat"
+
+msgid "[Prompt]"
+msgstr "[Prompt]"
+
+msgid "[Scratch]"
+msgstr "[Kladdeblok]"
+
+msgid ""
+"\n"
+"--- Signs ---"
+msgstr ""
+"\n"
+"--- Signs ---"
+
+#, c-format
+msgid "Signs for %s:"
+msgstr "Signs for %s:"
+
+#, c-format
+msgid " line=%ld id=%d name=%s"
+msgstr " linje=%ld id=%d navn=%s"
+
+msgid "E902: Cannot connect to port"
+msgstr "E902: Kan ikke oprette forbindelse til port"
+
+msgid "E901: gethostbyname() in channel_open()"
+msgstr "E901: gethostbyname() i channel_open()"
+
+msgid "E898: socket() in channel_open()"
+msgstr "E898: socket() i channel_open()"
+
+msgid "E903: received command with non-string argument"
+msgstr "E903: modtog kommando med argument som ikke er en streng"
+
+msgid "E904: last argument for expr/call must be a number"
+msgstr "E904: sidste argument for udtryk/kald skal være et nummer"
+
+msgid "E904: third argument for call must be a list"
+msgstr "E904: tredje argument for kald skal være en liste"
+
+#, c-format
+msgid "E905: received unknown command: %s"
+msgstr "E905: modtog ukendt kommando: %s"
+
+#, c-format
+msgid "E630: %s(): write while not connected"
+msgstr "E630: %s(): skrivning mens der ikke er forbindelse"
+
+#, c-format
+msgid "E631: %s(): write failed"
+msgstr "E631: %s(): skrivning mislykkedes"
+
+#, c-format
+msgid "E917: Cannot use a callback with %s()"
+msgstr "E917: Kan ikke bruge et callback med %s()"
+
+msgid "E912: cannot use ch_evalexpr()/ch_sendexpr() with a raw or nl channel"
+msgstr ""
+"E912: kan ikke bruge ch_evalexpr()/ch_sendexpr() med en rå- eller nl-kanal"
+
+msgid "E906: not an open channel"
+msgstr "E906: ikke en åben kanal"
+
+msgid "E920: _io file requires _name to be set"
+msgstr "E920: _io-fil kræver at _name er sat"
+
+msgid "E915: in_io buffer requires in_buf or in_name to be set"
+msgstr "E915: in_io-buffer kræver at in_buf eller in_name er sat"
+
+#, c-format
+msgid "E918: buffer must be loaded: %s"
+msgstr "E918: buffer skal være indlæst: %s"
+
+msgid "E821: File is encrypted with unknown method"
+msgstr "E821: Filen er krypteret med ukendt metode"
+
+msgid "Warning: Using a weak encryption method; see :help 'cm'"
+msgstr "Advarsel: Bruger en svag krypteringsmetode; se :help 'cm'"
+
+msgid "Enter encryption key: "
+msgstr "Indtast krypteringsnøgle: "
+
+msgid "Enter same key again: "
+msgstr "Indtast samme nøgle igen: "
+
+msgid "Keys don't match!"
+msgstr "Nøglerne er ikke ens!"
+
+msgid "[crypted]"
+msgstr "[crypted]"
+
+#, c-format
+msgid "E720: Missing colon in Dictionary: %s"
+msgstr "E720: Manglende kolon i ordbog: %s"
+
+#, c-format
+msgid "E721: Duplicate key in Dictionary: \"%s\""
+msgstr "E721: Duplikeret nøgle i ordbog: \"%s\""
+
+#, c-format
+msgid "E722: Missing comma in Dictionary: %s"
+msgstr "E722: Manglende komma i ordbog: %s"
+
+#, c-format
+msgid "E723: Missing end of Dictionary '}': %s"
+msgstr "E723: Manglende slutning på ordbog '}': %s"
+
+msgid "extend() argument"
+msgstr "extend()-argument"
+
+#, c-format
+msgid "E737: Key already exists: %s"
+msgstr "E737: Nøgle findes allerede: %s"
+
+#, c-format
+msgid "E96: Cannot diff more than %ld buffers"
+msgstr "E96: Kan ikke diff'e flere end %ld buffere"
+
+msgid "E810: Cannot read or write temp files"
+msgstr "E810: Kan ikke læse eller skrive midlertidige filer"
+
+msgid "E97: Cannot create diffs"
+msgstr "E97: Kan ikke oprette diff'er"
+
+msgid "Patch file"
+msgstr "Patch-fil"
+
+msgid "E816: Cannot read patch output"
+msgstr "E816: Kan ikke læse patch-output"
+
+msgid "E98: Cannot read diff output"
+msgstr "E98: Kan ikke læse diff-output"
+
+msgid "E99: Current buffer is not in diff mode"
+msgstr "E99: Nuværende buffer er ikke i diff-tilstand"
+
+msgid "E793: No other buffer in diff mode is modifiable"
+msgstr "E793: Ingen anden buffer i diff-tilstand kan ændres"
+
+msgid "E100: No other buffer in diff mode"
+msgstr "E100: Ingen anden buffer i diff-tilstand"
+
+msgid "E101: More than two buffers in diff mode, don't know which one to use"
+msgstr ""
+"E101: Mere end to buffere i diff-tilstand, ved ikke hvilke der skal bruges"
+
+#, c-format
+msgid "E102: Can't find buffer \"%s\""
+msgstr "E102: Kan ikke finde bufferen \"%s\""
+
+#, c-format
+msgid "E103: Buffer \"%s\" is not in diff mode"
+msgstr "E103: Bufferen \"%s\" er ikke i diff-tilstand"
+
+msgid "E787: Buffer changed unexpectedly"
+msgstr "E787: Buffer ændret uventet"
+
+msgid "E104: Escape not allowed in digraph"
+msgstr "E104: Escape ikke tilladt i digraf"
+
+msgid "E544: Keymap file not found"
+msgstr "E544: Keymap-fil ikke fundet"
+
+msgid "E105: Using :loadkeymap not in a sourced file"
+msgstr "E105: Bruger :loadkeymap ikke i en sourced fil"
+
+msgid "E791: Empty keymap entry"
+msgstr "E791: Tom keymap-post"
+
+msgid " Keyword completion (^N^P)"
+msgstr " Fuldførelse af nøgleord (^N^P)"
+
+msgid " ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+msgstr " ^X tilstand (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
+
+msgid " Whole line completion (^L^N^P)"
+msgstr " Fuldførelse af hel linje (^L^N^P)"
+
+msgid " File name completion (^F^N^P)"
+msgstr " Fuldførelse af filnavn (^F^N^P)"
+
+msgid " Tag completion (^]^N^P)"
+msgstr " Fuldførelse af tag (^]^N^P)"
+
+msgid " Path pattern completion (^N^P)"
+msgstr " Fuldførelse af sti (^N^P)"
+
+msgid " Definition completion (^D^N^P)"
+msgstr " Fuldførelse af definition (^D^N^P)"
+
+msgid " Dictionary completion (^K^N^P)"
+msgstr " Fuldførelse af ordbog (^K^N^P)"
+
+msgid " Thesaurus completion (^T^N^P)"
+msgstr " Fuldførelse af tesaurus (^T^N^P)"
+
+msgid " Command-line completion (^V^N^P)"
+msgstr " Fuldførelse af kommandolinje (^V^N^P)"
+
+msgid " User defined completion (^U^N^P)"
+msgstr " Fuldførelse af brugerdefineret (^U^N^P)"
+
+msgid " Omni completion (^O^N^P)"
+msgstr " Fuldførelse af omni (^O^N^P)"
+
+msgid " Spelling suggestion (s^N^P)"
+msgstr " Staveforslag (s^N^P)"
+
+msgid " Keyword Local completion (^N^P)"
+msgstr " Fuldførelse af nøgleord local (^N^P)"
+
+msgid "Hit end of paragraph"
+msgstr "Stødte på slutningen af afsnit"
+
+msgid "E839: Completion function changed window"
+msgstr "E839: Fuldførelse-funktion ændrede vindue"
+
+msgid "E840: Completion function deleted text"
+msgstr "E840: Fuldførelse-funktion slettede tekst"
+
+msgid "'dictionary' option is empty"
+msgstr "'dictionary'-tilvalget er tomt"
+
+msgid "'thesaurus' option is empty"
+msgstr "'thesaurus'-tilvalget er tomt"
+
+#, c-format
+msgid "Scanning dictionary: %s"
+msgstr "Skanner ordbog: %s"
+
+msgid " (insert) Scroll (^E/^Y)"
+msgstr " (indsæt) Rul (^E/^Y)"
+
+msgid " (replace) Scroll (^E/^Y)"
+msgstr " (erstat) Rul (^E/^Y)"
+
+#, c-format
+msgid "Scanning: %s"
+msgstr "Skanner: %s"
+
+msgid "Scanning tags."
+msgstr "Skanner tags."
+
+msgid "match in file"
+msgstr "match i fil"
+
+msgid " Adding"
+msgstr " Tilføjer"
+
+msgid "-- Searching..."
+msgstr "-- Søger..."
+
+msgid "Back at original"
+msgstr "Tilbage ved original"
+
+msgid "Word from other line"
+msgstr "Ord fra anden linje"
+
+msgid "The only match"
+msgstr "Det eneste match"
+
+#, c-format
+msgid "match %d of %d"
+msgstr "match %d af %d"
+
+#, c-format
+msgid "match %d"
+msgstr "match %d"
+
+msgid "E18: Unexpected characters in :let"
+msgstr "E18: Uventede tegn i :let"
+
+#, c-format
+msgid "E121: Undefined variable: %s"
+msgstr "E121: Udefineret variabel: %s"
+
+msgid "E111: Missing ']'"
+msgstr "E111: Manglende ']'"
+
+msgid "E719: Cannot use [:] with a Dictionary"
+msgstr "E719: Kan ikke bruge [:] med en ordbog"
+
+#, c-format
+msgid "E734: Wrong variable type for %s="
+msgstr "E734: Forkert variabeltype for %s="
+
+#, c-format
+msgid "E461: Illegal variable name: %s"
+msgstr "E461: Ulovligt variabelnavn: %s"
+
+msgid "E806: using Float as a String"
+msgstr "E806: bruger flydende kommatal som en streng"
+
+msgid "E687: Less targets than List items"
+msgstr "E687: Færre mål end listepunkter"
+
+msgid "E688: More targets than List items"
+msgstr "E688: Flere mål end listepunkter"
+
+msgid "Double ; in list of variables"
+msgstr "Dobbelt ; i liste over variabler"
+
+#, c-format
+msgid "E738: Can't list variables for %s"
+msgstr "E738: Kan ikke opliste variabler for %s"
+
+msgid "E689: Can only index a List or Dictionary"
+msgstr "E689: Kan kun indeksere en liste eller ordbog"
+
+msgid "E708: [:] must come last"
+msgstr "E708: [:] skal være sidst"
+
+msgid "E709: [:] requires a List value"
+msgstr "E709: [:] kræver en listeværdi"
+
+msgid "E710: List value has more items than target"
+msgstr "E710: Listeværdi har flere punkter end mål"
+
+msgid "E711: List value has not enough items"
+msgstr "E711: Listeværdi har ikke nok punkter"
+
+msgid "E690: Missing \"in\" after :for"
+msgstr "E690: Manglende \"in\" efter :for"
+
+#, c-format
+msgid "E108: No such variable: \"%s\""
+msgstr "E108: Ingen sådan variabel: \"%s\""
+
+#, c-format
+msgid "E940: Cannot lock or unlock variable %s"
+msgstr "E940: Kan ikke låse eller låse op for variablen %s"
+
+msgid "E743: variable nested too deep for (un)lock"
+msgstr "E743: variabel indlejret for dybt til at blive låst/låst op"
+
+msgid "E109: Missing ':' after '?'"
+msgstr "E109: Manglende ':' efter '?'"
+
+msgid "E804: Cannot use '%' with Float"
+msgstr "E804: Kan ikke bruge '%' med flydende kommatal"
+
+msgid "E110: Missing ')'"
+msgstr "E110: Manglende ')'"
+
+msgid "E695: Cannot index a Funcref"
+msgstr "E695: Kan ikke indeksere en funcref"
+
+msgid "E909: Cannot index a special variable"
+msgstr "E909: Kan ikke indeksere en speciel variabel"
+
+#, c-format
+msgid "E112: Option name missing: %s"
+msgstr "E112: Tilvalgsnavn mangler: %s"
+
+#, c-format
+msgid "E113: Unknown option: %s"
+msgstr "E113: Ukendt tilvalg: %s"
+
+#, c-format
+msgid "E114: Missing quote: %s"
+msgstr "E114: Manglende citationstegn: %s"
+
+#, c-format
+msgid "E115: Missing quote: %s"
+msgstr "E115: Manglende citationstegn: %s"
+
+msgid "Not enough memory to set references, garbage collection aborted!"
+msgstr "Ikke nok hukommelse til at sætte referencer, affaldsindsamling afbrudt!"
+
+msgid "E724: variable nested too deep for displaying"
+msgstr "E724: variabel indlejret for dybt til at blive vist"
+
+msgid "E805: Using a Float as a Number"
+msgstr "E805: Bruger et flydende kommatal som et nummer"
+
+msgid "E703: Using a Funcref as a Number"
+msgstr "E703: Bruger en funcref som et nummer"
+
+msgid "E745: Using a List as a Number"
+msgstr "E745: Bruger en liste som et nummer"
+
+msgid "E728: Using a Dictionary as a Number"
+msgstr "E728: Bruger en ordbog som et nummer"
+
+msgid "E910: Using a Job as a Number"
+msgstr "E910: Bruger et job som et nummer"
+
+msgid "E913: Using a Channel as a Number"
+msgstr "E913: Bruger en kanal som et nummer"
+
+msgid "E891: Using a Funcref as a Float"
+msgstr "E891: Bruger en funcref som et fyldende kommatal"
+
+msgid "E892: Using a String as a Float"
+msgstr "E892: Bruger en streng som et flydende kommatal"
+
+msgid "E893: Using a List as a Float"
+msgstr "E893: Bruger en liste som et flydende kommatal"
+
+msgid "E894: Using a Dictionary as a Float"
+msgstr "E894: Bruger en ordbog som et flydende kommatal"
+
+msgid "E907: Using a special value as a Float"
+msgstr "E907: Bruger en speciel værdi som et flydende kommatal"
+
+msgid "E911: Using a Job as a Float"
+msgstr "E911: Bruger et job som et flydende kommatal"
+
+msgid "E914: Using a Channel as a Float"
+msgstr "E914: Bruger en kanal som et flydende kommatal"
+
+msgid "E729: using Funcref as a String"
+msgstr "E729: bruger funcref som en streng"
+
+msgid "E730: using List as a String"
+msgstr "E730: bruger liste som en streng"
+
+msgid "E731: using Dictionary as a String"
+msgstr "E731: bruger ordbog som en streng"
+
+msgid "E908: using an invalid value as a String"
+msgstr "E908: bruger en ugyldig værdi som en streng"
+
+#, c-format
+msgid "E795: Cannot delete variable %s"
+msgstr "E795: Kan ikke slette variablen %s"
+
+#, c-format
+msgid "E704: Funcref variable name must start with a capital: %s"
+msgstr "E704: Funcref-variabelnavn skal begynde med et stort bogstav: %s"
+
+#, c-format
+msgid "E705: Variable name conflicts with existing function: %s"
+msgstr "E705: Variabelnavn er i konflikt med eksisterende funktion: %s"
+
+#, c-format
+msgid "E741: Value is locked: %s"
+msgstr "E741: Værdien er låst: %s"
+
+msgid "Unknown"
+msgstr "Ukendt"
+
+#, c-format
+msgid "E742: Cannot change value of %s"
+msgstr "E742: Kan ikke ændre værdien af %s"
+
+msgid "E698: variable nested too deep for making a copy"
+msgstr "E698: variabel indlejret for dybt til at lave en kopi"
+
+msgid ""
+"\n"
+"# global variables:\n"
+msgstr ""
+"\n"
+"# globale variabler:\n"
+
+msgid ""
+"\n"
+"\tLast set from "
+msgstr ""
+"\n"
+"\tSidst sat fra "
+
+msgid "E691: Can only compare List with List"
+msgstr "E691: Kan kun sammenligne liste med liste"
+
+msgid "E692: Invalid operation for List"
+msgstr "E692: Ugyldig handling for liste"
+
+msgid "E735: Can only compare Dictionary with Dictionary"
+msgstr "E735: Kan kun sammenligne ordbog med ordbog"
+
+msgid "E736: Invalid operation for Dictionary"
+msgstr "E736: Ugyldig handling for ordbog"
+
+msgid "E694: Invalid operation for Funcrefs"
+msgstr "E694: Ugyldig handling for funcref'er"
+
+msgid "map() argument"
+msgstr "map()-argument"
+
+msgid "filter() argument"
+msgstr "filter()-argument"
+
+#, c-format
+msgid "E686: Argument of %s must be a List"
+msgstr "E686: Argument af %s skal være en liste"
+
+msgid "E928: String required"
+msgstr "E928: Streng kræves"
+
+msgid "E808: Number or Float required"
+msgstr "E808: Nummer eller flydende kommatal kræves"
+
+msgid "add() argument"
+msgstr "add()-argument"
+
+msgid "E785: complete() can only be used in Insert mode"
+msgstr "E785: complete() kan kun bruges i indsæt-tilstand"
+
+msgid "&Ok"
+msgstr "&Ok"
+
+#, c-format
+msgid "+-%s%3ld line: "
+msgid_plural "+-%s%3ld lines: "
+msgstr[0] "+-%s%3ld linje: "
+msgstr[1] "+-%s%3ld linjer: "
+
+#, c-format
+msgid "E700: Unknown function: %s"
+msgstr "E700: Ukendt funktion: %s"
+
+msgid "E922: expected a dict"
+msgstr "E922: ventede en ordbog"
+
+msgid "E923: Second argument of function() must be a list or a dict"
+msgstr "E923: Andet argument af function() skal være en liste eller en ordbog"
+
+msgid ""
+"&OK\n"
+"&Cancel"
+msgstr ""
+"&OK\n"
+"&Annuller"
+
+msgid "called inputrestore() more often than inputsave()"
+msgstr "kaldte inputrestore() flere gange end inputsave()"
+
+msgid "insert() argument"
+msgstr "insert()-argument"
+
+msgid "E786: Range not allowed"
+msgstr "E786: Område ikke tilladt"
+
+msgid "E916: not a valid job"
+msgstr "E916: ikke et gyldigt job"
+
+msgid "E701: Invalid type for len()"
+msgstr "E701: Ugyldig type for len()"
+
+#, c-format
+msgid "E798: ID is reserved for \":match\": %ld"
+msgstr "E798: ID er reserveret til \":match\": %ld"
+
+msgid "E726: Stride is zero"
+msgstr "E726: Stride er nul"
+
+msgid "E727: Start past end"
+msgstr "E727: Start efter slutningen"
+
+msgid "<empty>"
+msgstr "<tom>"
+
+msgid "E240: No connection to the X server"
+msgstr "E240: Ingen forbindelse til X-serveren"
+
+#, c-format
+msgid "E241: Unable to send to %s"
+msgstr "E241: Kan ikke sende til %s"
+
+msgid "E277: Unable to read a server reply"
+msgstr "E277: Kan ikke læse et serversvar"
+
+msgid "E941: already started a server"
+msgstr "E941: allerede startet en server"
+
+msgid "E942: +clientserver feature not available"
+msgstr "E942: +clientserver-funktionalitet ikke tilgængelig"
+
+msgid "remove() argument"
+msgstr "remove()-argument"
+
+msgid "E655: Too many symbolic links (cycle?)"
+msgstr "E655: For mange symbolske links (cyklus?)"
+
+msgid "reverse() argument"
+msgstr "reverse()-argument"
+
+msgid "E258: Unable to send to client"
+msgstr "E258: Kan ikke sende til klient"
+
+#, c-format
+msgid "E927: Invalid action: '%s'"
+msgstr "E927: Ugyldig handling: '%s'"
+
+msgid "sort() argument"
+msgstr "sort()-argument"
+
+msgid "uniq() argument"
+msgstr "uniq()-argument"
+
+msgid "E702: Sort compare function failed"
+msgstr "E702: Sort-sammenligningsfunktion mislykkedes"
+
+msgid "E882: Uniq compare function failed"
+msgstr "E882: Uniq-sammenligningsfunktion mislykkedes"
+
+msgid "(Invalid)"
+msgstr "(Ugyldig)"
+
+#, c-format
+msgid "E935: invalid submatch number: %d"
+msgstr "E935: ugyldigt undermatch-nummer: %d"
+
+msgid "E677: Error writing temp file"
+msgstr "E677: Fejl ved skrivning af midlertidig fil"
+
+msgid "E921: Invalid callback argument"
+msgstr "E921: Ugyldigt callback-argument"
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Oct %03o, Digr %s"
+msgstr "<%s>%s%s %d, hex %02x, oct %03o, digr %s"
+
+#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
+msgstr "<%s>%s%s %d, hex %02x, octal %03o"
+
+#, c-format
+msgid "> %d, Hex %04x, Oct %o, Digr %s"
+msgstr "> %d, hex %04x, oct %o, digr %s"
+
+#, c-format
+msgid "> %d, Hex %08x, Oct %o, Digr %s"
+msgstr "> %d, hex %08x, oct %o, digr %s"
+
+#, c-format
+msgid "> %d, Hex %04x, Octal %o"
+msgstr "> %d, hex %04x, octal %o"
+
+#, c-format
+msgid "> %d, Hex %08x, Octal %o"
+msgstr "> %d, hex %08x, octal %o"
+
+msgid "E134: Move lines into themselves"
+msgstr "E134: flyt linjer ind i dem selv"
+
+msgid "1 line moved"
+msgstr "1 linje flyttet"
+
+#, c-format
+msgid "%ld lines moved"
+msgstr "%ld linjer flyttet"
+
+#, c-format
+msgid "%ld lines filtered"
+msgstr "%ld linjer filtreret"
+
+msgid "E135: *Filter* Autocommands must not change current buffer"
+msgstr "E135: *Filter*-autokommandoer må ikke ændre nuværende buffer"
+
+msgid "[No write since last change]\n"
+msgstr "[Ingen skrivning siden sidste ændring]\n"
+
+#, c-format
+msgid "%sviminfo: %s in line: "
+msgstr "%sviminfo: %s på linje: "
+
+msgid "E136: viminfo: Too many errors, skipping rest of file"
+msgstr "E136: viminfo: For mange fejl, springer resten af filen over"
+
+#, c-format
+msgid "Reading viminfo file \"%s\"%s%s%s"
+msgstr "Læser viminfo-filen \"%s\"%s%s%s"
+
+msgid " info"
+msgstr " info"
+
+msgid " marks"
+msgstr " mærker"
+
+msgid " oldfiles"
+msgstr " gamle filer"
+
+msgid " FAILED"
+msgstr " MISLYKKEDES"
+
+#, c-format
+msgid "E137: Viminfo file is not writable: %s"
+msgstr "E137: Viminfo-filen er skrivebeskyttet: %s"
+
+#, c-format
+msgid "E929: Too many viminfo temp files, like %s!"
+msgstr "E929: For mange midlertidige filer for viminfo, såsom %s!"
+
+#, c-format
+msgid "E138: Can't write viminfo file %s!"
+msgstr "E138: Kan ikke skrive viminfo-filen %s!"
+
+#, c-format
+msgid "Writing viminfo file \"%s\""
+msgstr "Skriver viminfo-filen \"%s\""
+
+#, c-format
+msgid "E886: Can't rename viminfo file to %s!"
+msgstr "E886: Kan ikke omdøbe viminfo-fil til %s!"
+
+#, c-format
+msgid "# This viminfo file was generated by Vim %s.\n"
+msgstr "# Denne viminfo-fil blev genereret af Vim %s.\n"
+
+msgid ""
+"# You may edit it if you're careful!\n"
+"\n"
+msgstr ""
+"# Du kan redigere den, hvis du er forsigtig!\n"
+"\n"
+
+msgid "# Value of 'encoding' when this file was written\n"
+msgstr "# Værdien af 'encoding' da filen blev skrevet\n"
+
+msgid "Illegal starting char"
+msgstr "Ulovligt tegn i begyndelsen"
+
+msgid ""
+"\n"
+"# Bar lines, copied verbatim:\n"
+msgstr ""
+"\n"
+"#-bjælkelinjer, kopieret ordret:\n"
+
+msgid "Save As"
+msgstr "Gem som"
+
+msgid "Write partial file?"
+msgstr "Skriv ufuldstændig fil?"
+
+msgid "E140: Use ! to write partial buffer"
+msgstr "E140: Brug ! til at skrive ufuldstændig buffer"
+
+#, c-format
+msgid "Overwrite existing file \"%s\"?"
+msgstr "Overskriv eksisterende fil \"%s\"?"
+
+#, c-format
+msgid "Swap file \"%s\" exists, overwrite anyway?"
+msgstr "Swap-filen \"%s\" findes, overskriv alligevel?"
+
+#, c-format
+msgid "E768: Swap file exists: %s (:silent! overrides)"
+msgstr "E768: Swap-filen findes: %s (:silent! tilsidesætter)"
+
+#, c-format
+msgid "E141: No file name for buffer %ld"
+msgstr "E141: Intet filnavn for buffer %ld"
+
+msgid "E142: File not written: Writing is disabled by 'write' option"
+msgstr "E142: Fil ikke skrevet: Skrivning er deaktiveret af 'write'-tilvalget"
+
+#, c-format
+msgid ""
+"'readonly' option is set for \"%s\".\n"
+"Do you wish to write anyway?"
+msgstr ""
+"'readonly'-tilvalget er sat for \"%s\".\n"
+"Vil du skrive alligevel?"
+
+#, c-format
+msgid ""
+"File permissions of \"%s\" are read-only.\n"
+"It may still be possible to write it.\n"
+"Do you wish to try?"
+msgstr ""
+"Filtilladelserne for \"%s\" er skrivebeskyttede.\n"
+"Der kan stadig være mulighed for at skrive den.\n"
+"Vil du prøve?"
+
+#, c-format
+msgid "E505: \"%s\" is read-only (add ! to override)"
+msgstr "E505: \"%s\" er skrivebeskyttet (tilføj ! for at tilsidesætte)"
+
+msgid "Edit File"
+msgstr "Rediger fil"
+
+#, c-format
+msgid "E143: Autocommands unexpectedly deleted new buffer %s"
+msgstr "E143: Autokommandoer slettede uventede ny buffer %s"
+
+msgid "E144: non-numeric argument to :z"
+msgstr "E144: ikke-numerisk argument til :z"
+
+msgid "E145: Shell commands not allowed in rvim"
+msgstr "E145: Skalkommandoer er ikke tilladt i rvim"
+
+msgid "E146: Regular expressions can't be delimited by letters"
+msgstr "E146: Regulære udtryk kan ikke afgrænses af bogstaver"
+
+#, c-format
+msgid "replace with %s (y/n/a/q/l/^E/^Y)?"
+msgstr "erstat med %s (y/n/a/q/l/^E/^Y)?"
+
+msgid "(Interrupted) "
+msgstr "(Afbrudt) "
+
+msgid "1 match"
+msgstr "1 match"
+
+msgid "1 substitution"
+msgstr "1 erstatning"
+
+#, c-format
+msgid "%ld matches"
+msgstr "%ld match"
+
+#, c-format
+msgid "%ld substitutions"
+msgstr "%ld erstatninger"
+
+msgid " on 1 line"
+msgstr " på 1 linje"
+
+#, c-format
+msgid " on %ld lines"
+msgstr " på %ld linjer"
+
+msgid "E147: Cannot do :global recursive with a range"
+msgstr "E147: Kan ikke foretage :global rekursivt med et område"
+
+msgid "E148: Regular expression missing from global"
+msgstr "E148: Regulære udtryk mangler fra global"
+
+#, c-format
+msgid "Pattern found in every line: %s"
+msgstr "Mønster fundet på hver linje: %s"
+
+#, c-format
+msgid "Pattern not found: %s"
+msgstr "Mønster ikke fundet: %s"
+
+msgid ""
+"\n"
+"# Last Substitute String:\n"
+"$"
+msgstr ""
+"\n"
+"# Sidste erstatningsstreng:\n"
+"$"
+
+msgid "E478: Don't panic!"
+msgstr "E478: Tag det bare helt roligt!"
+
+#, c-format
+msgid "E661: Sorry, no '%s' help for %s"
+msgstr "E661: Beklager, ingen '%s' hjælp til %s"
+
+#, c-format
+msgid "E149: Sorry, no help for %s"
+msgstr "E149: Beklager, ingen hjælp til %s"
+
+#, c-format
+msgid "Sorry, help file \"%s\" not found"
+msgstr "Beklager, hjælpfilen \"%s\" ikke fundet"
+
+#, c-format
+msgid "E151: No match: %s"
+msgstr "E151: Intet match: %s"
+
+#, c-format
+msgid "E152: Cannot open %s for writing"
+msgstr "E152: Kan ikke åbne %s til skrivning"
+
+#, c-format
+msgid "E153: Unable to open %s for reading"
+msgstr "E153: Kan ikke åbne %s til læsning"
+
+#, c-format
+msgid "E670: Mix of help file encodings within a language: %s"
+msgstr "E670: Blanding af kodninger for hjælpfiler i samme sprog: %s"
+
+#, c-format
+msgid "E154: Duplicate tag \"%s\" in file %s/%s"
+msgstr "E154: Duplikeret tag \"%s\" i fil %s/%s"
+
+#, c-format
+msgid "E150: Not a directory: %s"
+msgstr "E150: Ikke en mappe: %s"
+
+#, c-format
+msgid "E160: Unknown sign command: %s"
+msgstr "E160: Ukendt sign-kommando: %s"
+
+msgid "E156: Missing sign name"
+msgstr "E156: Manglende sign-navn"
+
+msgid "E612: Too many signs defined"
+msgstr "E612: For mange signs defineret"
+
+#, c-format
+msgid "E239: Invalid sign text: %s"
+msgstr "E239: Ugyldig sign-tekst: %s"
+
+#, c-format
+msgid "E155: Unknown sign: %s"
+msgstr "E155: Ukendt sign: %s"
+
+msgid "E159: Missing sign number"
+msgstr "E159: Manglende sign-nummer"
+
+#, c-format
+msgid "E158: Invalid buffer name: %s"
+msgstr "E158: Ugyldigt buffernavn: %s"
+
+msgid "E934: Cannot jump to a buffer that does not have a name"
+msgstr "E934: Kan ikke hoppe til en buffer som ikke har et navn"
+
+#, c-format
+msgid "E157: Invalid sign ID: %ld"
+msgstr "E157: Ugyldigt sign-ID: %ld"
+
+#, c-format
+msgid "E885: Not possible to change sign %s"
+msgstr "E885: Det er ikke muligt at ændre sign %s"
+
+msgid " (NOT FOUND)"
+msgstr " (IKKE FUNDET)"
+
+msgid " (not supported)"
+msgstr " (understøttes ikke)"
+
+msgid "[Deleted]"
+msgstr "[Slettet]"
+
+msgid "No old files"
+msgstr "Ingen gamle filer"
+
+msgid "Entering Debug mode. Type \"cont\" to continue."
+msgstr "Går i fejlretningstilstand. Skriv \"cont\" for at fortsætte."
+
+#, c-format
+msgid "Oldval = \"%s\""
+msgstr "Oldval = \"%s\""
+
+#, c-format
+msgid "Newval = \"%s\""
+msgstr "Newval = \"%s\""
+
+#, c-format
+msgid "line %ld: %s"
+msgstr "linje %ld: %s"
+
+#, c-format
+msgid "cmd: %s"
+msgstr "cmd: %s"
+
+msgid "frame is zero"
+msgstr "ramme er nul"
+
+#, c-format
+msgid "frame at highest level: %d"
+msgstr "ramme på højeste niveau: %d"
+
+#, c-format
+msgid "Breakpoint in \"%s%s\" line %ld"
+msgstr "Breakpoint i \"%s%s\" linje %ld"
+
+#, c-format
+msgid "E161: Breakpoint not found: %s"
+msgstr "E161: Breakpoint ikke fundet: %s"
+
+msgid "No breakpoints defined"
+msgstr "Ingen breakpoints defineret"
+
+#, c-format
+msgid "%3d %s %s line %ld"
+msgstr "%3d %s %s linje %ld"
+
+#, c-format
+msgid "%3d expr %s"
+msgstr "%3d udtryk %s"
+
+msgid "E750: First use \":profile start {fname}\""
+msgstr "E750: Brug først \":profile start {fname}\""
+
+#, c-format
+msgid "Save changes to \"%s\"?"
+msgstr "Gem ændringer til \"%s\"?"
+
+#, c-format
+msgid "E947: Job still running in buffer \"%s\""
+msgstr "E947: Job kører stadig i bufferen \"%s\""
+
+#, c-format
+msgid "E162: No write since last change for buffer \"%s\""
+msgstr "E162: Ingen skrivning siden sidste ændring for bufferen \"%s\""
+
+msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
+msgstr "Advarsel: Indtastede anden buffer uventede (tjek autokommandoer)"
+
+msgid "E163: There is only one file to edit"
+msgstr "E163: Der er kun én fil at redigere"
+
+msgid "E164: Cannot go before first file"
+msgstr "E164: Kan ikke gå før første fil"
+
+msgid "E165: Cannot go beyond last file"
+msgstr "E165: Kan ikke gå over sidste fil"
+
+#, c-format
+msgid "E666: compiler not supported: %s"
+msgstr "E666: kompiler understøttes ikke: %s"
+
+#, c-format
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "Søger efter \"%s\" i \"%s\""
+
+#, c-format
+msgid "Searching for \"%s\""
+msgstr "Søger efter \"%s\""
+
+#, c-format
+msgid "not found in '%s': \"%s\""
+msgstr "ikke fundet i '%s': \"%s\""
+
+#, c-format
+msgid "W20: Required python version 2.x not supported, ignoring file: %s"
+msgstr "W20: Krævede python-version 2.x understøttes ikke, ignorerer fil: %s"
+
+#, c-format
+msgid "W21: Required python version 3.x not supported, ignoring file: %s"
+msgstr "W21: Krævede python-version 3.x understøttes ikke, ignorerer fil: %s"
+
+msgid "Source Vim script"
+msgstr "Source Vim-script"
+
+#, c-format
+msgid "Cannot source a directory: \"%s\""
+msgstr "Kan ikke source en mappe: \"%s\""
+
+#, c-format
+msgid "could not source \"%s\""
+msgstr "kunne ikke source \"%s\""
+
+#, c-format
+msgid "line %ld: could not source \"%s\""
+msgstr "linje %ld: kunne ikke source \"%s\""
+
+#, c-format
+msgid "sourcing \"%s\""
+msgstr "sourcing \"%s\""
+
+#, c-format
+msgid "line %ld: sourcing \"%s\""
+msgstr "linje %ld: sourcing \"%s\""
+
+#, c-format
+msgid "finished sourcing %s"
+msgstr "færdig med sourcing af %s"
+
+#, c-format
+msgid "continuing in %s"
+msgstr "fortsætter i %s"
+
+msgid "modeline"
+msgstr "tilstandslinje"
+
+msgid "--cmd argument"
+msgstr "--cmd-argument"
+
+msgid "-c argument"
+msgstr "-c-argument"
+
+msgid "environment variable"
+msgstr "miljøvariabel"
+
+msgid "error handler"
+msgstr "fejlhåndtering"
+
+msgid "W15: Warning: Wrong line separator, ^M may be missing"
+msgstr "W15: Advarsel: Forkert linjeseparator, ^M mangler muligvis"
+
+msgid "E167: :scriptencoding used outside of a sourced file"
+msgstr "E167: :scriptencoding brugt udenfor en sourced fil"
+
+msgid "E168: :finish used outside of a sourced file"
+msgstr "E168: :finish udenfor en sourced fil"
+
+#, c-format
+msgid "Current %slanguage: \"%s\""
+msgstr "Nuværende %ssprog: \"%s\""
+
+#, c-format
+msgid "E197: Cannot set language to \"%s\""
+msgstr "E197: Kan ikke sætte sprog til \"%s\""
+
+msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
+msgstr "Går i Ex-tilstand. Skriv \"visual\" for at gå til normal tilstand."
+
+msgid "E501: At end-of-file"
+msgstr "E501: Ved filens slutning"
+
+msgid "E169: Command too recursive"
+msgstr "E169: Kommando for rekursiv"
+
+#, c-format
+msgid "E605: Exception not caught: %s"
+msgstr "E605: Undtagelse ikke fanget: %s"
+
+msgid "End of sourced file"
+msgstr "Slut på sourced fil"
+
+msgid "End of function"
+msgstr "Slutning af funktion"
+
+msgid "E464: Ambiguous use of user-defined command"
+msgstr "E464: Flertydig brug af brugerdefineret kommando"
+
+msgid "E492: Not an editor command"
+msgstr "E492: Ikke en editor-kommando"
+
+msgid "E493: Backwards range given"
+msgstr "E493: Baglæns område givet"
+
+msgid "Backwards range given, OK to swap"
+msgstr "Baglæns område givet, OK at bytte om"
+
+msgid "E494: Use w or w>>"
+msgstr "E494: Brug w eller w>>"
+
+msgid "E943: Command table needs to be updated, run 'make cmdidxs'"
+msgstr "E943: Kommandotabel skal opdateres, kør 'make cmdidxs'"
+
+msgid "E319: Sorry, the command is not available in this version"
+msgstr "E319: Beklager, kommandoen er ikke tilgængelig i denne version"
+
+msgid "1 more file to edit. Quit anyway?"
+msgstr "1 fil mere at redigere. Afslut alligevel?"
+
+#, c-format
+msgid "%d more files to edit. Quit anyway?"
+msgstr "%d filer mere at redigere. Afslut alligevel?"
+
+msgid "E173: 1 more file to edit"
+msgstr "E173: 1 fil mere at redigere"
+
+#, c-format
+msgid "E173: %ld more files to edit"
+msgstr "E173: %ld filer mere at redigere"
+
+msgid "E174: Command already exists: add ! to replace it"
+msgstr "E174: Kommandoen findes allerede: tilføj ! for at erstatte den"
+
+msgid ""
+"\n"
+" Name Args Address Complete Definition"
+msgstr ""
+"\n"
+" Navn Argumenter Adresse Fuldført Definition"
+
+msgid "No user-defined commands found"
+msgstr "Fandt ingen brugerdefinerede kommandoer"
+
+msgid "E175: No attribute specified"
+msgstr "E175: Ingen attribut angivet"
+
+msgid "E176: Invalid number of arguments"
+msgstr "E176: Ugyldigt antal argumenter"
+
+msgid "E177: Count cannot be specified twice"
+msgstr "E177: Tælling må ikke angives to gange"
+
+msgid "E178: Invalid default value for count"
+msgstr "E178: Ugyldig standardværdi for tælling"
+
+msgid "E179: argument required for -complete"
+msgstr "E179: argument kræves til -complete"
+
+msgid "E179: argument required for -addr"
+msgstr "E179: argument kræves til -addr"
+
+#, c-format
+msgid "E181: Invalid attribute: %s"
+msgstr "E181: Ugyldig attribut: %s"
+
+msgid "E182: Invalid command name"
+msgstr "E182: Ugyldigt kommandonavn"
+
+msgid "E183: User defined commands must start with an uppercase letter"
+msgstr "E183: Brugerdefinerede kommandoer skal begynde med et stort bogstav"
+
+msgid "E841: Reserved name, cannot be used for user defined command"
+msgstr "E841: Reserveret navn, kan ikke bruges til brugerdefineret kommando"
+
+#, c-format
+msgid "E184: No such user-defined command: %s"
+msgstr "E184: Ingen sådan brugerdefineret kommando: %s"
+
+#, c-format
+msgid "E180: Invalid address type value: %s"
+msgstr "E180: Ugyldig værdi for adressetype: %s"
+
+#, c-format
+msgid "E180: Invalid complete value: %s"
+msgstr "E180: Ugyldig complete-værdi: %s"
+
+msgid "E468: Completion argument only allowed for custom completion"
+msgstr "E468: Fuldførelse-argument kun tilladt for tilpasset fuldførelse"
+
+msgid "E467: Custom completion requires a function argument"
+msgstr "E467: Tilpasset fuldførelse kræver et funktion-argument"
+
+msgid "unknown"
+msgstr "ukendt"
+
+#, c-format
+msgid "E185: Cannot find color scheme '%s'"
+msgstr "E185: Kan ikke finde farveskemaet '%s'"
+
+msgid "Greetings, Vim user!"
+msgstr "Hejsa, Vim-bruger!"
+
+msgid "E784: Cannot close last tab page"
+msgstr "E784: Kan ikke lukke sidste fanebladsside"
+
+msgid "Already only one tab page"
+msgstr "Allerede kun én fanebladsside"
+
+msgid "Edit File in new window"
+msgstr "Rediger fil i nyt vindue"
+
+#, c-format
+msgid "Tab page %d"
+msgstr "Fanebladsside %d"
+
+msgid "No swap file"
+msgstr "Ingen swap-fil"
+
+msgid "Append File"
+msgstr "Tilføj fil til slutningen"
+
+msgid "E747: Cannot change directory, buffer is modified (add ! to override)"
+msgstr ""
+"E747: Kan ikke skifte mappe, buffer er ændret (tilføj ! for at tilsidesætte)"
+
+msgid "E186: No previous directory"
+msgstr "E186: Ingen tidligere ordbog"
+
+msgid "E187: Unknown"
+msgstr "E187: Ukendt"
+
+msgid "E465: :winsize requires two number arguments"
+msgstr "E465: :winsize kræver to nummer-argumenter"
+
+#, c-format
+msgid "Window position: X %d, Y %d"
+msgstr "Vinduesplacering: X %d, Y %d"
+
+msgid "E188: Obtaining window position not implemented for this platform"
+msgstr ""
+"E188: Indhentelse af vinduesplacering ikke implementeret på denne platform"
+
+msgid "E466: :winpos requires two number arguments"
+msgstr "E466: :winpos kræver to nummer-argumenter"
+
+msgid "E930: Cannot use :redir inside execute()"
+msgstr "E930: Kan ikke bruge :redir i execute()"
+
+msgid "Save Redirection"
+msgstr "Gem omdirigering"
+
+msgid "Save View"
+msgstr "Gem visning"
+
+msgid "Save Session"
+msgstr "Gem session"
+
+msgid "Save Setup"
+msgstr "Gem opsætning"
+
+#, c-format
+msgid "E739: Cannot create directory: %s"
+msgstr "E739: Kan ikke oprette mappe: %s"
+
+#, c-format
+msgid "E189: \"%s\" exists (add ! to override)"
+msgstr "E189: \"%s\" findes (tilføj ! for at tilsidesætte)"
+
+#, c-format
+msgid "E190: Cannot open \"%s\" for writing"
+msgstr "E190: Kan ikke åbne \"%s\" til skrivning"
+
+msgid "E191: Argument must be a letter or forward/backward quote"
+msgstr ""
+"E191: Argument skal være et bogstav eller retvendt/omvendt citationstegn"
+
+msgid "E192: Recursive use of :normal too deep"
+msgstr "E192: Rekursiv brug af :normal for dyb"
+
+msgid "E809: #< is not available without the +eval feature"
+msgstr "E809: #< er ikke tilgængelig uden +eval-funktionaliteten"
+
+msgid "E194: No alternate file name to substitute for '#'"
+msgstr "E194: Intet alternate-filnavn til erstatning for '#'"
+
+msgid "E495: no autocommand file name to substitute for \"<afile>\""
+msgstr "E495: intet autokommando-filnavn til erstatning for \"<afile>\""
+
+msgid "E496: no autocommand buffer number to substitute for \"<abuf>\""
+msgstr "E496: intet autokommando-buffernummer til erstatning for \"<abuf>\""
+
+msgid "E497: no autocommand match name to substitute for \"<amatch>\""
+msgstr "E497: intet autokommando-matchnavn til erstatning for \"<amatch>\""
+
+msgid "E498: no :source file name to substitute for \"<sfile>\""
+msgstr "E498: intet :source-filnavn til erstatning for \"<sfile>\""
+
+msgid "E842: no line number to use for \"<slnum>\""
+msgstr "E842: intet linjenummer til brug for \"<slnum>\""
+
+#, no-c-format
+msgid "E499: Empty file name for '%' or '#', only works with \":p:h\""
+msgstr "E499: Tomt filnavn for '%' eller '#', virker kun med \":p:h\""
+
+msgid "E500: Evaluates to an empty string"
+msgstr "E500: Evaluerer til en tom streng"
+
+msgid "E195: Cannot open viminfo file for reading"
+msgstr "E195: Kan ikke åbne viminfo-fil til læsning"
+
+msgid "Untitled"
+msgstr "Unavngivet"
+
+msgid "E196: No digraphs in this version"
+msgstr "E196: Ingen digraffer i denne version"
+
+msgid "E608: Cannot :throw exceptions with 'Vim' prefix"
+msgstr "E608: Kan ikke :throw-undtagelser med 'Vim'-præfiks"
+
+#, c-format
+msgid "Exception thrown: %s"
+msgstr "Undtagelse kastet: %s"
+
+#, c-format
+msgid "Exception finished: %s"
+msgstr "Undtagelse færdig: %s"
+
+#, c-format
+msgid "Exception discarded: %s"
+msgstr "Undtagelse forkastet: %s"
+
+#, c-format
+msgid "%s, line %ld"
+msgstr "%s, linje %ld"
+
+#, c-format
+msgid "Exception caught: %s"
+msgstr "Undtagelse fanget: %s"
+
+#, c-format
+msgid "%s made pending"
+msgstr "%s gjort afventende"
+
+#, c-format
+msgid "%s resumed"
+msgstr "%s genoptaget"
+
+#, c-format
+msgid "%s discarded"
+msgstr "%s forkastet"
+
+msgid "Exception"
+msgstr "Undtagelse"
+
+msgid "Error and interrupt"
+msgstr "Fejl og afbryd"
+
+msgid "Error"
+msgstr "Fejl"
+
+msgid "Interrupt"
+msgstr "Afbryd"
+
+msgid "E579: :if nesting too deep"
+msgstr "E579: :if-indlejring for dyb"
+
+msgid "E580: :endif without :if"
+msgstr "E580: :endif uden :if"
+
+msgid "E581: :else without :if"
+msgstr "E581: :else uden :if"
+
+msgid "E582: :elseif without :if"
+msgstr "E582: :elseif uden :if"
+
+msgid "E583: multiple :else"
+msgstr "E583: flere :else"
+
+msgid "E584: :elseif after :else"
+msgstr "E584: :elseif efter :else"
+
+msgid "E585: :while/:for nesting too deep"
+msgstr "E585: :while/:for-indlejring for dyb"
+
+msgid "E586: :continue without :while or :for"
+msgstr "E586: :continue uden :while eller :for"
+
+msgid "E587: :break without :while or :for"
+msgstr "E587: :break uden :while eller :for"
+
+msgid "E732: Using :endfor with :while"
+msgstr "E732: Bruger :endfor med :while"
+
+msgid "E733: Using :endwhile with :for"
+msgstr "E733: Bruger :endwhile med :for"
+
+msgid "E601: :try nesting too deep"
+msgstr "E601: :try-indlejring for dyb"
+
+msgid "E603: :catch without :try"
+msgstr "E603: :catch uden :try"
+
+msgid "E604: :catch after :finally"
+msgstr "E604: :catch efter :finally"
+
+msgid "E606: :finally without :try"
+msgstr "E606: :finally uden :try"
+
+msgid "E607: multiple :finally"
+msgstr "E607: flere :finally"
+
+msgid "E602: :endtry without :try"
+msgstr "E602: :endtry uden :try"
+
+msgid "E193: :endfunction not inside a function"
+msgstr "E193: :endfunction ikke i en funktion"
+
+msgid "E788: Not allowed to edit another buffer now"
+msgstr "E788: Ikke tilladt at redigere anden buffer nu"
+
+msgid "E811: Not allowed to change buffer information now"
+msgstr "E811: Ikke tilladt at ændre bufferinformation nu"
+
+msgid "tagname"
+msgstr "tagnavn"
+
+msgid " kind file\n"
+msgstr " kind-fil\n"
+
+msgid "'history' option is zero"
+msgstr "'history'-tilvalget er nul"
+
+#, c-format
+msgid ""
+"\n"
+"# %s History (newest to oldest):\n"
+msgstr ""
+"\n"
+"# %s Historik (nyeste til ældste):\n"
+
+msgid "Command Line"
+msgstr "Kommandolinje"
+
+msgid "Search String"
+msgstr "Søgestreng"
+
+msgid "Expression"
+msgstr "Udtryk"
+
+msgid "Input Line"
+msgstr "Inputlinje"
+
+msgid "Debug Line"
+msgstr "Fejlretningslinje"
+
+msgid "E198: cmd_pchar beyond the command length"
+msgstr "E198: cmd_pchar efter kommandolængden"
+
+msgid "E199: Active window or buffer deleted"
+msgstr "E199: Aktivt vindue eller buffer slettet"
+
+msgid "E812: Autocommands changed buffer or buffer name"
+msgstr "E812: Autokommandoer ændrede buffer eller buffernavn"
+
+msgid "Illegal file name"
+msgstr "Ulovlig filnavn"
+
+msgid "is a directory"
+msgstr "er en mappe"
+
+msgid "is not a file"
+msgstr "er ikke en fil"
+
+msgid "is a device (disabled with 'opendevice' option)"
+msgstr "er en enhed (deaktiveret med 'opendevice'-tilvalget)"
+
+msgid "[New File]"
+msgstr "[Ny fil]"
+
+msgid "[New DIRECTORY]"
+msgstr "[Ny MAPPE]"
+
+msgid "[File too big]"
+msgstr "[Filen er for stor]"
+
+msgid "[Permission Denied]"
+msgstr "[Tilladelse nægtet]"
+
+msgid "E200: *ReadPre autocommands made the file unreadable"
+msgstr "E200: *ReadPre-autokommandoer gjorde filen ulæselig"
+
+msgid "E201: *ReadPre autocommands must not change current buffer"
+msgstr "E201: *ReadPre-autokommandoer må ikke ændre nuværende buffer"
+
+msgid "Vim: Reading from stdin...\n"
+msgstr "Vim: Læser fra stdin...\n"
+
+msgid "Reading from stdin..."
+msgstr "Læser fra stdin..."
+
+msgid "E202: Conversion made file unreadable!"
+msgstr "E202: Konvertering gjorde filen ulæselig!"
+
+msgid "[fifo/socket]"
+msgstr "[fifo/sokkel]"
+
+msgid "[fifo]"
+msgstr "[fifo]"
+
+msgid "[socket]"
+msgstr "[sokkel]"
+
+msgid "[character special]"
+msgstr "[character special]"
+
+msgid "[CR missing]"
+msgstr "[CR mangler]"
+
+msgid "[long lines split]"
+msgstr "[opdeling af lange linjer]"
+
+msgid "[NOT converted]"
+msgstr "[IKKE konverteret]"
+
+msgid "[converted]"
+msgstr "[konverteret]"
+
+#, c-format
+msgid "[CONVERSION ERROR in line %ld]"
+msgstr "[KONVERTERINGSFEJL på linje %ld]"
+
+#, c-format
+msgid "[ILLEGAL BYTE in line %ld]"
+msgstr "[ULOVLIG BYTE på linje %ld]"
+
+msgid "[READ ERRORS]"
+msgstr "[LÆSEFEJL]"
+
+msgid "Can't find temp file for conversion"
+msgstr "Kan ikke finde midlertidig fil til konvertering"
+
+msgid "Conversion with 'charconvert' failed"
+msgstr "Konvertering med 'charconvert' mislykkedes"
+
+msgid "can't read output of 'charconvert'"
+msgstr "kan ikke læse output af 'charconvert'"
+
+msgid "E676: No matching autocommands for acwrite buffer"
+msgstr "E676: Ingen matchende autokommandoer for acwrite-buffer"
+
+msgid "E203: Autocommands deleted or unloaded buffer to be written"
+msgstr "E203: Autokommandoer slettet eller udlæste buffer som skal skrives"
+
+msgid "E204: Autocommand changed number of lines in unexpected way"
+msgstr "E204: Autokommando ændrede antal linjer på en uventede måde"
+
+msgid "NetBeans disallows writes of unmodified buffers"
+msgstr "NetBeans tillader ikke skrivninger af uændrede buffere"
+
+msgid "Partial writes disallowed for NetBeans buffers"
+msgstr "Ufuldstændige skrivninger er ikke tilladt for NetBeans-buffere"
+
+msgid "is not a file or writable device"
+msgstr "er ikke en fil eller enhed som der kan skrives til"
+
+msgid "writing to device disabled with 'opendevice' option"
+msgstr "skrivning til enhed er deaktiveret med 'opendevice'-tilvalget"
+
+msgid "is read-only (add ! to override)"
+msgstr "er skrivebeskyttet (tilføj ! for at tilsidesætte)"
+
+msgid "E506: Can't write to backup file (add ! to override)"
+msgstr ""
+"E506: Kan ikke skrive til sikkerhedskopieret fil (tilføj ! for at "
+"tilsidesætte)"
+
+msgid "E507: Close error for backup file (add ! to override)"
+msgstr ""
+"E507: Fejl ved lukning af sikkerhedskopieret fil (tilføj ! for at "
+"tilsidesætte)"
+
+msgid "E508: Can't read file for backup (add ! to override)"
+msgstr ""
+"E508: Kan ikke læse fil til sikkerhedskopiering (tilføj ! for at "
+"tilsidesætte)"
+
+msgid "E509: Cannot create backup file (add ! to override)"
+msgstr ""
+"E509: Kan ikke oprette (create) sikkerhedskopieret fil (tilføj ! for at "
+"tilsidesætte)"
+
+msgid "E510: Can't make backup file (add ! to override)"
+msgstr ""
+"E510: Kan ikke oprette (make) sikkerhedskopieret fil (tilføj ! for at "
+"tilsidesætte)"
+
+msgid "E214: Can't find temp file for writing"
+msgstr "E214: Kan ikke finde midlertidig fil til skrivning"
+
+msgid "E213: Cannot convert (add ! to write without conversion)"
+msgstr "E213: Kan ikke konvertere (tilføj ! for at skrive uden konvertering)"
+
+msgid "E166: Can't open linked file for writing"
+msgstr "E166: Kan ikke åbne linket fil til skrivning"
+
+msgid "E212: Can't open file for writing"
+msgstr "E212: Kan ikke åbne filen til skrivning"
+
+msgid "E949: File changed while writing"
+msgstr "E949: Filen blev ændret ved skrivning"
+
+msgid "E512: Close failed"
+msgstr "E512: Lukning mislykkedes"
+
+msgid "E513: write error, conversion failed (make 'fenc' empty to override)"
+msgstr ""
+"E513: fejl ved skrivning, konvertering mislykkedes (gør 'fenc' tom for at "
+"tilsidesætte)"
+
+#, c-format
+msgid ""
+"E513: write error, conversion failed in line %ld (make 'fenc' empty to "
+"override)"
+msgstr ""
+"E513: fejl ved skrivning, konvertering mislykkedes på linje %ld (gør 'fenc' "
+"tom for at tilsidesætte)"
+
+msgid "E514: write error (file system full?)"
+msgstr "E514: skrivefejl (er filsystemet fuldt?)"
+
+msgid " CONVERSION ERROR"
+msgstr " KONVERTERINGSFEJL"
+
+#, c-format
+msgid " in line %ld;"
+msgstr " på linje %ld;"
+
+msgid "[Device]"
+msgstr "[Enhed]"
+
+msgid "[New]"
+msgstr "[Ny]"
+
+msgid " [a]"
+msgstr " [a]"
+
+msgid " appended"
+msgstr " tilføjet i slutningen"
+
+msgid " [w]"
+msgstr " [s]"
+
+msgid " written"
+msgstr " skrevet"
+
+msgid "E205: Patchmode: can't save original file"
+msgstr "E205: Patchmode: kan ikke gemme original fil"
+
+msgid "E206: patchmode: can't touch empty original file"
+msgstr "E206: patchmode: kan ikke touch tom original fil"
+
+msgid "E207: Can't delete backup file"
+msgstr "E207: Kan ikke slette sikkerhedskopieret fil"
+
+msgid ""
+"\n"
+"WARNING: Original file may be lost or damaged\n"
+msgstr ""
+"\n"
+"ADVARSEL: Den originale fil kan man mistet eller beskadiget\n"
+
+msgid "don't quit the editor until the file is successfully written!"
+msgstr "afslut ikke editoren inden filen er blevet skrevet!"
+
+msgid "[dos]"
+msgstr "[dos]"
+
+msgid "[dos format]"
+msgstr "[dos-format]"
+
+msgid "[mac]"
+msgstr "[mac]"
+
+msgid "[mac format]"
+msgstr "[mac-format]"
+
+msgid "[unix]"
+msgstr "[unix]"
+
+msgid "[unix format]"
+msgstr "[unix-format]"
+
+msgid "1 line, "
+msgstr "1 linje, "
+
+#, c-format
+msgid "%ld lines, "
+msgstr "%ld linjer, "
+
+msgid "1 character"
+msgstr "1 tegn"
+
+#, c-format
+msgid "%lld characters"
+msgstr "%lld tegn"
+
+msgid "[noeol]"
+msgstr "[ingen eol]"
+
+msgid "[Incomplete last line]"
+msgstr "[Ufuldstændig sidste linje]"
+
+msgid "WARNING: The file has been changed since reading it!!!"
+msgstr "ADVARSEL: Filen er blevet ændret siden den blev læst!!!"
+
+msgid "Do you really want to write to it"
+msgstr "Vil du virkelig skrive den"
+
+#, c-format
+msgid "E208: Error writing to \"%s\""
+msgstr "E208: Fejl ved skrivning til \"%s\""
+
+#, c-format
+msgid "E209: Error closing \"%s\""
+msgstr "E209: Fejl ved lukning af \"%s\""
+
+#, c-format
+msgid "E210: Error reading \"%s\""
+msgstr "E210: Fejl ved læsning af \"%s\""
+
+msgid "E246: FileChangedShell autocommand deleted buffer"
+msgstr "E246: FileChangedShell-autokommando slettede buffer"
+
+#, c-format
+msgid "E211: File \"%s\" no longer available"
+msgstr "E211: Filen \"%s\" er ikke længere tilgængelig"
+
+#, c-format
+msgid ""
+"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
+"well"
+msgstr ""
+"W12: Advarsel: Filen \"%s\" er blevet ændret og bufferen blev også ændret i "
+"Vim"
+
+msgid "See \":help W12\" for more info."
+msgstr "Se \":help W12\" for mere info."
+
+#, c-format
+msgid "W11: Warning: File \"%s\" has changed since editing started"
+msgstr "W11: Advarsel: Filen \"%s\" er blevet ændret siden redigeringen startede"
+
+msgid "See \":help W11\" for more info."
+msgstr "Se \":help W11\" for mere info."
+
+#, c-format
+msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
+msgstr ""
+"W16: Advarsel: Tilstanden af filen \"%s\" er blevet ændret siden redigeringen "
+"startede"
+
+msgid "See \":help W16\" for more info."
+msgstr "Se \":help W16\" for mere info."
+
+#, c-format
+msgid "W13: Warning: File \"%s\" has been created after editing started"
+msgstr ""
+"W13: Advarsel: Filen \"%s\" er blevet oprettet efter redigeringen startede"
+
+msgid "Warning"
+msgstr "Advarsel"
+
+msgid ""
+"&OK\n"
+"&Load File"
+msgstr ""
+"&OK\n"
+"&Indlæs fil"
+
+#, c-format
+msgid "E462: Could not prepare for reloading \"%s\""
+msgstr "E462: Kunne ikke forbedre til genindlæsning af \"%s\""
+
+#, c-format
+msgid "E321: Could not reload \"%s\""
+msgstr "E321: Kunne ikke genindlæse \"%s\""
+
+msgid "--Deleted--"
+msgstr "--Slettet--"
+
+#, c-format
+msgid "auto-removing autocommand: %s <buffer=%d>"
+msgstr "auto-removing-autokommando: %s <buffer=%d>"
+
+#, c-format
+msgid "E367: No such group: \"%s\""
+msgstr "E367: Ingen sådan gruppe: \"%s\""
+
+msgid "E936: Cannot delete the current group"
+msgstr "E936: Kan ikke slette den nuværende gruppe"
+
+msgid "W19: Deleting augroup that is still in use"
+msgstr "W19: Sletter augroup som stadig er i brug"
+
+#, c-format
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: Ulovligt tegn efter *: %s"
+
+#, c-format
+msgid "E216: No such event: %s"
+msgstr "E216: Ingen sådan hændelse: %s"
+
+#, c-format
+msgid "E216: No such group or event: %s"
+msgstr "E216: Ingen sådan gruppe eller hændelse: %s"
+
+msgid ""
+"\n"
+"--- Auto-Commands ---"
+msgstr ""
+"\n"
+"--- Auto-kommandoer ---"
+
+#, c-format
+msgid "E680: <buffer=%d>: invalid buffer number "
+msgstr "E680: <buffer=%d>: ugyldigt buffernummer "
+
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: Kan ikke udføre autokommandoer for ALLE hændelser"
+
+msgid "No matching autocommands"
+msgstr "Ingen matchende autokommandoer"
+
+msgid "E218: autocommand nesting too deep"
+msgstr "E218: autokommando indlejret for dyb"
+
+#, c-format
+msgid "%s Auto commands for \"%s\""
+msgstr "%s Auto-kommandoer for \"%s\""
+
+#, c-format
+msgid "Executing %s"
+msgstr "Udfører %s"
+
+#, c-format
+msgid "autocommand %s"
+msgstr "autokommando %s"
+
+msgid "E219: Missing {."
+msgstr "E219: Manglende {."
+
+msgid "E220: Missing }."
+msgstr "E220: Manglende }."
+
+msgid "E490: No fold found"
+msgstr "E490: Ingen sammenfoldning fundet"
+
+msgid "E350: Cannot create fold with current 'foldmethod'"
+msgstr "E350: Kan ikke oprette sammenfoldning med nuværende 'foldmethod'"
+
+msgid "E351: Cannot delete fold with current 'foldmethod'"
+msgstr "E351: Kan ikke slette sammenfoldning med nuværende 'foldmethod'"
+
+#, c-format
+msgid "+--%3ld line folded "
+msgid_plural "+--%3ld lines folded "
+msgstr[0] "+--%3ld linje sammenfoldet "
+msgstr[1] "+--%3ld linjer sammenfoldet "
+
+msgid "E222: Add to read buffer"
+msgstr "E222: Tilføj til læsebuffer"
+
+msgid "E223: recursive mapping"
+msgstr "E223: rekursiv mapping"
+
+#, c-format
+msgid "E224: global abbreviation already exists for %s"
+msgstr "E224: global forkortelse findes allerede for %s"
+
+#, c-format
+msgid "E225: global mapping already exists for %s"
+msgstr "E225: global mapping findes allerede for %s"
+
+#, c-format
+msgid "E226: abbreviation already exists for %s"
+msgstr "E226: forkortelse findes allerede for %s"
+
+#, c-format
+msgid "E227: mapping already exists for %s"
+msgstr "E227: mapping findes allerede for %s"
+
+msgid "No abbreviation found"
+msgstr "Ingen forkortelse fundet"
+
+msgid "No mapping found"
+msgstr "Ingen mapping fundet"
+
+msgid "E228: makemap: Illegal mode"
+msgstr "E228: makemap: Ulovlig tilstand"
+
+msgid "E851: Failed to create a new process for the GUI"
+msgstr "E851: Kunne ikke oprette en ny proces for GUI'en"
+
+msgid "E852: The child process failed to start the GUI"
+msgstr "E852: Barneprocessen kunne ikke starte GUI'en"
+
+msgid "E229: Cannot start the GUI"
+msgstr "E229: Kan ikke starte GUI'en"
+
+#, c-format
+msgid "E230: Cannot read from \"%s\""
+msgstr "E230: Kan ikke læse fra \"%s\""
+
+msgid "E665: Cannot start GUI, no valid font found"
+msgstr "E665: Kan ikke starte GUI, ingen gyldig skrifttype fundet"
+
+msgid "E231: 'guifontwide' invalid"
+msgstr "E231: 'guifontwide' ugyldig"
+
+msgid "E599: Value of 'imactivatekey' is invalid"
+msgstr "E599: Værdien af 'imactivatekey' er ugyldig"
+
+#, c-format
+msgid "E254: Cannot allocate color %s"
+msgstr "E254: Kan ikke allokere farven %s"
+
+msgid "No match at cursor, finding next"
+msgstr "Intet match ved markør, finder næste"
+
+msgid "<cannot open> "
+msgstr "<kan ikke åbne> "
+
+#, c-format
+msgid "E616: vim_SelFile: can't get font %s"
+msgstr "E616: vim_SelFile: kan ikke hente skrifttypen %s"
+
+msgid "E614: vim_SelFile: can't return to current directory"
+msgstr "E614: vim_SelFile: kan ikke vende tilbage til nuværende mappe"
+
+msgid "Pathname:"
+msgstr "Stinavn:"
+
+msgid "E615: vim_SelFile: can't get current directory"
+msgstr "E615: vim_SelFile: kan ikke hente nuværende mappe"
+
+msgid "OK"
+msgstr "OK"
+
+msgid "Cancel"
+msgstr "Annuller"
+
+msgid "Scrollbar Widget: Could not get geometry of thumb pixmap."
+msgstr ""
+"Rullebjælke-widget: Kunne ikke hente geometri eller pixelkort til miniature."
+
+msgid "Vim dialog"
+msgstr "Vim-dialog"
+
+msgid "E232: Cannot create BalloonEval with both message and callback"
+msgstr "E232: Kan ikke oprette BalloonEval med både meddelelse og callback"
+
+msgid "_Cancel"
+msgstr "_Annuller"
+
+msgid "_Save"
+msgstr "_Gem"
+
+msgid "_Open"
+msgstr "_Ã…bn"
+
+msgid "_OK"
+msgstr "_OK"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"&Cancel"
+msgstr ""
+"&Ja\n"
+"&Nej\n"
+"&Annuller"
+
+msgid "Yes"
+msgstr "Ja"
+
+msgid "No"
+msgstr "Nej"
+
+msgid "Input _Methods"
+msgstr "Input_metoder"
+
+msgid "VIM - Search and Replace..."
+msgstr "VIM - Søg og erstat..."
+
+msgid "VIM - Search..."
+msgstr "VIM - Søg..."
+
+msgid "Find what:"
+msgstr "Find hvad:"
+
+msgid "Replace with:"
+msgstr "Erstat med:"
+
+msgid "Match whole word only"
+msgstr "Match kun hele ord"
+
+msgid "Match case"
+msgstr "Der skelnes ikke mellem store og små bogstaver"
+
+msgid "Direction"
+msgstr "Retning"
+
+msgid "Up"
+msgstr "Op"
+
+msgid "Down"
+msgstr "Ned"
+
+msgid "Find Next"
+msgstr "Find næste"
+
+msgid "Replace"
+msgstr "Erstat"
+
+msgid "Replace All"
+msgstr "Erstat alle"
+
+msgid "_Close"
+msgstr "_Luk"
+
+msgid "Vim: Received \"die\" request from session manager\n"
+msgstr "Vim: Modtog \"die\"-anmodning fra sessionshåndtering\n"
+
+msgid "Close tab"
+msgstr "Luk faneblad"
+
+msgid "New tab"
+msgstr "Nyt faneblad"
+
+msgid "Open Tab..."
+msgstr "Ã…bn faneblad..."
+
+msgid "Vim: Main window unexpectedly destroyed\n"
+msgstr "Vim: Hovedvindue uventet ødelagt\n"
+
+msgid "&Filter"
+msgstr "&Filter"
+
+msgid "&Cancel"
+msgstr "&Annuller"
+
+msgid "Directories"
+msgstr "Mapper"
+
+msgid "Filter"
+msgstr "Filter"
+
+msgid "&Help"
+msgstr "&Hjælp"
+
+msgid "Files"
+msgstr "Filer"
+
+msgid "&OK"
+msgstr "&OK"
+
+msgid "Selection"
+msgstr "Markering"
+
+msgid "Find &Next"
+msgstr "Find &næste"
+
+msgid "&Replace"
+msgstr "&Erstat"
+
+msgid "Replace &All"
+msgstr "Erstat &alle"
+
+msgid "&Undo"
+msgstr "&Fortryd"
+
+msgid "Open tab..."
+msgstr "Ã…bn faneblad..."
+
+msgid "Find string (use '\\\\' to find a '\\')"
+msgstr "Find streng (brug '\\\\' til at finde et '\\')"
+
+msgid "Find & Replace (use '\\\\' to find a '\\')"
+msgstr "Find og erstat (brug '\\\\' til at finde et '\\')"
+
+msgid "Not Used"
+msgstr "Ikke brugt"
+
+msgid "Directory\t*.nothing\n"
+msgstr "Mappe\t\t*.nothing\n"
+
+#, c-format
+msgid "E671: Cannot find window title \"%s\""
+msgstr "E671: Kan ikke finde vinduestitlen \"%s\""
+
+#, c-format
+msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
+msgstr "E243: Argumentet understøttes ikke: \"-%s\"; Brug OLE-versionen."
+
+msgid "E672: Unable to open window inside MDI application"
+msgstr "E672: Kan ikke åbne vindue i MDI-program"
+
+msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect"
+msgstr ""
+"Vim E458: Kan ikke allokere colormap-post, nogle farver kan være forkerte"
+
+#, c-format
+msgid "E250: Fonts for the following charsets are missing in fontset %s:"
+msgstr "E250: Skrifttyper for følgende tegnsæt mangler i skrifttypesættet %s:"
+
+#, c-format
+msgid "E252: Fontset name: %s"
+msgstr "E252: Skrifttypesætnavn: %s"
+
+#, c-format
+msgid "Font '%s' is not fixed-width"
+msgstr "Skrifttypen '%s' er ikke med fast bredde"
+
+#, c-format
+msgid "E253: Fontset name: %s"
+msgstr "E253: Skrifttypesætnavn: %s"
+
+#, c-format
+msgid "Font0: %s"
+msgstr "Skrifttype0: %s"
+
+#, c-format
+msgid "Font1: %s"
+msgstr "Skrifttype1: %s"
+
+#, c-format
+msgid "Font%ld width is not twice that of font0"
+msgstr "Bredden på skrifttype%ld er ikke det dobbelte af skrifttype0"
+
+#, c-format
+msgid "Font0 width: %ld"
+msgstr "Bredden på skrifttype0: %ld"
+
+#, c-format
+msgid "Font1 width: %ld"
+msgstr "Bredden på skrifttype1: %ld"
+
+msgid "Invalid font specification"
+msgstr "Ugyldig skrifttypespecifikation"
+
+msgid "&Dismiss"
+msgstr "&Luk"
+
+msgid "no specific match"
+msgstr "intet specifikt match"
+
+msgid "Vim - Font Selector"
+msgstr "Vim - Skrifttypevælger"
+
+msgid "Name:"
+msgstr "Navn:"
+
+msgid "Show size in Points"
+msgstr "Vis størrelse i punkter"
+
+msgid "Encoding:"
+msgstr "Kodning:"
+
+msgid "Font:"
+msgstr "Skrifttype:"
+
+msgid "Style:"
+msgstr "Stil:"
+
+msgid "Size:"
+msgstr "Størrelse:"
+
+msgid "E256: Hangul automata ERROR"
+msgstr "E256: FEJL ved Hangul automata"
+
+msgid "E550: Missing colon"
+msgstr "E550: Manglende kolon"
+
+msgid "E551: Illegal component"
+msgstr "E551: Ulovlig komponent"
+
+msgid "E552: digit expected"
+msgstr "E552: ciffer ventet"
+
+#, c-format
+msgid "Page %d"
+msgstr "Side %d"
+
+msgid "No text to be printed"
+msgstr "Ingen tekst at udskrive"
+
+#, c-format
+msgid "Printing page %d (%d%%)"
+msgstr "Udskriver side %d (%d%%)"
+
+#, c-format
+msgid " Copy %d of %d"
+msgstr " Kopi %d af %d"
+
+#, c-format
+msgid "Printed: %s"
+msgstr "Udskrev: %s"
+
+msgid "Printing aborted"
+msgstr "Udskrivning afbrudt"
+
+msgid "E455: Error writing to PostScript output file"
+msgstr "E455: Fejl ved skrivning til PostScript-output-fil"
+
+#, c-format
+msgid "E624: Can't open file \"%s\""
+msgstr "E624: Kan ikke åbne filen \"%s\""
+
+#, c-format
+msgid "E457: Can't read PostScript resource file \"%s\""
+msgstr "E457: Kan ikke læse PostScript-ressourcefilen \"%s\""
+
+#, c-format
+msgid "E618: file \"%s\" is not a PostScript resource file"
+msgstr "E618: filen \"%s\" er ikke en PostScript-ressourcefil"
+
+#, c-format
+msgid "E619: file \"%s\" is not a supported PostScript resource file"
+msgstr "E619: filen \"%s\" er ikke en understøttet PostScript-ressourcefil"
+
+#, c-format
+msgid "E621: \"%s\" resource file has wrong version"
+msgstr "E621: \"%s\"-ressourcefilen har forkert version"
+
+msgid "E673: Incompatible multi-byte encoding and character set."
+msgstr "E673: Inkompatibel multibyte-kodning og -tegnsæt."
+
+msgid "E674: printmbcharset cannot be empty with multi-byte encoding."
+msgstr "E674: printmbcharset må ikke være tom med multibyte-kodning."
+
+msgid "E675: No default font specified for multi-byte printing."
+msgstr "E675: Ingen standardskrifttype angivet for multibyte-udskrivning."
+
+msgid "E324: Can't open PostScript output file"
+msgstr "E324: Kan ikke åbne PostScript-output-fil"
+
+#, c-format
+msgid "E456: Can't open file \"%s\""
+msgstr "E456: Kan ikke åbne filen \"%s\""
+
+msgid "E456: Can't find PostScript resource file \"prolog.ps\""
+msgstr "E456: Kan ikke finde PostScript-ressourcefilen \"prolog.ps\""
+
+msgid "E456: Can't find PostScript resource file \"cidfont.ps\""
+msgstr "E456: Kan ikke finde PostScript-ressourcefilen \"cidfont.ps\""
+
+#, c-format
+msgid "E456: Can't find PostScript resource file \"%s.ps\""
+msgstr "E456: Kan ikke finde PostScript-ressourcefilen \"%s.ps\""
+
+#, c-format
+msgid "E620: Unable to convert to print encoding \"%s\""
+msgstr "E620: Kan ikke konvertere til udskrivningskodningen \"%s\""
+
+msgid "Sending to printer..."
+msgstr "Sender til printer..."
+
+msgid "E365: Failed to print PostScript file"
+msgstr "E365: Kunne ikke udskrive PostScript-fil"
+
+msgid "Print job sent."
+msgstr "Udskrivningsjob sendt."
+
+msgid "Add a new database"
+msgstr "Tilføj en ny database"
+
+msgid "Query for a pattern"
+msgstr "Forespørgsel til et mønster"
+
+msgid "Show this message"
+msgstr "Vis denne meddelelse"
+
+msgid "Kill a connection"
+msgstr "Dræb en forbindelse"
+
+msgid "Reinit all connections"
+msgstr "Geninitialisere alle forbindelser"
+
+msgid "Show connections"
+msgstr "Vis forbindelser"
+
+#, c-format
+msgid "E560: Usage: cs[cope] %s"
+msgstr "E560: Anvendelse: cs[cope] %s"
+
+msgid "This cscope command does not support splitting the window.\n"
+msgstr "Denne cscope-kommando understøtter ikke opdeling af vinduet.\n"
+
+msgid "E562: Usage: cstag <ident>"
+msgstr "E562: Anvendelse: cstag <ident>"
+
+msgid "E257: cstag: tag not found"
+msgstr "E257: cstag: tag ikke fundet"
+
+#, c-format
+msgid "E563: stat(%s) error: %d"
+msgstr "E563: fejl ved stat(%s): %d"
+
+msgid "E563: stat error"
+msgstr "E563: fejl ved stat"
+
+#, c-format
+msgid "E564: %s is not a directory or a valid cscope database"
+msgstr "E564: %s er ikke en mappe eller en gyldig cscope-database"
+
+#, c-format
+msgid "Added cscope database %s"
+msgstr "Tilføjede cscope-databasen %s"
+
+#, c-format
+msgid "E262: error reading cscope connection %ld"
+msgstr "E262: fejl ved læsning af cscope-forbindelse %ld"
+
+msgid "E561: unknown cscope search type"
+msgstr "E561: ukendt cscope-søgetype"
+
+msgid "E566: Could not create cscope pipes"
+msgstr "E566: Kunne ikke oprette cscope-pipes"
+
+msgid "E622: Could not fork for cscope"
+msgstr "E622: Kunne ikke fork for cscope"
+
+msgid "cs_create_connection setpgid failed"
+msgstr "cs_create_connection setpgid mislykkedes"
+
+msgid "cs_create_connection exec failed"
+msgstr "cs_create_connection exec mislykkedes"
+
+msgid "cs_create_connection: fdopen for to_fp failed"
+msgstr "cs_create_connection: fdopen for to_fp mislykkedes"
+
+msgid "cs_create_connection: fdopen for fr_fp failed"
+msgstr "cs_create_connection: fdopen for fr_fp mislykkedes"
+
+msgid "E623: Could not spawn cscope process"
+msgstr "E623: Kunne ikke spawn cscope-proces"
+
+msgid "E567: no cscope connections"
+msgstr "E567: ingen cscope-forbindelser"
+
+#, c-format
+msgid "E469: invalid cscopequickfix flag %c for %c"
+msgstr "E469: ugyldigt cscopequickfix-flag %c for %c"
+
+#, c-format
+msgid "E259: no matches found for cscope query %s of %s"
+msgstr "E259: ingen match fundet for cscope-forespørgsel %s af %s"
+
+msgid "cscope commands:\n"
+msgstr "cscope-kommandoer:\n"
+
+#, c-format
+msgid "%-5s: %s%*s (Usage: %s)"
+msgstr "%-5s: %s%*s (Anvendelse: %s)"
+
+msgid ""
+"\n"
+" a: Find assignments to this symbol\n"
+" c: Find functions calling this function\n"
+" d: Find functions called by this function\n"
+" e: Find this egrep pattern\n"
+" f: Find this file\n"
+" g: Find this definition\n"
+" i: Find files #including this file\n"
+" s: Find this C symbol\n"
+" t: Find this text string\n"
+msgstr ""
+"\n"
+" a: Find tildelinger til symbolet\n"
+" c: Find funktioner som kalder funktionen\n"
+" d: Find funktioner som kaldes af funktionen\n"
+" e: Find dette egrep-mønster\n"
+" f: Find filen\n"
+" g: Find definitionen\n"
+" i: Find filer som #inkludere filen\n"
+" s: Find C-symbolet\n"
+" t: Find tekststrengen\n"
+
+#, c-format
+msgid "E625: cannot open cscope database: %s"
+msgstr "E625: kan ikke åbne cscope-database: %s"
+
+msgid "E626: cannot get cscope database information"
+msgstr "E626: kan ikke hente information for cscope-database"
+
+msgid "E568: duplicate cscope database not added"
+msgstr "E568: duplikeret cscope-database ikke tilføjet"
+
+#, c-format
+msgid "E261: cscope connection %s not found"
+msgstr "E261: cscope-forbindelsen %s ikke fundet"
+
+#, c-format
+msgid "cscope connection %s closed"
+msgstr "cscope-forbindelsen %s lukket"
+
+msgid "E570: fatal error in cs_manage_matches"
+msgstr "E570: fatal fejl i cs_manage_matches"
+
+#, c-format
+msgid "Cscope tag: %s"
+msgstr "Cscope-tag: %s"
+
+msgid ""
+"\n"
+" # line"
+msgstr ""
+"\n"
+" # linje"
+
+msgid "filename / context / line\n"
+msgstr "filnavn/kontekst/linje\n"
+
+#, c-format
+msgid "E609: Cscope error: %s"
+msgstr "E609: Fejl ved cscope: %s"
+
+msgid "All cscope databases reset"
+msgstr "Alle cscope-databaser nulstillet"
+
+msgid "no cscope connections\n"
+msgstr "ingen cscope-forbindelser\n"
+
+msgid " # pid database name prepend path\n"
+msgstr " # pid databasenavn prepend-sti\n"
+
+msgid "Lua library cannot be loaded."
+msgstr "Lua-bibliotek kan ikke indlæses."
+
+msgid "cannot save undo information"
+msgstr "kan ikke gemme fortrydinformation"
+
+msgid ""
+"E815: Sorry, this command is disabled, the MzScheme libraries could not be "
+"loaded."
+msgstr ""
+"E815: Beklager, kommandoen er deaktiveret, MzScheme-bibliotekerne kunne ikke "
+"indlæses."
+
+msgid ""
+"E895: Sorry, this command is disabled, the MzScheme's racket/base module "
+"could not be loaded."
+msgstr ""
+"E895: Beklager, kommandoen er deaktiveret, MzScheme's racket-/base-modul "
+"kunne ikke indlæses."
+
+msgid "invalid expression"
+msgstr "ugyldigt udtryk"
+
+msgid "expressions disabled at compile time"
+msgstr "udtryk deaktiveret ved kompileringstid"
+
+msgid "hidden option"
+msgstr "skjult tilvalg"
+
+msgid "unknown option"
+msgstr "ukendt tilvalg"
+
+msgid "window index is out of range"
+msgstr "vinduesindeks udenfor område"
+
+msgid "couldn't open buffer"
+msgstr "kan ikke åbne buffer"
+
+msgid "cannot delete line"
+msgstr "kan ikke slette linje"
+
+msgid "cannot replace line"
+msgstr "kan ikke erstatte linje"
+
+msgid "cannot insert line"
+msgstr "kan ikke indsætte linje"
+
+msgid "string cannot contain newlines"
+msgstr "streng må ikke indeholde linjeskift"
+
+msgid "error converting Scheme values to Vim"
+msgstr "fejl ved konvertering af Scheme-værdier til Vim"
+
+msgid "Vim error: ~a"
+msgstr "Fejl ved Vim: ~a"
+
+msgid "Vim error"
+msgstr "Fejl ved Vim"
+
+msgid "buffer is invalid"
+msgstr "buffer er ugyldig"
+
+msgid "window is invalid"
+msgstr "vindue er ugyldigt"
+
+msgid "linenr out of range"
+msgstr "linjenummer udenfor område"
+
+msgid "not allowed in the Vim sandbox"
+msgstr "ikke tilladt i Vim-sandboksen"
+
+msgid "E836: This Vim cannot execute :python after using :py3"
+msgstr "E836: Denne Vim kan ikke udføre :python efter brug af :py3"
+
+msgid ""
+"E263: Sorry, this command is disabled, the Python library could not be "
+"loaded."
+msgstr ""
+"E263: Beklager, kommandoen er deaktiveret, Python-biblioteket kunne ikke "
+"indlæses."
+
+msgid ""
+"E887: Sorry, this command is disabled, the Python's site module could not be "
+"loaded."
+msgstr ""
+"E887: Beklager, kommandoen er deaktiveret, Python's site-modul kunne ikke "
+"indlæses."
+
+msgid "E659: Cannot invoke Python recursively"
+msgstr "E659: Kan ikke starte Python rekursivt"
+
+msgid "E837: This Vim cannot execute :py3 after using :python"
+msgstr "E837: Denne Vim kan ikke udføre :py3 efter brug af :python"
+
+msgid "E265: $_ must be an instance of String"
+msgstr "E265: $_ skal være en instans af streng"
+
+msgid ""
+"E266: Sorry, this command is disabled, the Ruby library could not be loaded."
+msgstr ""
+"E266: Beklager, kommandoen er deaktiveret, Ruby-biblioteket kunne ikke "
+"indlæses."
+
+msgid "E267: unexpected return"
+msgstr "E267: uventet return"
+
+msgid "E268: unexpected next"
+msgstr "E268: uventet next"
+
+msgid "E269: unexpected break"
+msgstr "E269: uventet break"
+
+msgid "E270: unexpected redo"
+msgstr "E270: uventet redo"
+
+msgid "E271: retry outside of rescue clause"
+msgstr "E271: prøv igen udenfor rescue clause"
+
+msgid "E272: unhandled exception"
+msgstr "E272: uhåndteret undtagelse"
+
+#, c-format
+msgid "E273: unknown longjmp status %d"
+msgstr "E273: ukendt longjmp-status %d"
+
+msgid "invalid buffer number"
+msgstr "ugyldigt buffernummer"
+
+msgid "not implemented yet"
+msgstr "endnu ikke implementeret"
+
+msgid "cannot set line(s)"
+msgstr "kan ikke sætte linje(r)"
+
+msgid "invalid mark name"
+msgstr "ugyldigt mærkenavn"
+
+msgid "mark not set"
+msgstr "mærke ikke sat"
+
+#, c-format
+msgid "row %d column %d"
+msgstr "række %d kolonne %d"
+
+msgid "cannot insert/append line"
+msgstr "kan ikke indsætte/tilføje linje"
+
+msgid "line number out of range"
+msgstr "linjenummer udenfor område"
+
+msgid "unknown flag: "
+msgstr "ukendt flag: "
+
+msgid "unknown vimOption"
+msgstr "ukendt vimOption"
+
+msgid "keyboard interrupt"
+msgstr "tastaturafbryd"
+
+msgid "vim error"
+msgstr "fejl ved vim"
+
+msgid "cannot create buffer/window command: object is being deleted"
+msgstr "kan ikke oprette buffer-/vindue-kommando: objekt slettes"
+
+msgid ""
+"cannot register callback command: buffer/window is already being deleted"
+msgstr ""
+"kan ikke registrere callback-kommando: buffer/vindue er allerede ved at "
+"blive slettet"
+
+msgid ""
+"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim."
+"org"
+msgstr ""
+"E280: FATAL FEJL VED TCL: reflist korrupt!? Rapportér det venligst til vim-"
+"dev@vim.org"
+
+msgid "cannot register callback command: buffer/window reference not found"
+msgstr ""
+"kan ikke registrere callback-kommando: buffer-/vindue-reference ikke fundet"
+
+msgid ""
+"E571: Sorry, this command is disabled: the Tcl library could not be loaded."
+msgstr ""
+"E571: Beklager, kommandoen er deaktiveret: Tcl-biblioteket kunne ikke "
+"indlæses."
+
+#, c-format
+msgid "E572: exit code %d"
+msgstr "E572: afslutningskode %d"
+
+msgid "cannot get line"
+msgstr "kan ikke hente linje"
+
+msgid "Unable to register a command server name"
+msgstr "Kan ikke registrere et kommandoservernavn"
+
+msgid "E248: Failed to send command to the destination program"
+msgstr "E248: Kunne ikke sende kommando til destinationsprogrammet"
+
+#, c-format
+msgid "E573: Invalid server id used: %s"
+msgstr "E573: Ugyldigt server-id brugt: %s"
+
+msgid "E251: VIM instance registry property is badly formed. Deleted!"
+msgstr ""
+"E251: Registreringsegenskab for VIM-instans er dårligt udformet. Slettet!"
+
+#, c-format
+msgid "E938: Duplicate key in JSON: \"%s\""
+msgstr "E938: Duplikeret nøgle i JSON: \"%s\""
+
+#, c-format
+msgid "E696: Missing comma in List: %s"
+msgstr "E696: Manglende komma i liste: %s"
+
+#, c-format
+msgid "E697: Missing end of List ']': %s"
+msgstr "E697: Manglende slutning på List ']': %s"
+
+msgid "Unknown option argument"
+msgstr "Ukendt tilvalgsargument"
+
+msgid "Too many edit arguments"
+msgstr "For mange redigeringsargumenter"
+
+msgid "Argument missing after"
+msgstr "Argument mangler efter"
+
+msgid "Garbage after option argument"
+msgstr "Affald efter tilvalgsargument"
+
+msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"
+msgstr ""
+"For mange \"+kommando\"-, \"-c kommando\"- eller \"--cmd kommando\"-argumenter"
+
+msgid "Invalid argument for"
+msgstr "Ugyldigt argument for"
+
+#, c-format
+msgid "%d files to edit\n"
+msgstr "%d filer at redigere\n"
+
+msgid "netbeans is not supported with this GUI\n"
+msgstr "netbeans understøttes ikke med denne GUI\n"
+
+msgid "'-nb' cannot be used: not enabled at compile time\n"
+msgstr "'-nb' kan ikke bruges: ikke aktiveret ved kompileringstid\n"
+
+msgid "This Vim was not compiled with the diff feature."
+msgstr "Denne Vim blev ikke kompileret med diff-funktionaliteten."
+
+msgid "Attempt to open script file again: \""
+msgstr "Forsøg på at åbne scriptfil igen: \""
+
+msgid "Cannot open for reading: \""
+msgstr "Kan ikke åbne til læsning: \""
+
+msgid "Cannot open for script output: \""
+msgstr "Kan ikke åbne for script-output: \""
+
+msgid "Vim: Error: Failure to start gvim from NetBeans\n"
+msgstr "Vim: Fejl: Kunne ikke starte gvim fra NetBeans\n"
+
+msgid "Vim: Error: This version of Vim does not run in a Cygwin terminal\n"
+msgstr "Vim: Fejl: Denne version af Vim kører ikke i en Cygwin-terminal\n"
+
+msgid "Vim: Warning: Output is not to a terminal\n"
+msgstr "Vim: Advarsel: Output er ikke til en terminal\n"
+
+msgid "Vim: Warning: Input is not from a terminal\n"
+msgstr "Vim: Advarsel: Input er ikke fra en terminal\n"
+
+msgid "pre-vimrc command line"
+msgstr "pre-vimrc-kommandolinje"
+
+#, c-format
+msgid "E282: Cannot read from \"%s\""
+msgstr "E282: Kan ikke læse fra \"%s\""
+
+msgid ""
+"\n"
+"More info with: \"vim -h\"\n"
+msgstr ""
+"\n"
+"Mere info med: \"vim -h\"\n"
+
+msgid "[file ..] edit specified file(s)"
+msgstr "[fil ..] rediger angivne fil(er)"
+
+msgid "- read text from stdin"
+msgstr "- læs tekst fra stdin"
+
+msgid "-t tag edit file where tag is defined"
+msgstr "-t tag rediger fil hvor tag er defineret"
+
+msgid "-q [errorfile] edit file with first error"
+msgstr "-q [fejlfil] rediger fil med første fejl"
+
+msgid ""
+"\n"
+"\n"
+"usage:"
+msgstr ""
+"\n"
+"\n"
+"anvendelse:"
+
+msgid " vim [arguments] "
+msgstr " vim [argumenter] "
+
+msgid ""
+"\n"
+" or:"
+msgstr ""
+"\n"
+" eller:"
+
+msgid ""
+"\n"
+"Where case is ignored prepend / to make flag upper case"
+msgstr ""
+"\n"
+"Når der ikke skelnes mellem store og små bogstaver, så tilføj / i "
+"begyndelsen for at gøre flag til store bogstaver"
+
+msgid ""
+"\n"
+"\n"
+"Arguments:\n"
+msgstr ""
+"\n"
+"\n"
+"Argumenter:\n"
+
+msgid "--\t\t\tOnly file names after this"
+msgstr "--\t\t\tKun filnavne herefter"
+
+msgid "--literal\t\tDon't expand wildcards"
+msgstr "--literal\t\tUdvid ikke jokertegn"
+
+msgid "-register\t\tRegister this gvim for OLE"
+msgstr "-register\t\tRegistrer denne gvim til OLE"
+
+msgid "-unregister\t\tUnregister gvim for OLE"
+msgstr "-unregister\t\tAfregistrer gvim for OLE"
+
+msgid "-g\t\t\tRun using GUI (like \"gvim\")"
+msgstr "-g\t\t\tKør med GUI (ligesom \"gvim\")"
+
+msgid "-f or --nofork\tForeground: Don't fork when starting GUI"
+msgstr "-f eller --nofork\tForgrund: Fork ikke når GUI startes"
+
+msgid "-v\t\t\tVi mode (like \"vi\")"
+msgstr "-v\t\t\tVi-tilstand (ligesom \"vi\")"
+
+msgid "-e\t\t\tEx mode (like \"ex\")"
+msgstr "-e\t\t\tEx-tilstand (ligesom \"ex\")"
+
+msgid "-E\t\t\tImproved Ex mode"
+msgstr "-E\t\t\tForbedret Ex-tilstand"
+
+msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")"
+msgstr "-s\t\t\tStille (batch) tilstand (kun til \"ex\")"
+
+msgid "-d\t\t\tDiff mode (like \"vimdiff\")"
+msgstr "-d\t\t\tDiff-tilstand (ligesom \"vimdiff\")"
+
+msgid "-y\t\t\tEasy mode (like \"evim\", modeless)"
+msgstr "-y\t\t\tEasy-tilstand (ligesom \"evim\", tilstandsløs)"
+
+msgid "-R\t\t\tReadonly mode (like \"view\")"
+msgstr "-R\t\t\tSkrivebeskyttet tilstand (ligesom \"view\")"
+
+msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
+msgstr "-Z\t\t\tRestriktiv tilstand (ligesom \"rvim\")"
+
+msgid "-m\t\t\tModifications (writing files) not allowed"
+msgstr "-m\t\t\tÆndringer (skrivning af filer) ikke tilladt"
+
+msgid "-M\t\t\tModifications in text not allowed"
+msgstr "-M\t\t\tÆndringer i tekst ikke tilladt"
+
+msgid "-b\t\t\tBinary mode"
+msgstr "-b\t\t\tBinær tilstand"
+
+msgid "-l\t\t\tLisp mode"
+msgstr "-l\t\t\tLisp-tilstand"
+
+msgid "-C\t\t\tCompatible with Vi: 'compatible'"
+msgstr "-C\t\t\tKompatibel med Vi: 'compatible'"
+
+msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'"
+msgstr "-N\t\t\tIkke fuldt ud Vi-kompatibel: 'nocompatible'"
+
+msgid "-V[N][fname]\t\tBe verbose [level N] [log messages to fname]"
+msgstr "-V[N][fnavn]\t\tVær uddybende [niveau N] [log meddelelser til fnavn]"
+
+msgid "-D\t\t\tDebugging mode"
+msgstr "-D\t\t\tFejlretningstilstand"
+
+msgid "-n\t\t\tNo swap file, use memory only"
+msgstr "-n\t\t\tIngen swap-fil, brug kun hukommelse"
+
+msgid "-r\t\t\tList swap files and exit"
+msgstr "-r\t\t\tOplist swap-filer og afslut"
+
+msgid "-r (with file name)\tRecover crashed session"
+msgstr "-r (med filnavn)\tGendan session som holdt op med at virke"
+
+msgid "-L\t\t\tSame as -r"
+msgstr "-L\t\t\tSamme som -r"
+
+msgid "-f\t\t\tDon't use newcli to open window"
+msgstr "-f\t\t\tBrug ikke newcli til at åbne vindue"
+
+msgid "-dev <device>\t\tUse <device> for I/O"
+msgstr "-dev <enhed>\t\tBrug <enhed> til I/O"
+
+msgid "-A\t\t\tstart in Arabic mode"
+msgstr "-A\t\t\tstart i arabisk tilstand"
+
+msgid "-H\t\t\tStart in Hebrew mode"
+msgstr "-H\t\t\tStart i hebraisk tilstand"
+
+msgid "-F\t\t\tStart in Farsi mode"
+msgstr "-F\t\t\tStart i persisk tilstand"
+
+msgid "-T <terminal>\tSet terminal type to <terminal>"
+msgstr "-T <terminal>\tSæt terminaltype til <terminal>"
+
+msgid "--not-a-term\t\tSkip warning for input/output not being a terminal"
+msgstr ""
+"--not-a-term\t\tSpring advarsel over for input/output som ikke er en terminal"
+
+msgid "--ttyfail\t\tExit if input or output is not a terminal"
+msgstr "--ttyfail\t\tAfslut hvis input eller output ikke er en terminal"
+
+msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc"
+msgstr "-u <vimrc>\t\tBrug <vimrc> i stedet for nogen .vimrc"
+
+msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc"
+msgstr "-U <gvimrc>\t\tBrug <gvimrc> i stedet for nogen .gvimrc"
+
+msgid "--noplugin\t\tDon't load plugin scripts"
+msgstr "--noplugin\t\tIndlæs ikke plugin-scripts"
+
+msgid "-p[N]\t\tOpen N tab pages (default: one for each file)"
+msgstr "-p[N]\t\tÅbn N fanebladssider (standard: én pr. fil)"
+
+msgid "-o[N]\t\tOpen N windows (default: one for each file)"
+msgstr "-o[N]\t\tÅbn N vinduer (standard: én pr. fil)"
+
+msgid "-O[N]\t\tLike -o but split vertically"
+msgstr "-O[N]\t\tLigesom -o men opdel lodret"
+
+msgid "+\t\t\tStart at end of file"
+msgstr "+\t\t\tBegynd ved slutningen af filen"
+
+msgid "+<lnum>\t\tStart at line <lnum>"
+msgstr "+<lnum>\t\tBegynd ved linje <lnum>"
+
+msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
+msgstr "--cmd <kommando>\tUdfør <kommando> inden indlæsning af vimrc-filer"
+
+msgid "-c <command>\t\tExecute <command> after loading the first file"
+msgstr "-c <kommando>\tUdfør <kommando> efter indlæsning af den første fil"
+
+msgid "-S <session>\t\tSource file <session> after loading the first file"
+msgstr "-S <session>\t\tSource filen <session> efter indlæsning af den første fil"
+
+msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>"
+msgstr "-s <scriptind>\tLæs normal tilstand-kommandoer fra filen <scriptind>"
+
+msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>"
+msgstr ""
+"-w <scriptud>\tTilføj alle indtastede kommandoer til slutningen af filen "
+"<scriptud>"
+
+msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>"
+msgstr "-W <scriptud>\tSkriv alle indtastede kommandoer til filen <scriptud>"
+
+msgid "-x\t\t\tEdit encrypted files"
+msgstr "-x\t\t\tRediger krypterede filer"
+
+msgid "-display <display>\tConnect vim to this particular X-server"
+msgstr "-display <display>\tForbind vim til denne X-server"
+
+msgid "-X\t\t\tDo not connect to X server"
+msgstr "-X\t\t\tOpret ikke forbindelse til X-server"
+
+msgid "--remote <files>\tEdit <files> in a Vim server if possible"
+msgstr "--remote <filer>\tRediger <filer> i en Vim-server, hvis det er muligt"
+
+msgid "--remote-silent <files> Same, don't complain if there is no server"
+msgstr ""
+"--remote-silent <filer> Samme, men vær tavs hvis der ikke er nogen server"
+
+msgid ""
+"--remote-wait <files> As --remote but wait for files to have been edited"
+msgstr ""
+"--remote-wait <filer> Som --remote men vent på filer som skal redigeres"
+
+msgid ""
+"--remote-wait-silent <files> Same, don't complain if there is no server"
+msgstr ""
+"--remote-wait-silent <filer> Samme, men vær tavs hvis der ikke er nogen "
+"server"
+
+msgid ""
+"--remote-tab[-wait][-silent] <files> As --remote but use tab page per file"
+msgstr ""
+"--remote-tab[-wait][-silent] <filer> Som --remote men brug fanebladsside "
+"pr. fil"
+
+msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit"
+msgstr "--remote-send <nøgler>\tSend <nøgler> til en Vim-server og afslut"
+
+msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result"
+msgstr ""
+"--remote-expr <udtryk>\tEvaluér <udtryk> i en Vim-server og udskriv "
+"resultatet"
+
+msgid "--serverlist\t\tList available Vim server names and exit"
+msgstr "--serverlist\t\tOplist tilgængelige Vim-servernavne og afslut"
+
+msgid "--servername <name>\tSend to/become the Vim server <name>"
+msgstr "--servername <navn>\tSend til/bliv Vim-serveren <navn>"
+
+msgid "--startuptime <file>\tWrite startup timing messages to <file>"
+msgstr "--startuptime <fil>\tSkriv meddelelser om opstartstiming til <fil>"
+
+msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo"
+msgstr "-i <viminfo>\t\tBrug <viminfo> i stedet for .viminfo"
+
+msgid "--clean\t\t'nocompatible', Vim defaults, no plugins, no viminfo"
+msgstr "--clean\t\t'nocompatible', Vim-standarder, ingen plugins, ingen viminfo"
+
+msgid "-h or --help\tPrint Help (this message) and exit"
+msgstr "-h eller --help\tUdskriv hjælp (denne meddelelse) og afslut"
+
+msgid "--version\t\tPrint version information and exit"
+msgstr "--version\t\tUdskriv versionsinformation og afslut"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Motif version):\n"
+msgstr ""
+"\n"
+"Argumenter som genkendes af gvim (Motif-version):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (neXtaw version):\n"
+msgstr ""
+"\n"
+"Argumenter som genkendes af gvim (neXtaw-version):\n"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (Athena version):\n"
+msgstr ""
+"\n"
+"Argumenter som genkendes af gvim (Athena-version):\n"
+
+msgid "-display <display>\tRun vim on <display>"
+msgstr "-display <display>\tKør vim på <display>"
+
+msgid "-iconic\t\tStart vim iconified"
+msgstr "-iconic\t\tStart vim som ikon"
+
+msgid "-background <color>\tUse <color> for the background (also: -bg)"
+msgstr "-background <farve>\tBrug <farve> til baggrunden (også: -bg)"
+
+msgid "-foreground <color>\tUse <color> for normal text (also: -fg)"
+msgstr "-foreground <farve>\tBrug <farve> til normal tekst (også: -fg)"
+
+msgid "-font <font>\t\tUse <font> for normal text (also: -fn)"
+msgstr "-font <skrifttype>\tBrug <skrifttype> til normal tekst (også: -fn)"
+
+msgid "-boldfont <font>\tUse <font> for bold text"
+msgstr "-boldfont <skrifttype>\tBrug <skrifttype> til fed tekst"
+
+msgid "-italicfont <font>\tUse <font> for italic text"
+msgstr "-italicfont <skriftt.>\tBrug <skrifttype> til kursiv tekst"
+
+msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)"
+msgstr "-geometry <geom>\tBrug <geom> for indledende geometri (også: -geom)"
+
+msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)"
+msgstr "-borderwidth <bredde>\tBrug en kantbredde på <bredde> (også: -bw)"
+
+msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)"
+msgstr ""
+"-scrollbarwidth <bredde> Brug en rullebjælkebredde på <bredde> (også: -sw)"
+
+msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)"
+msgstr "-menuheight <højde>\tBrug en menulinjehøjde på <højde> (også: -mh)"
+
+msgid "-reverse\t\tUse reverse video (also: -rv)"
+msgstr "-reverse\t\tBrug omvendt grafik (også: -rv)"
+
+msgid "+reverse\t\tDon't use reverse video (also: +rv)"
+msgstr "+reverse\t\tBrug ikke omvendt grafik (også: +rv)"
+
+msgid "-xrm <resource>\tSet the specified resource"
+msgstr "-xrm <ressource>\tSæt den angivne ressource"
+
+msgid ""
+"\n"
+"Arguments recognised by gvim (GTK+ version):\n"
+msgstr ""
+"\n"
+"Argumenter genkendt af gvim (GTK+-version):\n"
+
+msgid "-display <display>\tRun vim on <display> (also: --display)"
+msgstr "-display <display>\tKør vim på <display> (også: --display)"
+
+msgid "--role <role>\tSet a unique role to identify the main window"
+msgstr "--role <rolle>\tSæt en unik rolle til at identificere hovedvinduet"
+
+msgid "--socketid <xid>\tOpen Vim inside another GTK widget"
+msgstr "--socketid <xid>\tÃ…bn Vim i en anden GTK-widget"
+
+msgid "--echo-wid\t\tMake gvim echo the Window ID on stdout"
+msgstr "--echo-wid\t\tFÃ¥ gvim til at skrive vinduets ID til stdout"
+
+msgid "-P <parent title>\tOpen Vim inside parent application"
+msgstr "-P <forældertitel>\tÅbn Vim i forælderprogram"
+
+msgid "--windowid <HWND>\tOpen Vim inside another win32 widget"
+msgstr "--windowid <HWND>\tÃ…bn Vim i en anden win32-widget"
+
+msgid "No display"
+msgstr "Intet display"
+
+msgid ": Send failed.\n"
+msgstr ": Sending mislykkedes.\n"
+
+msgid ": Send failed. Trying to execute locally\n"
+msgstr ": Sending mislykkedes. Prøver at udføre lokalt\n"
+
+#, c-format
+msgid "%d of %d edited"
+msgstr "%d af %d redigeret"
+
+msgid "No display: Send expression failed.\n"
+msgstr "Intet display: Send-udtryk mislykkedes.\n"
+
+msgid ": Send expression failed.\n"
+msgstr ": Send-udtryk mislykkedes.\n"
+
+msgid "No marks set"
+msgstr "Ingen mærker sat"
+
+#, c-format
+msgid "E283: No marks matching \"%s\""
+msgstr "E283: Ingen mærker matcher \"%s\""
+
+msgid ""
+"\n"
+"mark line col file/text"
+msgstr ""
+"\n"
+"mærke linje kol fil/tekst"
+
+msgid ""
+"\n"
+" jump line col file/text"
+msgstr ""
+"\n"
+" hop linje kol fil/tekst"
+
+msgid ""
+"\n"
+"change line col text"
+msgstr ""
+"\n"
+"skift linje kol tekst"
+
+msgid ""
+"\n"
+"# File marks:\n"
+msgstr ""
+"\n"
+"# Filmærker:\n"
+
+msgid ""
+"\n"
+"# Jumplist (newest first):\n"
+msgstr ""
+"\n"
+"# Hopliste (nyeste først):\n"
+
+msgid ""
+"\n"
+"# History of marks within files (newest to oldest):\n"
+msgstr ""
+"\n"
+"# Historik over mærker i filer (nyeste til ældste):\n"
+
+msgid "Missing '>'"
+msgstr "Manglende '>'"
+
+msgid "E543: Not a valid codepage"
+msgstr "E543: Ikke en gyldig tegnkodningstabel"
+
+msgid "E284: Cannot set IC values"
+msgstr "E284: Kan ikke sætte IC-værdier"
+
+msgid "E285: Failed to create input context"
+msgstr "E285: Kunne ikke oprette inputkontekst"
+
+msgid "E286: Failed to open input method"
+msgstr "E286: Kunne ikke åbne inputmetode"
+
+msgid "E287: Warning: Could not set destroy callback to IM"
+msgstr "E287: Advarsel: Kunne ikke sætte destroy callback til IM"
+
+msgid "E288: input method doesn't support any style"
+msgstr "E288: inputmetode understøtter ikke nogen stil"
+
+msgid "E289: input method doesn't support my preedit type"
+msgstr "E289: inputmetode understøtter ikke min preedit-type"
+
+msgid "E293: block was not locked"
+msgstr "E293: blok blev ikke låst"
+
+msgid "E294: Seek error in swap file read"
+msgstr "E294: Søgefejl ved læsning af swap-fil"
+
+msgid "E295: Read error in swap file"
+msgstr "E295: Læsefejl i swap-fil"
+
+msgid "E296: Seek error in swap file write"
+msgstr "E296: Søgefejl ved skrivning af swap-fil"
+
+msgid "E297: Write error in swap file"
+msgstr "E297: Skrivefejl i swap-fil"
+
+msgid "E300: Swap file already exists (symlink attack?)"
+msgstr "E300: Swap-filen findes allerede (symlink angreb?)"
+
+msgid "E298: Didn't get block nr 0?"
+msgstr "E298: Blev blok nr. 0 ikke hentet?"
+
+msgid "E298: Didn't get block nr 1?"
+msgstr "E298: Blev blok nr. 1 ikke hentet?"
+
+msgid "E298: Didn't get block nr 2?"
+msgstr "E298: Blev blok nr. 2 ikke hentet?"
+
+msgid "E843: Error while updating swap file crypt"
+msgstr "E843: Fejl ved opdatering af crypt for swap-fil"
+
+msgid "E301: Oops, lost the swap file!!!"
+msgstr "E301: Ups, mistede swap-filen!!!"
+
+msgid "E302: Could not rename swap file"
+msgstr "E302: Kunne ikke omdøbe swap-fil"
+
+#, c-format
+msgid "E303: Unable to open swap file for \"%s\", recovery impossible"
+msgstr "E303: Kan ikke åbne swap-filen for \"%s\", gendannelse er ikke muligt"
+
+msgid "E304: ml_upd_block0(): Didn't get block 0??"
+msgstr "E304: ml_upd_block0(): Blev blok 0 ikke hentet??"
+
+#, c-format
+msgid "E305: No swap file found for %s"
+msgstr "E305: Fandt ingen swap-fil for %s"
+
+msgid "Enter number of swap file to use (0 to quit): "
+msgstr "Indtast antal swap-filer som der skal bruges (0 for at afslutte): "
+
+#, c-format
+msgid "E306: Cannot open %s"
+msgstr "E306: Kan ikke åbne %s"
+
+msgid "Unable to read block 0 from "
+msgstr "Kan ikke læse blok 0 fra "
+
+msgid ""
+"\n"
+"Maybe no changes were made or Vim did not update the swap file."
+msgstr ""
+"\n"
+"Måske er der ikke foretaget nogen ændringer eller Vim opdaterede ikke swap-"
+"filen."
+
+msgid " cannot be used with this version of Vim.\n"
+msgstr " kan ikke bruges med denne version af Vim.\n"
+
+msgid "Use Vim version 3.0.\n"
+msgstr "Brug Vim version 3.0.\n"
+
+#, c-format
+msgid "E307: %s does not look like a Vim swap file"
+msgstr "E307: %s ligner ikke en Vim swap-fil"
+
+msgid " cannot be used on this computer.\n"
+msgstr " kan ikke bruges på denne computer.\n"
+
+msgid "The file was created on "
+msgstr "Filen blev oprettet på "
+
+msgid ""
+",\n"
+"or the file has been damaged."
+msgstr ""
+",\n"
+"eller filen er beskadiget."
+
+#, c-format
+msgid ""
+"E833: %s is encrypted and this version of Vim does not support encryption"
+msgstr ""
+"E833: %s er krypteret og denne version af Vim understøtter ikke kryptering"
+
+msgid " has been damaged (page size is smaller than minimum value).\n"
+msgstr " er beskadiget (sidestørrelsen er mindre end minimumsværdien).\n"
+
+#, c-format
+msgid "Using swap file \"%s\""
+msgstr "Bruger swap-filen \"%s\""
+
+#, c-format
+msgid "Original file \"%s\""
+msgstr "Den originale fil \"%s\""
+
+msgid "E308: Warning: Original file may have been changed"
+msgstr "E308: Advarsel: Den originale fil kan være ændret"
+
+#, c-format
+msgid "Swap file is encrypted: \"%s\""
+msgstr "Swap-filen er krypteret: \"%s\""
+
+msgid ""
+"\n"
+"If you entered a new crypt key but did not write the text file,"
+msgstr ""
+"\n"
+"Hvis du indtastede en ny crypt-nøgle men ikke skrev tekstfilen,"
+
+msgid ""
+"\n"
+"enter the new crypt key."
+msgstr ""
+"\n"
+"så indtast den nye crypt-nøgle."
+
+msgid ""
+"\n"
+"If you wrote the text file after changing the crypt key press enter"
+msgstr ""
+"\n"
+"Hvis du skrev tekstfilen efter crypt-nøglen blev ændret, så tryk på enter"
+
+msgid ""
+"\n"
+"to use the same key for text file and swap file"
+msgstr ""
+"\n"
+"for at bruge den samme nøgle til tekstfilen og swap-filen"
+
+#, c-format
+msgid "E309: Unable to read block 1 from %s"
+msgstr "E309: Kan ikke læse blok 1 fra %s"
+
+msgid "???MANY LINES MISSING"
+msgstr "???MANGE LINJER MANGLER"
+
+msgid "???LINE COUNT WRONG"
+msgstr "???LINJEANTAL FORKERT"
+
+msgid "???EMPTY BLOCK"
+msgstr "???TOM BLOK"
+
+msgid "???LINES MISSING"
+msgstr "???LINJER MANGLER"
+
+#, c-format
+msgid "E310: Block 1 ID wrong (%s not a .swp file?)"
+msgstr "E310: Forkert ID for blok 1 (%s ikke en .swp-fil?)"
+
+msgid "???BLOCK MISSING"
+msgstr "???BLOK MANGLER"
+
+msgid "??? from here until ???END lines may be messed up"
+msgstr "??? herfra indtil ???SLUT kan linjer være rodet"
+
+msgid "??? from here until ???END lines may have been inserted/deleted"
+msgstr "??? herfra indtil ???SLUT kan linjer være indsat/slettet"
+
+msgid "???END"
+msgstr "???SLUT"
+
+msgid "E311: Recovery Interrupted"
+msgstr "E311: Gendannelse afbrudt"
+
+msgid ""
+"E312: Errors detected while recovering; look for lines starting with ???"
+msgstr ""
+"E312: Fejl registreret ved gendannelse; kig efter linjer som begynder med "
+"???"
+
+msgid "See \":help E312\" for more information."
+msgstr "Se \":help E312\" for mere information."
+
+msgid "Recovery completed. You should check if everything is OK."
+msgstr "Gendannelse gennemført. Du bør tjekke om alt er OK."
+
+msgid ""
+"\n"
+"(You might want to write out this file under another name\n"
+msgstr ""
+"\n"
+"(Det kan være du vil skrive filen under et andet navn\n"
+
+msgid "and run diff with the original file to check for changes)"
+msgstr "og kør diff men den originale fil for at tjekke for ændringer)"
+
+msgid "Recovery completed. Buffer contents equals file contents."
+msgstr ""
+"Gendannelse gennemført. Bufferens indhold er det samme som filens indhold."
+
+msgid ""
+"\n"
+"You may want to delete the .swp file now.\n"
+"\n"
+msgstr ""
+"\n"
+"Det kan være du vil slette .swp-filen nu.\n"
+"\n"
+
+msgid "Using crypt key from swap file for the text file.\n"
+msgstr "Bruger crypt-nøglen fra swap-filen til tekstfilen.\n"
+
+msgid "Swap files found:"
+msgstr "Swap-filer fundet:"
+
+msgid " In current directory:\n"
+msgstr " I nuværende mappe:\n"
+
+msgid " Using specified name:\n"
+msgstr " Bruger angivne navn:\n"
+
+msgid " In directory "
+msgstr " I mappe "
+
+msgid " -- none --\n"
+msgstr " -- ingen --\n"
+
+msgid " owned by: "
+msgstr " ejet af: "
+
+msgid " dated: "
+msgstr " dateret: "
+
+msgid " dated: "
+msgstr " dateret: "
+
+msgid " [from Vim version 3.0]"
+msgstr " [fra Vim version 3.0]"
+
+msgid " [does not look like a Vim swap file]"
+msgstr " [ligner ikke en Vim swap-fil]"
+
+msgid " file name: "
+msgstr " filnavn: "
+
+msgid ""
+"\n"
+" modified: "
+msgstr ""
+"\n"
+" ændret: "
+
+msgid "YES"
+msgstr "JA"
+
+msgid "no"
+msgstr "nej"
+
+msgid ""
+"\n"
+" user name: "
+msgstr ""
+"\n"
+" brugernavn: "
+
+msgid " host name: "
+msgstr " værtsnavn: "
+
+msgid ""
+"\n"
+" host name: "
+msgstr ""
+"\n"
+" værtsnavn: "
+
+msgid ""
+"\n"
+" process ID: "
+msgstr ""
+"\n"
+" proces-ID: "
+
+msgid " (still running)"
+msgstr " (kører stadig)"
+
+msgid ""
+"\n"
+" [not usable with this version of Vim]"
+msgstr ""
+"\n"
+" [ikke anvendelig med denne version af Vim]"
+
+msgid ""
+"\n"
+" [not usable on this computer]"
+msgstr ""
+"\n"
+" [ikke anvendelig på denne computer]"
+
+msgid " [cannot be read]"
+msgstr " [kan ikke læses]"
+
+msgid " [cannot be opened]"
+msgstr " [kan ikke åbnes]"
+
+msgid "E313: Cannot preserve, there is no swap file"
+msgstr "E313: Kan ikke bevares, der er ikke nogen swap-fil"
+
+msgid "File preserved"
+msgstr "Fil bevaret"
+
+msgid "E314: Preserve failed"
+msgstr "E314: Bevaring mislykkedes"
+
+#, c-format
+msgid "E315: ml_get: invalid lnum: %ld"
+msgstr "E315: ml_get: ugyldig lnum: %ld"
+
+#, c-format
+msgid "E316: ml_get: cannot find line %ld"
+msgstr "E316: ml_get: kan ikke finde linje %ld"
+
+msgid "E317: pointer block id wrong 3"
+msgstr "E317: forkert blok-id for pointer 3"
+
+msgid "stack_idx should be 0"
+msgstr "stack_idx skal være 0"
+
+msgid "E318: Updated too many blocks?"
+msgstr "E318: Opdaterede for mange blokke?"
+
+msgid "E317: pointer block id wrong 4"
+msgstr "E317: forkert blok-id for pointer 4"
+
+msgid "deleted block 1?"
+msgstr "slettede blok 1?"
+
+#, c-format
+msgid "E320: Cannot find line %ld"
+msgstr "E320: Kan ikke finde linje %ld"
+
+msgid "E317: pointer block id wrong"
+msgstr "E317: forkert blok-id for pointer"
+
+msgid "pe_line_count is zero"
+msgstr "pe_line_count er nul"
+
+#, c-format
+msgid "E322: line number out of range: %ld past the end"
+msgstr "E322: linjenummer udenfor område: %ld efter slutningen"
+
+#, c-format
+msgid "E323: line count wrong in block %ld"
+msgstr "E323: linje antal forkert i blok %ld"
+
+msgid "Stack size increases"
+msgstr "Stakstørrelse øges"
+
+msgid "E317: pointer block id wrong 2"
+msgstr "E317: forkert blok-id for pointer 2"
+
+#, c-format
+msgid "E773: Symlink loop for \"%s\""
+msgstr "E773: Symlink-løkke for \"%s\""
+
+msgid "E325: ATTENTION"
+msgstr "E325: OBS"
+
+msgid ""
+"\n"
+"Found a swap file by the name \""
+msgstr ""
+"\n"
+"Fandt en swap-fil ved navn \""
+
+msgid "While opening file \""
+msgstr "Ved åbning af filen \""
+
+msgid " NEWER than swap file!\n"
+msgstr " NYERE end swap-fil!\n"
+
+msgid ""
+"\n"
+"(1) Another program may be editing the same file. If this is the case,\n"
+" be careful not to end up with two different instances of the same\n"
+" file when making changes. Quit, or continue with caution.\n"
+msgstr ""
+"\n"
+"(1) Et andet program redigere muligvis den samme fil. Hvis det er tilfældet,\n"
+" så pas på ikke at ende med to forskellige instanser af den samme\n"
+" fil når der foretages ændringer. Afslut, eller fortsæt med forsigtighed.\n"
+
+msgid "(2) An edit session for this file crashed.\n"
+msgstr "(2) En redigeringssession for filen holdt op med at virke.\n"
+
+msgid " If this is the case, use \":recover\" or \"vim -r "
+msgstr " Hvis det er tilfældet, så brug \":recover\" eller \"vim -r "
+
+msgid ""
+"\"\n"
+" to recover the changes (see \":help recovery\").\n"
+msgstr ""
+"\"\n"
+" for at gendanne ændringerne (se \":help recovery\").\n"
+
+msgid " If you did this already, delete the swap file \""
+msgstr " Hvis du allerede har gjort det, så slet swap-filen \""
+
+msgid ""
+"\"\n"
+" to avoid this message.\n"
+msgstr ""
+"\"\n"
+" for at undgå denne meddelelse.\n"
+
+msgid "Swap file \""
+msgstr "Swap-filen \""
+
+msgid "\" already exists!"
+msgstr "\" findes allerede!"
+
+msgid "VIM - ATTENTION"
+msgstr "VIM - OBS"
+
+msgid "Swap file already exists!"
+msgstr "Swap-filen findes allerede!"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&Ã…bn skrivebeskyttet\n"
+"&Rediger alligevel\n"
+"&Gendan\n"
+"&Afslut\n"
+"&Afbryd"
+
+msgid ""
+"&Open Read-Only\n"
+"&Edit anyway\n"
+"&Recover\n"
+"&Delete it\n"
+"&Quit\n"
+"&Abort"
+msgstr ""
+"&Ã…bn skrivebeskyttet\n"
+"&Rediger alligevel\n"
+"&Gendan\n"
+"&Slet den\n"
+"&Afslut\n"
+"&Afbryd"
+
+msgid "E326: Too many swap files found"
+msgstr "E326: For mange swap-filer fundet"
+
+msgid "E327: Part of menu-item path is not sub-menu"
+msgstr "E327: Del af sti til menupunkt er ikke undermenu"
+
+msgid "E328: Menu only exists in another mode"
+msgstr "E328: Menuen findes kun i en anden tilstand"
+
+#, c-format
+msgid "E329: No menu \"%s\""
+msgstr "E329: Ingen menu \"%s\""
+
+msgid "E792: Empty menu name"
+msgstr "E792: Tomt menunavn"
+
+msgid "E330: Menu path must not lead to a sub-menu"
+msgstr "E330: Menusti må ikke lede til en undermenu"
+
+msgid "E331: Must not add menu items directly to menu bar"
+msgstr "E331: Må ikke tilføje menupunkter direkte til menulinje"
+
+msgid "E332: Separator cannot be part of a menu path"
+msgstr "E332: Separator må ikke være del af en menusti"
+
+msgid ""
+"\n"
+"--- Menus ---"
+msgstr ""
+"\n"
+"--- Menuer ---"
+
+msgid "Tear off this menu"
+msgstr "Løsriv menuen"
+
+#, c-format
+msgid "E335: Menu not defined for %s mode"
+msgstr "E335: Menu ikke defineret for %s-tilstand"
+
+msgid "E333: Menu path must lead to a menu item"
+msgstr "E333: Menusti skal lede til et menupunkt"
+
+#, c-format
+msgid "E334: Menu not found: %s"
+msgstr "E334: Menu ikke fundet: %s"
+
+msgid "E336: Menu path must lead to a sub-menu"
+msgstr "E336: Menusti skal lede til en undermenu"
+
+msgid "E337: Menu not found - check menu names"
+msgstr "E337: Menu ikke fundet - tjek menunavne"
+
+#, c-format
+msgid "Error detected while processing %s:"
+msgstr "Fejl registreret ved behandling af %s:"
+
+#, c-format
+msgid "line %4ld:"
+msgstr "linje %4ld:"
+
+#, c-format
+msgid "E354: Invalid register name: '%s'"
+msgstr "E354: Ugyldigt registernavn: '%s'"
+
+msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>"
+msgstr "Oversætter: scootergrisen"
+
+msgid "Interrupt: "
+msgstr "Afbryd: "
+
+msgid "Press ENTER or type command to continue"
+msgstr "Tryk på ENTER eller skriv kommando for at fortsætte"
+
+#, c-format
+msgid "%s line %ld"
+msgstr "%s linje %ld"
+
+msgid "-- More --"
+msgstr "-- Mere --"
+
+msgid " SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "
+msgstr " MELLEMRUM/d/j: skærm/side/linje ned, b/u/k: op, q: afslut "
+
+msgid "Question"
+msgstr "Spørgsmål"
+
+msgid ""
+"&Yes\n"
+"&No"
+msgstr ""
+"&Ja\n"
+"&Nej"
+
+msgid ""
+"&Yes\n"
+"&No\n"
+"Save &All\n"
+"&Discard All\n"
+"&Cancel"
+msgstr ""
+"&Ja\n"
+"&Nej\n"
+"Gem &alle\n"
+"&Forkast alle\n"
+"&Annuller"
+
+msgid "Select Directory dialog"
+msgstr "Vælg mappe-dialog"
+
+msgid "Save File dialog"
+msgstr "Gem fil-dialog"
+
+msgid "Open File dialog"
+msgstr "Ã…bn fil-dialog"
+
+msgid "E338: Sorry, no file browser in console mode"
+msgstr "E338: Beklager, ingen filbrowser i konsol-tilstand"
+
+msgid "E766: Insufficient arguments for printf()"
+msgstr "E766: Ikke nok argumenter for printf()"
+
+msgid "E807: Expected Float argument for printf()"
+msgstr "E807: Ventede flydende kommatal-argument for printf()"
+
+msgid "E767: Too many arguments to printf()"
+msgstr "E767: For mange argumenter til printf()"
+
+msgid "W10: Warning: Changing a readonly file"
+msgstr "W10: Advarsel: Ændre en skrivebeskyttet fil"
+
+msgid "Type number and <Enter> or click with mouse (empty cancels): "
+msgstr "Skriv nummer og <Enter> eller klik med musen (tom annullerer): "
+
+msgid "Type number and <Enter> (empty cancels): "
+msgstr "Skriv nummer og <Enter> (tom annullerer): "
+
+msgid "1 more line"
+msgstr "1 linje mere"
+
+msgid "1 line less"
+msgstr "1 linje mindre"
+
+#, c-format
+msgid "%ld more lines"
+msgstr "%ld linjer mere"
+
+#, c-format
+msgid "%ld fewer lines"
+msgstr "%ld linjere mindre"
+
+msgid " (Interrupted)"
+msgstr " (Afbrudt)"
+
+msgid "Beep!"
+msgstr "Bip!"
+
+msgid "ERROR: "
+msgstr "FEJL: "
+
+#, c-format
+msgid ""
+"\n"
+"[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"
+msgstr ""
+"\n"
+"[byte] samlet allok-frigivet %lu-%lu, i brug %lu, spidspunktsbrug %lu\n"
+
+#, c-format
+msgid ""
+"[calls] total re/malloc()'s %lu, total free()'s %lu\n"
+"\n"
+msgstr ""
+"[kald] samlet re/malloc()'er %lu, samlet free()'er %lu\n"
+"\n"
+
+msgid "E340: Line is becoming too long"
+msgstr "E340: Linje er ved at blive for lang"
+
+#, c-format
+msgid "E341: Internal error: lalloc(%ld, )"
+msgstr "E341: Intern fejl: lalloc(%ld, )"
+
+#, c-format
+msgid "E342: Out of memory! (allocating %lu bytes)"
+msgstr "E342: Ikke mere ledig hukommelse! (allokerer %lu byte)"
+
+#, c-format
+msgid "Calling shell to execute: \"%s\""
+msgstr "Kalder skal til udførelse af: \"%s\""
+
+msgid "E545: Missing colon"
+msgstr "E545: Manglende kolon"
+
+msgid "E546: Illegal mode"
+msgstr "E546: Ulovlig tilstand"
+
+msgid "E547: Illegal mouseshape"
+msgstr "E547: Ulovlig museform"
+
+msgid "E548: digit expected"
+msgstr "E548: ciffer ventet"
+
+msgid "E549: Illegal percentage"
+msgstr "E549: Ulovlig procent"
+
+msgid "E854: path too long for completion"
+msgstr "E854: sti for lang til fuldførelse"
+
+#, c-format
+msgid ""
+"E343: Invalid path: '**[number]' must be at the end of the path or be "
+"followed by '%s'."
+msgstr ""
+"E343: Ugyldig sti: '**[nummer]' skal være i slutningen af stien eller "
+"efterfølges af '%s'."
+
+#, c-format
+msgid "E344: Can't find directory \"%s\" in cdpath"
+msgstr "E344: Kan ikke finde mappen \"%s\" i cdpath"
+
+#, c-format
+msgid "E345: Can't find file \"%s\" in path"
+msgstr "E345: Kan ikke finde filen \"%s\" i path"
+
+#, c-format
+msgid "E346: No more directory \"%s\" found in cdpath"
+msgstr "E346: Ikke flere mappe \"%s\" fundet i cdpath"
+
+#, c-format
+msgid "E347: No more file \"%s\" found in path"
+msgstr "E347: Ikke flere fil \"%s\" fundet i path"
+
+#, c-format
+msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\""
+msgstr "E668: Forkert adgangstilstand for NetBeans-forbindelsens info-fil: \"%s\""
+
+#, c-format
+msgid "E658: NetBeans connection lost for buffer %ld"
+msgstr "E658: NetBeans-forbindelse mistet for buffer %ld"
+
+msgid "E838: netbeans is not supported with this GUI"
+msgstr "E838: netbeans understøttes ikke med denne GUI"
+
+msgid "E511: netbeans already connected"
+msgstr "E511: netbeans allerede forbundet"
+
+#, c-format
+msgid "E505: %s is read-only (add ! to override)"
+msgstr "E505: %s er skrivebeskyttet (tilføj ! for at tilsidesætte)"
+
+msgid "E349: No identifier under cursor"
+msgstr "E349: Ingen identifikator under markør"
+
+msgid "E774: 'operatorfunc' is empty"
+msgstr "E774: 'operatorfunc' er tom"
+
+msgid "E775: Eval feature not available"
+msgstr "E775: Eval-funktionalitet ikke tilgængelig"
+
+msgid "Warning: terminal cannot highlight"
+msgstr "Advarsel: terminal kan ikke fremhæve"
+
+msgid "E348: No string under cursor"
+msgstr "E348: Ingen streng under markør"
+
+msgid "E352: Cannot erase folds with current 'foldmethod'"
+msgstr "E352: Kan ikke slette sammenfoldninger med nuværende 'foldmethod'"
+
+msgid "E664: changelist is empty"
+msgstr "E664: ændringsliste er tom"
+
+msgid "E662: At start of changelist"
+msgstr "E662: Ved begyndelsen af ændringsliste"
+
+msgid "E663: At end of changelist"
+msgstr "E663: Ved slutningen af ændringsliste"
+
+msgid "Type :qa! and press <Enter> to abandon all changes and exit Vim"
+msgstr ""
+"Skriv :qa! og tryk på <Enter> for at droppe alle ændringer og afslut Vim"
+
+#, c-format
+msgid "1 line %sed 1 time"
+msgstr "1 linje %sed 1 gang"
+
+#, c-format
+msgid "1 line %sed %d times"
+msgstr "1 linje %sed %d gange"
+
+#, c-format
+msgid "%ld lines %sed 1 time"
+msgstr "%ld linjer %sed 1 gang"
+
+#, c-format
+msgid "%ld lines %sed %d times"
+msgstr "%ld linjer %sed %d gange"
+
+#, c-format
+msgid "%ld lines to indent... "
+msgstr "%ld linjer at indrykke... "
+
+msgid "1 line indented "
+msgstr "1 linje indrykket "
+
+#, c-format
+msgid "%ld lines indented "
+msgstr "%ld linjer indrykket "
+
+msgid "E748: No previously used register"
+msgstr "E748: Intet tidligere brugt register"
+
+msgid "cannot yank; delete anyway"
+msgstr "kan ikke rykke; slet alligevel"
+
+msgid "1 line changed"
+msgstr "1 linje ændret"
+
+#, c-format
+msgid "%ld lines changed"
+msgstr "%ld linjer ændret"
+
+#, c-format
+msgid "freeing %ld lines"
+msgstr "frigør %ld linjer"
+
+#, c-format
+msgid " into \"%c"
+msgstr " i \"%c"
+
+#, c-format
+msgid "block of 1 line yanked%s"
+msgstr "blok på 1 linje rykket%s"
+
+#, c-format
+msgid "1 line yanked%s"
+msgstr "1 linje rykket%s"
+
+#, c-format
+msgid "block of %ld lines yanked%s"
+msgstr "blok på %ld linjer rykket%s"
+
+#, c-format
+msgid "%ld lines yanked%s"
+msgstr "%ld linjer rykket%s"
+
+#, c-format
+msgid "E353: Nothing in register %s"
+msgstr "E353: Intet i register %s"
+
+msgid ""
+"\n"
+"--- Registers ---"
+msgstr ""
+"\n"
+"--- Registre ---"
+
+msgid "Illegal register name"
+msgstr "Ulovligt registernavn"
+
+msgid ""
+"\n"
+"# Registers:\n"
+msgstr ""
+"\n"
+"# Registre:\n"
+
+#, c-format
+msgid "E574: Unknown register type %d"
+msgstr "E574: Ukendt registertype %d"
+
+msgid ""
+"E883: search pattern and expression register may not contain two or more "
+"lines"
+msgstr ""
+"E883: søgemønster og udtryksregister må ikke indeholde to eller flere linjer"
+
+#, c-format
+msgid "%ld Cols; "
+msgstr "%ld kolonner; "
+
+#, c-format
+msgid "Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Bytes"
+msgstr "Markerede %s%ld af %ld linje; %lld af %lld ord; %lld af %lld byte"
+
+#, c-format
+msgid ""
+"Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Chars; %lld of "
+"%lld Bytes"
+msgstr ""
+"Markerede %s%ld af %ld linje; %lld af %lld ord; %lld af %lld tegn; %lld af %"
+"lld byte"
+
+#, c-format
+msgid "Col %s of %s; Line %ld of %ld; Word %lld of %lld; Byte %lld of %lld"
+msgstr "Kol %s af %s; Linje %ld af %ld; Ord %lld af %lld; Byte %lld af %lld"
+
+#, c-format
+msgid ""
+"Col %s of %s; Line %ld of %ld; Word %lld of %lld; Char %lld of %lld; Byte "
+"%lld of %lld"
+msgstr ""
+"Kol %s af %s; Linje %ld af %ld; Ord %lld af %lld; Tegn %lld af %lld; Byte %"
+"lld af %lld"
+
+#, c-format
+msgid "(+%lld for BOM)"
+msgstr "(+%lld for BOM)"
+
+msgid "Thanks for flying Vim"
+msgstr "Tak fordi du fløj med Vim"
+
+msgid "E518: Unknown option"
+msgstr "E518: Ukendt tilvalg"
+
+msgid "E519: Option not supported"
+msgstr "E519: Tilvalg understøttes ikke"
+
+msgid "E520: Not allowed in a modeline"
+msgstr "E520: Ikke tilladt på en tilstandslinje"
+
+msgid "E846: Key code not set"
+msgstr "E846: Tastekode ikke sat"
+
+msgid "E521: Number required after ="
+msgstr "E521: Nummer kræves efter ="
+
+msgid "E522: Not found in termcap"
+msgstr "E522: Ikke fundet i termcap"
+
+#, c-format
+msgid "E539: Illegal character <%s>"
+msgstr "E539: Ulovligt tegn <%s>"
+
+#, c-format
+msgid "For option %s"
+msgstr "For tilvalget %s"
+
+msgid "E529: Cannot set 'term' to empty string"
+msgstr "E529: Kan ikke sætte 'term' til tom streng"
+
+msgid "E530: Cannot change term in GUI"
+msgstr "E530: Kan ikke skifte term i GUI"
+
+msgid "E531: Use \":gui\" to start the GUI"
+msgstr "E531: Brug \":gui\" til at starte GUI'en"
+
+msgid "E589: 'backupext' and 'patchmode' are equal"
+msgstr "E589: 'backupext' og 'patchmode' er ens"
+
+msgid "E834: Conflicts with value of 'listchars'"
+msgstr "E834: Er i konflikt med værdien af 'listchars'"
+
+msgid "E835: Conflicts with value of 'fillchars'"
+msgstr "E835: Er i konflikt med værdien af 'fillchars'"
+
+msgid "E617: Cannot be changed in the GTK+ 2 GUI"
+msgstr "E617: Kan ikke ændres i GTK+ 2 GUI'en"
+
+#, c-format
+msgid "E950: Cannot convert between %s and %s"
+msgstr "E950: Kan ikke konvertere mellem %s og %s"
+
+msgid "E524: Missing colon"
+msgstr "E524: Manglende kolon"
+
+msgid "E525: Zero length string"
+msgstr "E525: Streng uden længde"
+
+#, c-format
+msgid "E526: Missing number after <%s>"
+msgstr "E526: Manglende nummer efter <%s>"
+
+msgid "E527: Missing comma"
+msgstr "E527: Manglende komma"
+
+msgid "E528: Must specify a ' value"
+msgstr "E528: Skal angive en '-værdi"
+
+msgid "E595: contains unprintable or wide character"
+msgstr "E595: indeholder tegn som ikke kan udskrives eller er bredt"
+
+msgid "E596: Invalid font(s)"
+msgstr "E596: Ugyldig skrifttype(r)"
+
+msgid "E597: can't select fontset"
+msgstr "E597: kan ikke vælge skrifttypesæt"
+
+msgid "E598: Invalid fontset"
+msgstr "E598: Ugyldigt skrifttypesæt"
+
+msgid "E533: can't select wide font"
+msgstr "E533: kan ikke vælge bred skrifttype"
+
+msgid "E534: Invalid wide font"
+msgstr "E534: Ugyldig bred skrifttype"
+
+#, c-format
+msgid "E535: Illegal character after <%c>"
+msgstr "E535: Ulovligt tegn efter <%c>"
+
+msgid "E536: comma required"
+msgstr "E536: komma kræves"
+
+#, c-format
+msgid "E537: 'commentstring' must be empty or contain %s"
+msgstr "E537: 'commentstring' skal være tom eller indeholde %s"
+
+msgid "E538: No mouse support"
+msgstr "E538: Ingen understøttelse af mus"
+
+msgid "E540: Unclosed expression sequence"
+msgstr "E540: Ulukket udtryk-sekvens"
+
+msgid "E541: too many items"
+msgstr "E541: for mange punkter"
+
+msgid "E542: unbalanced groups"
+msgstr "E542: ubalancerede grupper"
+
+msgid "E946: Cannot make a terminal with running job modifiable"
+msgstr "E946: Kan ikke gøre en terminal med kørende job ændringsbar"
+
+msgid "E590: A preview window already exists"
+msgstr "E590: Der findes allerede et forhåndsvisningsvindue"
+
+msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'"
+msgstr "W17: Arabisk kræver UTF-8, brug ':set encoding=utf-8'"
+
+msgid "E954: 24-bit colors are not supported on this environment"
+msgstr "E954: 24-bit farver understøttes ikke i dette miljø"
+
+#, c-format
+msgid "E593: Need at least %d lines"
+msgstr "E593: Skal være mindst %d linjer"
+
+#, c-format
+msgid "E594: Need at least %d columns"
+msgstr "E594: Skal være mindst %d kolonner"
+
+#, c-format
+msgid "E355: Unknown option: %s"
+msgstr "E355: Ukendt tilvalg: %s"
+
+#, c-format
+msgid "E521: Number required: &%s = '%s'"
+msgstr "E521: Nummer kræves: &%s = '%s'"
+
+msgid ""
+"\n"
+"--- Terminal codes ---"
+msgstr ""
+"\n"
+"--- Terminal-koder ---"
+
+msgid ""
+"\n"
+"--- Global option values ---"
+msgstr ""
+"\n"
+"--- Værdier for globale tilvalg ---"
+
+msgid ""
+"\n"
+"--- Local option values ---"
+msgstr ""
+"\n"
+"--- Værdier for lokale tilvalg ---"
+
+msgid ""
+"\n"
+"--- Options ---"
+msgstr ""
+"\n"
+"--- Tilvalg ---"
+
+msgid "E356: get_varp ERROR"
+msgstr "E356: Fejl ved get_varp"
+
+#, c-format
+msgid "E357: 'langmap': Matching character missing for %s"
+msgstr "E357: 'langmap': Matchende tegn mangler for %s"
+
+#, c-format
+msgid "E358: 'langmap': Extra characters after semicolon: %s"
+msgstr "E358: 'langmap': Ekstra tegn efter semikolon: %s"
+
+msgid "cannot open "
+msgstr "kan ikke åbne "
+
+msgid "VIM: Can't open window!\n"
+msgstr "VIM: Kan ikke åbne vindue!\n"
+
+msgid "Need Amigados version 2.04 or later\n"
+msgstr "Behøver Amigados version 2.04 eller senere\n"
+
+#, c-format
+msgid "Need %s version %ld\n"
+msgstr "Behøver %s version %ld\n"
+
+msgid "Cannot open NIL:\n"
+msgstr "Kan ikke åbne NIL:\n"
+
+msgid "Cannot create "
+msgstr "Kan ikke oprette "
+
+#, c-format
+msgid "Vim exiting with %d\n"
+msgstr "Vim afsluttede med %d\n"
+
+msgid "cannot change console mode ?!\n"
+msgstr "kan ikke skifte konsoltilstand ?!\n"
+
+msgid "mch_get_shellsize: not a console??\n"
+msgstr "mch_get_shellsize: ikke en konsol??\n"
+
+msgid "E360: Cannot execute shell with -f option"
+msgstr "E360: Kan ikke udføre skal med -f-tilvalget"
+
+msgid "Cannot execute "
+msgstr "Kan ikke udføre "
+
+msgid "shell "
+msgstr "skal "
+
+msgid " returned\n"
+msgstr " returnerede\n"
+
+msgid "ANCHOR_BUF_SIZE too small."
+msgstr "ANCHOR_BUF_SIZE for lille."
+
+msgid "I/O ERROR"
+msgstr "FEJL VED I/O"
+
+msgid "Message"
+msgstr "Meddelelse"
+
+msgid "E237: Printer selection failed"
+msgstr "E237: Valg af printer mislykkedes"
+
+#, c-format
+msgid "to %s on %s"
+msgstr "til %s på %s"
+
+#, c-format
+msgid "E613: Unknown printer font: %s"
+msgstr "E613: Ukendt skrifttype til printer: %s"
+
+#, c-format
+msgid "E238: Print error: %s"
+msgstr "E238: Fejl ved udskrivning: %s"
+
+#, c-format
+msgid "Printing '%s'"
+msgstr "Udskriver '%s'"
+
+#, c-format
+msgid "E244: Illegal charset name \"%s\" in font name \"%s\""
+msgstr "E244: Ulovligt tegnsætnavn \"%s\" i skrifttypenavnet \"%s\""
+
+#, c-format
+msgid "E244: Illegal quality name \"%s\" in font name \"%s\""
+msgstr "E244: Ulovligt kvalitetsnavn \"%s\" i skrifttypenavnet \"%s\""
+
+#, c-format
+msgid "E245: Illegal char '%c' in font name \"%s\""
+msgstr "E245: Ulovligt tegn '%c' i skrifttypenavnet \"%s\""
+
+#, c-format
+msgid "Opening the X display took %ld msec"
+msgstr "Ã…bningen af X-displayet tog %ld ms"
+
+msgid ""
+"\n"
+"Vim: Got X error\n"
+msgstr ""
+"\n"
+"Vim: Fik fejl ved X\n"
+
+msgid "Testing the X display failed"
+msgstr "Test af X-displayet mislykkedes"
+
+msgid "Opening the X display timed out"
+msgstr "Ã…bningen af X-displayet fik timeout"
+
+msgid ""
+"\n"
+"Could not get security context for "
+msgstr ""
+"\n"
+"Kunne ikke hente sikkerhedskontekst for "
+
+msgid ""
+"\n"
+"Could not set security context for "
+msgstr ""
+"\n"
+"Kunne ikke sætte sikkerhedskontekst for "
+
+#, c-format
+msgid "Could not set security context %s for %s"
+msgstr "Kunne ikke sætte sikkerhedskonteksten %s for %s"
+
+#, c-format
+msgid "Could not get security context %s for %s. Removing it!"
+msgstr "Kunne ikke hente sikkerhedskonteksten %s for %s. Fjerner den!"
+
+msgid ""
+"\n"
+"Cannot execute shell sh\n"
+msgstr ""
+"\n"
+"Kan ikke udføre skallen sh\n"
+
+msgid ""
+"\n"
+"shell returned "
+msgstr ""
+"\n"
+"skal returnerede "
+
+msgid ""
+"\n"
+"Cannot create pipes\n"
+msgstr ""
+"\n"
+"Kan ikke oprette pipes\n"
+
+msgid ""
+"\n"
+"Cannot fork\n"
+msgstr ""
+"\n"
+"Kan ikke fork\n"
+
+msgid ""
+"\n"
+"Cannot execute shell "
+msgstr ""
+"\n"
+"Kan ikke udføre skallen "
+
+msgid ""
+"\n"
+"Command terminated\n"
+msgstr ""
+"\n"
+"Kommando termineret\n"
+
+msgid "XSMP lost ICE connection"
+msgstr "XSMP mistede ICE-forbindelse"
+
+#, c-format
+msgid "dlerror = \"%s\""
+msgstr "dlerror = \"%s\""
+
+msgid "Opening the X display failed"
+msgstr "Ã…bningen af X-displayet mislykkedes"
+
+msgid "XSMP handling save-yourself request"
+msgstr "XSMP-håndtering save-yourself-anmodning"
+
+msgid "XSMP opening connection"
+msgstr "XSMP åbner forbindelse"
+
+msgid "XSMP ICE connection watch failed"
+msgstr "XSMP ICE-forbindelse watch mislykkedes"
+
+#, c-format
+msgid "XSMP SmcOpenConnection failed: %s"
+msgstr "XSMP SmcOpenConnection mislykkedes: %s"
+
+msgid "At line"
+msgstr "PÃ¥ linje"
+
+msgid "Could not load vim32.dll!"
+msgstr "Kunne ikke indlæse vim32.dll!"
+
+msgid "VIM Error"
+msgstr "Fejl ved VIM"
+
+msgid "Could not fix up function pointers to the DLL!"
+msgstr "Kunne ikke rette op på funktion-pointere til DLL'en!"
+
+#, c-format
+msgid "Vim: Caught %s event\n"
+msgstr "Vim: Fangede %s-hændelse\n"
+
+msgid "close"
+msgstr "luk"
+
+msgid "logoff"
+msgstr "log ud"
+
+msgid "shutdown"
+msgstr "luk ned"
+
+msgid "E371: Command not found"
+msgstr "E371: Kommando ikke fundet"
+
+msgid ""
+"VIMRUN.EXE not found in your $PATH.\n"
+"External commands will not pause after completion.\n"
+"See :help win32-vimrun for more information."
+msgstr ""
+"VIMRUN.EXE ikke fundet i din $PATH.\n"
+"Eksterne kommandoer sættes ikke på pause efter fuldførelse.\n"
+"Se :help win32-vimrun for mere information."
+
+msgid "Vim Warning"
+msgstr "Advarsel ved Vim"
+
+#, c-format
+msgid "shell returned %d"
+msgstr "skal returnerede %d"
+
+msgid "E926: Current location list was changed"
+msgstr "E926: Nuværende placeringsliste blev ændret"
+
+#, c-format
+msgid "E372: Too many %%%c in format string"
+msgstr "E372: For mange %%%c i formatet streng"
+
+#, c-format
+msgid "E373: Unexpected %%%c in format string"
+msgstr "E373: Uventet %%%c i formatet streng"
+
+msgid "E374: Missing ] in format string"
+msgstr "E374: Manglende ] i formatet streng"
+
+#, c-format
+msgid "E375: Unsupported %%%c in format string"
+msgstr "E375: Ikke-understøttet %%%c i formatet streng"
+
+#, c-format
+msgid "E376: Invalid %%%c in format string prefix"
+msgstr "E376: Ugyldig %%%c i præfiks for formatet streng"
+
+#, c-format
+msgid "E377: Invalid %%%c in format string"
+msgstr "E377: Ugyldig %%%c i formatet streng"
+
+msgid "E378: 'errorformat' contains no pattern"
+msgstr "E378: 'errorformat' indeholder ikke noget mønter"
+
+msgid "E379: Missing or empty directory name"
+msgstr "E379: Manglende eller tomt mappenavn"
+
+msgid "E553: No more items"
+msgstr "E553: Ikke flere punkter"
+
+msgid "E924: Current window was closed"
+msgstr "E924: Nuværende vindue blev lukket"
+
+msgid "E925: Current quickfix was changed"
+msgstr "E925: Nuværende quickfix blev ændret"
+
+#, c-format
+msgid "(%d of %d)%s%s: "
+msgstr "(%d af %d)%s%s: "
+
+msgid " (line deleted)"
+msgstr " (linje slettet)"
+
+#, c-format
+msgid "%serror list %d of %d; %d errors "
+msgstr "%sfejlliste %d af %d; %d fejl "
+
+msgid "E380: At bottom of quickfix stack"
+msgstr "E380: Nederst i quickfix-stakken"
+
+msgid "E381: At top of quickfix stack"
+msgstr "E381: Øverst i quickfix-stakken"
+
+msgid "No entries"
+msgstr "Ingen poster"
+
+msgid "Error file"
+msgstr "Fejlfil"
+
+msgid "E683: File name missing or invalid pattern"
+msgstr "E683: Filnavn mangler eller ugyldigt mønster"
+
+#, c-format
+msgid "Cannot open file \"%s\""
+msgstr "Kan ikke åbne filen \"%s\""
+
+msgid "E681: Buffer is not loaded"
+msgstr "E681: Buffer er ikke indlæst"
+
+msgid "E777: String or List expected"
+msgstr "E777: Streng eller liste ventet"
+
+#, c-format
+msgid "E369: invalid item in %s%%[]"
+msgstr "E369: ugyldigt punkt i %s%%[]"
+
+#, c-format
+msgid "E769: Missing ] after %s["
+msgstr "E769: Manglende ] efter %s["
+
+msgid "E944: Reverse range in character class"
+msgstr "E944: Baglæns område i tegnklasse"
+
+msgid "E945: Range too large in character class"
+msgstr "E945: Område for stort i tegnklasse"
+
+#, c-format
+msgid "E53: Unmatched %s%%("
+msgstr "E53: Ikke-matchet %s%%("
+
+#, c-format
+msgid "E54: Unmatched %s("
+msgstr "E54: Ikke-matchet %s("
+
+#, c-format
+msgid "E55: Unmatched %s)"
+msgstr "E55: Ikke-matchet %s)"
+
+msgid "E66: \\z( not allowed here"
+msgstr "E66: \\z( ikke tilladt her"
+
+msgid "E67: \\z1 et al. not allowed here"
+msgstr "E67: \\z1 og andre ikke tilladt her"
+
+#, c-format
+msgid "E69: Missing ] after %s%%["
+msgstr "E69: Manglende ] efter %s%%["
+
+#, c-format
+msgid "E70: Empty %s%%[]"
+msgstr "E70: Tom %s%%[]"
+
+msgid "E65: Illegal back reference"
+msgstr "E65: Ulovlig tilbage-reference"
+
+msgid "E339: Pattern too long"
+msgstr "E339: Mønster for langt"
+
+msgid "E50: Too many \\z("
+msgstr "E50: For mange \\z("
+
+#, c-format
+msgid "E51: Too many %s("
+msgstr "E51: For mange %s("
+
+msgid "E52: Unmatched \\z("
+msgstr "E52: Ikke-matchet \\z("
+
+#, c-format
+msgid "E59: invalid character after %s@"
+msgstr "E59: ugyldigt tegn efter %s@"
+
+#, c-format
+msgid "E60: Too many complex %s{...}s"
+msgstr "E60: For mange komplekse %s{...}s"
+
+#, c-format
+msgid "E61: Nested %s*"
+msgstr "E61: Indlejret %s*"
+
+#, c-format
+msgid "E62: Nested %s%c"
+msgstr "E62: Indlejret %s%c"
+
+msgid "E63: invalid use of \\_"
+msgstr "E63: ugyldig brug af \\_"
+
+#, c-format
+msgid "E64: %s%c follows nothing"
+msgstr "E64: %s%c efterfølger intet"
+
+msgid "E68: Invalid character after \\z"
+msgstr "E68: Ugyldigt tegn efter \\z"
+
+#, c-format
+msgid "E678: Invalid character after %s%%[dxouU]"
+msgstr "E678: Ugyldigt tegn efter %s%%[dxouU]"
+
+#, c-format
+msgid "E71: Invalid character after %s%%"
+msgstr "E71: Ugyldigt tegn efter %s%%"
+
+#, c-format
+msgid "E554: Syntax error in %s{...}"
+msgstr "E554: Fejl ved syntaks i %s{...}"
+
+msgid "External submatches:\n"
+msgstr "Eksterne undermatch:\n"
+
+#, c-format
+msgid "E888: (NFA regexp) cannot repeat %s"
+msgstr "E888: (NFA regexp) kan ikke gentage %s"
+
+msgid ""
+"E864: \\%#= can only be followed by 0, 1, or 2. The automatic engine will be "
+"used "
+msgstr ""
+"E864: \\%#= må kun efterfølges af 0, 1 eller 2. Bruger den automatiske motor "
+
+msgid "Switching to backtracking RE engine for pattern: "
+msgstr "Skifter til backtracking RE-motor for mønster: "
+
+msgid "E865: (NFA) Regexp end encountered prematurely"
+msgstr "E865: (NFA) Mødte slutningen på regulært udtryk for tidligt"
+
+#, c-format
+msgid "E866: (NFA regexp) Misplaced %c"
+msgstr "E866: (NFA regexp) Forkert placeret %c"
+
+#, c-format
+msgid "E877: (NFA regexp) Invalid character class: %ld"
+msgstr "E877: (NFA regexp) Ugyldig tegnklasse: %ld"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\z%c'"
+msgstr "E867: (NFA) Ukendt operator '\\z%c'"
+
+msgid "E951: \\% value too large"
+msgstr "E951: \\%-værdi for stor"
+
+#, c-format
+msgid "E867: (NFA) Unknown operator '\\%%%c'"
+msgstr "E867: (NFA) Ukendt operator '\\%%%c'"
+
+msgid "E868: Error building NFA with equivalence class!"
+msgstr "E868: Fejl ved bygning af NFA med ligestillet klasse!"
+
+#, c-format
+msgid "E869: (NFA) Unknown operator '\\@%c'"
+msgstr "E869: (NFA) Ukendt operator '\\@%c'"
+
+msgid "E870: (NFA regexp) Error reading repetition limits"
+msgstr "E870: (NFA regexp) Fejl ved læsning af gentagelsesgrænser"
+
+msgid "E871: (NFA regexp) Can't have a multi follow a multi !"
+msgstr "E871: (NFA regexp) En multi må ikke efterfølges af en multi !"
+
+msgid "E872: (NFA regexp) Too many '('"
+msgstr "E872: (NFA regexp) For mange '('"
+
+msgid "E879: (NFA regexp) Too many \\z("
+msgstr "E879: (NFA regexp) For mange \\z("
+
+msgid "E873: (NFA regexp) proper termination error"
+msgstr "E873: (NFA regexp) fejl ved korrekt terminering"
+
+msgid "E874: (NFA) Could not pop the stack !"
+msgstr "E874: (NFA) Kunne ikke pop'e stakken !"
+
+msgid ""
+"E875: (NFA regexp) (While converting from postfix to NFA), too many states "
+"left on stack"
+msgstr ""
+"E875: (NFA regexp) (Ved konvertering fra postfix til NFA), for mange "
+"tilstande tilbage på stak"
+
+msgid "E876: (NFA regexp) Not enough space to store the whole NFA "
+msgstr "E876: (NFA regexp) Ikke nok plads til at lagre hele NFA'en "
+
+msgid "E878: (NFA) Could not allocate memory for branch traversal!"
+msgstr "E878: (NFA) Kunne ikke allokere hukommelse til gennemgang af gren!"
+
+msgid ""
+"Could not open temporary log file for writing, displaying on stderr ... "
+msgstr "Kunne ikke åbne midlertidig logfil til skrivning, viser på stderr ... "
+
+#, c-format
+msgid "(NFA) COULD NOT OPEN %s !"
+msgstr "(NFA) KUNNE IKKE Ã…BNE %s !"
+
+msgid "Could not open temporary log file for writing "
+msgstr "Kunne ikke åbne midlertidig logfil til skrivning "
+
+msgid " VREPLACE"
+msgstr " VERSTAT"
+
+msgid " REPLACE"
+msgstr " ERSTAT"
+
+msgid " REVERSE"
+msgstr " BAGLÆNS"
+
+msgid " INSERT"
+msgstr " INDSÆT"
+
+msgid " (insert)"
+msgstr " (indsæt)"
+
+msgid " (replace)"
+msgstr " (erstat)"
+
+msgid " (vreplace)"
+msgstr " (verstat)"
+
+msgid " Hebrew"
+msgstr " Hebraisk"
+
+msgid " Arabic"
+msgstr " Arabisk"
+
+msgid " (paste)"
+msgstr " (indsæt)"
+
+msgid " VISUAL"
+msgstr " VISUEL"
+
+msgid " VISUAL LINE"
+msgstr " VISUEL LINJE"
+
+msgid " VISUAL BLOCK"
+msgstr " VISUEL BLOK"
+
+msgid " SELECT"
+msgstr " VÆLG"
+
+msgid " SELECT LINE"
+msgstr " VÆLG LINJE"
+
+msgid " SELECT BLOCK"
+msgstr " VÆLG BLOK"
+
+msgid "recording"
+msgstr "optager"
+
+#, c-format
+msgid "E383: Invalid search string: %s"
+msgstr "E383: Ugyldig søgestreng: %s"
+
+#, c-format
+msgid "E384: search hit TOP without match for: %s"
+msgstr "E384: søgning ramte ØVERST uden match for: %s"
+
+#, c-format
+msgid "E385: search hit BOTTOM without match for: %s"
+msgstr "E385: søgning ramte NEDERST uden match for: %s"
+
+msgid "E386: Expected '?' or '/' after ';'"
+msgstr "E386: Ventede '?' eller '/' efter ';'"
+
+msgid " (includes previously listed match)"
+msgstr " (inkluderer tidligere oplistet match)"
+
+msgid "--- Included files "
+msgstr "--- Inkluderede filer "
+
+msgid "not found "
+msgstr "ikke fundet "
+
+msgid "in path ---\n"
+msgstr "i sti ---\n"
+
+msgid " (Already listed)"
+msgstr " (Allerede oplistet)"
+
+msgid " NOT FOUND"
+msgstr " IKKE FUNDET"
+
+#, c-format
+msgid "Scanning included file: %s"
+msgstr "Skanner inkluderede filer: %s"
+
+#, c-format
+msgid "Searching included file %s"
+msgstr "Søger efter inkluderede fil %s"
+
+msgid "E387: Match is on current line"
+msgstr "E387: Match er på nuværende linje"
+
+msgid "All included files were found"
+msgstr "Alle inkluderede filer blev fundet"
+
+msgid "No included files"
+msgstr "Ingen inkluderede filer"
+
+msgid "E388: Couldn't find definition"
+msgstr "E388: Kunne ikke finde definition"
+
+msgid "E389: Couldn't find pattern"
+msgstr "E389: Kunne ikke finde mønster"
+
+msgid "Substitute "
+msgstr "Erstatning "
+
+#, c-format
+msgid ""
+"\n"
+"# Last %sSearch Pattern:\n"
+"~"
+msgstr ""
+"\n"
+"# Sidste %sSøgemønster:\n"
+"~"
+
+msgid "E756: Spell checking is not enabled"
+msgstr "E756: Stavekontrol er ikke aktiveret"
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s_%s.spl\" or \"%s_ascii.spl\""
+msgstr "Advarsel: Kan ikke finde ordlisten \"%s_%s.spl\" eller \"%s_ascii.spl\""
+
+#, c-format
+msgid "Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""
+msgstr "Advarsel: Kan ikke finde ordlisten \"%s.%s.spl\" eller \"%s.ascii.spl\""
+
+msgid "E797: SpellFileMissing autocommand deleted buffer"
+msgstr "E797: SpellFileMissing-autokommando slettede buffer"
+
+#, c-format
+msgid "Warning: region %s not supported"
+msgstr "Advarsel: regionen %s understøttes ikke"
+
+msgid "Sorry, no suggestions"
+msgstr "Beklager, ingen forslag"
+
+#, c-format
+msgid "Sorry, only %ld suggestions"
+msgstr "Beklager, kun %ld forslag"
+
+#, c-format
+msgid "Change \"%.*s\" to:"
+msgstr "Ændr \"%.*s\" til:"
+
+#, c-format
+msgid " < \"%.*s\""
+msgstr " < \"%.*s\""
+
+msgid "E752: No previous spell replacement"
+msgstr "E752: Ingen tidligere staveerstatning"
+
+#, c-format
+msgid "E753: Not found: %s"
+msgstr "E753: Ikke fundet: %s"
+
+msgid "E758: Truncated spell file"
+msgstr "E758: Afkortet spell-fil"
+
+#, c-format
+msgid "Trailing text in %s line %d: %s"
+msgstr "Efterstillede tekst i %s linje %d: %s"
+
+#, c-format
+msgid "Affix name too long in %s line %d: %s"
+msgstr "Affix-navn for langt i %s linje %d: %s"
+
+msgid "E761: Format error in affix file FOL, LOW or UPP"
+msgstr "E761: Fejl i format i affix-filens FOL, LOW eller UPP"
+
+msgid "E762: Character in FOL, LOW or UPP is out of range"
+msgstr "E762: Tegn i FOL, LOW eller UPP er udenfor område"
+
+msgid "Compressing word tree..."
+msgstr "Komprimerer ordtræ..."
+
+#, c-format
+msgid "Reading spell file \"%s\""
+msgstr "Læser spell-filen \"%s\""
+
+msgid "E757: This does not look like a spell file"
+msgstr "E757: Det ligner ikke en spell-fil"
+
+msgid "E771: Old spell file, needs to be updated"
+msgstr "E771: Gammel spell-fil, som skal opdateres"
+
+msgid "E772: Spell file is for newer version of Vim"
+msgstr "E772: Spell-filen er til en nyere version af Vim"
+
+msgid "E770: Unsupported section in spell file"
+msgstr "E770: Ikke-understøttet sektion i spell-fil"
+
+#, c-format
+msgid "E778: This does not look like a .sug file: %s"
+msgstr "E778: ligner ikke en .sug-fil: %s"
+
+#, c-format
+msgid "E779: Old .sug file, needs to be updated: %s"
+msgstr "E779: Gammel .sug-fil, som skal opdateres: %s"
+
+#, c-format
+msgid "E780: .sug file is for newer version of Vim: %s"
+msgstr "E780: .sug-filen er til en nyere version af Vim: %s"
+
+#, c-format
+msgid "E781: .sug file doesn't match .spl file: %s"
+msgstr "E781: .sug-filen matcher ikke .spl-filen: %s"
+
+#, c-format
+msgid "E782: error while reading .sug file: %s"
+msgstr "E782: fejl ved læsning af .sug-fil: %s"
+
+#, c-format
+msgid "Reading affix file %s ..."
+msgstr "Læser affix-filen %s ..."
+
+#, c-format
+msgid "Conversion failure for word in %s line %d: %s"
+msgstr "Mislykkede konvertering for ordet %s linje %d: %s"
+
+#, c-format
+msgid "Conversion in %s not supported: from %s to %s"
+msgstr "Konvertering i %s understøttes ikke: fra %s til %s"
+
+#, c-format
+msgid "Conversion in %s not supported"
+msgstr "Konvertering i %s understøttes ikke"
+
+#, c-format
+msgid "Invalid value for FLAG in %s line %d: %s"
+msgstr "Ugyldig værdi for FLAG i %s linje %d: %s"
+
+#, c-format
+msgid "FLAG after using flags in %s line %d: %s"
+msgstr "FLAG efter brug af flag i %s linje %d: %s"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"Definering af COMPOUNDFORBIDFLAG efter PFX-punkt kan give forkerte "
+"resultater i %s linje %d"
+
+#, c-format
+msgid ""
+"Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line "
+"%d"
+msgstr ""
+"Definering af COMPOUNDPERMITFLAG efter PFX-punkt kan give forkerte "
+"resultater i %s linje %d"
+
+#, c-format
+msgid "Wrong COMPOUNDRULES value in %s line %d: %s"
+msgstr "Forkert COMPOUNDRULES-værdi i %s linje %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDWORDMAX value in %s line %d: %s"
+msgstr "Forkert COMPOUNDWORDMAX-værdi i %s linje %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDMIN value in %s line %d: %s"
+msgstr "Forkert COMPOUNDMIN-værdi i %s linje %d: %s"
+
+#, c-format
+msgid "Wrong COMPOUNDSYLMAX value in %s line %d: %s"
+msgstr "Forkert COMPOUNDSYLMAX-værdi i %s linje %d: %s"
+
+#, c-format
+msgid "Wrong CHECKCOMPOUNDPATTERN value in %s line %d: %s"
+msgstr "Forkert CHECKCOMPOUNDPATTERN-værdi i %s linje %d: %s"
+
+#, c-format
+msgid "Different combining flag in continued affix block in %s line %d: %s"
+msgstr "Forskellige kombineringsflag i fortsat affix-blok i %s linje %d: %s"
+
+#, c-format
+msgid "Duplicate affix in %s line %d: %s"
+msgstr "Duplikeret affix i %s linje %d: %s"
+
+#, c-format
+msgid ""
+"Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in %s "
+"line %d: %s"
+msgstr ""
+"Affix også brugt for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST i %s "
+"linje %d: %s"
+
+#, c-format
+msgid "Expected Y or N in %s line %d: %s"
+msgstr "Ventede Y eller N i %s linje %d: %s"
+
+#, c-format
+msgid "Broken condition in %s line %d: %s"
+msgstr "Ødelagt betingelse i %s linje %d: %s"
+
+#, c-format
+msgid "Expected REP(SAL) count in %s line %d"
+msgstr "Ventede REP(SAL)-tælling i %s linje %d"
+
+#, c-format
+msgid "Expected MAP count in %s line %d"
+msgstr "Ventede MAP-tælling i %s linje %d"
+
+#, c-format
+msgid "Duplicate character in MAP in %s line %d"
+msgstr "Duplikeret tegn i MAP i %s linje %d"
+
+#, c-format
+msgid "Unrecognized or duplicate item in %s line %d: %s"
+msgstr "Ikke-genkendt eller duplikeret punkt i %s linje %d: %s"
+
+#, c-format
+msgid "Missing FOL/LOW/UPP line in %s"
+msgstr "Manglende FOL-/LOW-/UPP-linje i %s"
+
+msgid "COMPOUNDSYLMAX used without SYLLABLE"
+msgstr "COMPOUNDSYLMAX brugt uden SYLLABLE"
+
+msgid "Too many postponed prefixes"
+msgstr "For mange udskudte præfikser"
+
+msgid "Too many compound flags"
+msgstr "For mange compound-flag"
+
+msgid "Too many postponed prefixes and/or compound flags"
+msgstr "For mange udskudte præfikser og/eller compound-flag"
+
+#, c-format
+msgid "Missing SOFO%s line in %s"
+msgstr "Manglende SOFO%s-linje i %s"
+
+#, c-format
+msgid "Both SAL and SOFO lines in %s"
+msgstr "BÃ¥de SAL- og SOFO-linjer i %s"
+
+#, c-format
+msgid "Flag is not a number in %s line %d: %s"
+msgstr "Flag er ikke et nummer i %s linje %d: %s"
+
+#, c-format
+msgid "Illegal flag in %s line %d: %s"
+msgstr "Ulovligt flag i %s linje %d: %s"
+
+#, c-format
+msgid "%s value differs from what is used in another .aff file"
+msgstr "%s-værdi er ikke den samme som bruges i en anden .aff-fil"
+
+#, c-format
+msgid "Reading dictionary file %s ..."
+msgstr "Læser ordbogsfilen %s ..."
+
+#, c-format
+msgid "E760: No word count in %s"
+msgstr "E760: Ingen ordtælling i %s"
+
+#, c-format
+msgid "line %6d, word %6ld - %s"
+msgstr "linje %6d, ord %6ld - %s"
+
+#, c-format
+msgid "Duplicate word in %s line %d: %s"
+msgstr "Duplikeret ord i %s linje %d: %s"
+
+#, c-format
+msgid "First duplicate word in %s line %d: %s"
+msgstr "Første duplikeret ord i %s linje %d: %s"
+
+#, c-format
+msgid "%d duplicate word(s) in %s"
+msgstr "%d duplikeret ord i %s"
+
+#, c-format
+msgid "Ignored %d word(s) with non-ASCII characters in %s"
+msgstr "Ignorerede %d ord med ikke-ASCII-tegn i %s"
+
+#, c-format
+msgid "Reading word file %s ..."
+msgstr "Læser ordfilen %s ..."
+
+#, c-format
+msgid "Duplicate /encoding= line ignored in %s line %d: %s"
+msgstr "Duplikeret /encoding=-linje ignoreret i %s linje %d: %s"
+
+#, c-format
+msgid "/encoding= line after word ignored in %s line %d: %s"
+msgstr "/encoding=-linje efter ord ignoreret i %s linje %d: %s"
+
+#, c-format
+msgid "Duplicate /regions= line ignored in %s line %d: %s"
+msgstr "Duplikerede /regions=-linjer ignoreret i %s linje %d: %s"
+
+#, c-format
+msgid "Too many regions in %s line %d: %s"
+msgstr "For mange regioner i %s linje %d: %s"
+
+#, c-format
+msgid "/ line ignored in %s line %d: %s"
+msgstr "/-linje ignoreret i %s linje %d: %s"
+
+#, c-format
+msgid "Invalid region nr in %s line %d: %s"
+msgstr "Ugyldigt regisionsnummer i %s linje %d: %s"
+
+#, c-format
+msgid "Unrecognized flags in %s line %d: %s"
+msgstr "Ugenkendte flag i %s linje %d: %s"
+
+#, c-format
+msgid "Ignored %d words with non-ASCII characters"
+msgstr "Ignorerer %d ord med ikke-ASCII-tegn"
+
+msgid "E845: Insufficient memory, word list will be incomplete"
+msgstr "E845: Ikke nok hukommelse, ordlisten vil være ufuldstændig"
+
+#, c-format
+msgid "Compressed %d of %d nodes; %d (%d%%) remaining"
+msgstr "Komprimerede %d af %d punkter; %d (%d%%) tilbage"
+
+msgid "Reading back spell file..."
+msgstr "Læser spell-fil tilbage..."
+
+msgid "Performing soundfolding..."
+msgstr "Udfører lydsammenfoldning..."
+
+#, c-format
+msgid "Number of words after soundfolding: %ld"
+msgstr "Antal ord efter lydsammenfoldning: %ld"
+
+#, c-format
+msgid "Total number of words: %d"
+msgstr "Samlet antal ord: %d"
+
+#, c-format
+msgid "Writing suggestion file %s ..."
+msgstr "Skriver forslagsfilen %s ..."
+
+#, c-format
+msgid "Estimated runtime memory use: %d bytes"
+msgstr "Anslået brug af afviklingshukommelse: %d byte"
+
+msgid "E751: Output file name must not have region name"
+msgstr "E751: Outputfilnavn må ikke have regionsnavn"
+
+#, c-format
+msgid "E754: Only up to %ld regions supported"
+msgstr "E754: Kun op til %ld regioner understøttes"
+
+#, c-format
+msgid "E755: Invalid region in %s"
+msgstr "E755: Ugyldig region i %s"
+
+msgid "Warning: both compounding and NOBREAK specified"
+msgstr "Advarsel: både compounding og NOBREAK angivet"
+
+#, c-format
+msgid "Writing spell file %s ..."
+msgstr "Skriver spell-filen %s ..."
+
+msgid "Done!"
+msgstr "Færdig!"
+
+#, c-format
+msgid "E765: 'spellfile' does not have %ld entries"
+msgstr "E765: 'spellfile' har ingen %ld-poster"
+
+#, c-format
+msgid "Word '%.*s' removed from %s"
+msgstr "Ordet '%.*s' fjernet fra %s"
+
+#, c-format
+msgid "Word '%.*s' added to %s"
+msgstr "Ordet '%.*s' tilføjet til %s"
+
+msgid "E763: Word characters differ between spell files"
+msgstr "E763: Ordtegn er ikke ens i spell-filer"
+
+msgid "E783: duplicate char in MAP entry"
+msgstr "E783: duplikeret tegn i MAP-post"
+
+msgid "No Syntax items defined for this buffer"
+msgstr "Ingen syntakspunkter defineret for denne buffer"
+
+msgid "syntax conceal on"
+msgstr "syntax conceal on"
+
+msgid "syntax conceal off"
+msgstr "syntax conceal off"
+
+#, c-format
+msgid "E390: Illegal argument: %s"
+msgstr "E390: Ulovligt argument: %s"
+
+msgid "syntax case ignore"
+msgstr "syntax case ignore"
+
+msgid "syntax case match"
+msgstr "syntax case match"
+
+msgid "syntax spell toplevel"
+msgstr "syntax spell toplevel"
+
+msgid "syntax spell notoplevel"
+msgstr "syntax spell notoplevel"
+
+msgid "syntax spell default"
+msgstr "syntax spell default"
+
+msgid "syntax iskeyword "
+msgstr "syntax iskeyword "
+
+#, c-format
+msgid "E391: No such syntax cluster: %s"
+msgstr "E391: Ingen sådan syntaks-cluster: %s"
+
+msgid "syncing on C-style comments"
+msgstr "synkronisering på C-style-kommentarer"
+
+msgid "no syncing"
+msgstr "ingen synkronisering"
+
+msgid "syncing starts "
+msgstr "synkronisering starter "
+
+msgid " lines before top line"
+msgstr " linjer inden øverste linje"
+
+msgid ""
+"\n"
+"--- Syntax sync items ---"
+msgstr ""
+"\n"
+"--- Syntaks-synkroniseringspunkter ---"
+
+msgid ""
+"\n"
+"syncing on items"
+msgstr ""
+"\n"
+"synkroniserer på punkter"
+
+msgid ""
+"\n"
+"--- Syntax items ---"
+msgstr ""
+"\n"
+"--- Syntakspunkter ---"
+
+#, c-format
+msgid "E392: No such syntax cluster: %s"
+msgstr "E392: Ingen sådan syntaks-cluster: %s"
+
+msgid "minimal "
+msgstr "minimal "
+
+msgid "maximal "
+msgstr "maksimal "
+
+msgid "; match "
+msgstr "; match "
+
+msgid " line breaks"
+msgstr " linjeombrydninger"
+
+msgid "E395: contains argument not accepted here"
+msgstr "E395: indeholder argument som ikke accepteres her"
+
+msgid "E844: invalid cchar value"
+msgstr "E844: ugyldig cchar-værdi"
+
+msgid "E393: group[t]here not accepted here"
+msgstr "E393: group[t]here accepteres ikke her"
+
+#, c-format
+msgid "E394: Didn't find region item for %s"
+msgstr "E394: Find ikke regionspunkter for %s"
+
+msgid "E397: Filename required"
+msgstr "E397: Filnavn kræves"
+
+msgid "E847: Too many syntax includes"
+msgstr "E847: For mange syntaks inkluderinger"
+
+#, c-format
+msgid "E789: Missing ']': %s"
+msgstr "E789: Manglende ']': %s"
+
+#, c-format
+msgid "E890: trailing char after ']': %s]%s"
+msgstr "E890: efterstillede tegn efter ']': %s]%s"
+
+#, c-format
+msgid "E398: Missing '=': %s"
+msgstr "E398: Manglende '=': %s"
+
+#, c-format
+msgid "E399: Not enough arguments: syntax region %s"
+msgstr "E399: For mange argumenter: syntaks region %s"
+
+msgid "E848: Too many syntax clusters"
+msgstr "E848: For mange syntaks-clusters"
+
+msgid "E400: No cluster specified"
+msgstr "E400: Ingen cluster angivet"
+
+#, c-format
+msgid "E401: Pattern delimiter not found: %s"
+msgstr "E401: Mønsterafgrænser ikke fundet: %s"
+
+#, c-format
+msgid "E402: Garbage after pattern: %s"
+msgstr "E402: Affald efter mønster: %s"
+
+msgid "E403: syntax sync: line continuations pattern specified twice"
+msgstr ""
+"E403: syntaks synkronisering: linjefortsættelsesmønster angivet to gange"
+
+#, c-format
+msgid "E404: Illegal arguments: %s"
+msgstr "E404: Ulovlige argumenter: %s"
+
+#, c-format
+msgid "E405: Missing equal sign: %s"
+msgstr "E405: Manglende lighedstegn: %s"
+
+#, c-format
+msgid "E406: Empty argument: %s"
+msgstr "E406: Tomt argument: %s"
+
+#, c-format
+msgid "E407: %s not allowed here"
+msgstr "E407: %s ikke tilladt her"
+
+#, c-format
+msgid "E408: %s must be first in contains list"
+msgstr "E408: %s skal være først i contains-liste"
+
+#, c-format
+msgid "E409: Unknown group name: %s"
+msgstr "E409: Ukendt gruppenavn: %s"
+
+#, c-format
+msgid "E410: Invalid :syntax subcommand: %s"
+msgstr "E410: Ugyldig :syntax-underkommando: %s"
+
+msgid ""
+" TOTAL COUNT MATCH SLOWEST AVERAGE NAME PATTERN"
+msgstr ""
+" SAMLET ANTAL MATCH LANGSOMST GENNEMS. NAVN MØNSTER"
+
+msgid "E679: recursive loop loading syncolor.vim"
+msgstr "E679: rekursiv løkke ved indlæsning af syncolor.vim"
+
+#, c-format
+msgid "E411: highlight group not found: %s"
+msgstr "E411: fremhævningsgruppe ikke fundet: %s"
+
+#, c-format
+msgid "E412: Not enough arguments: \":highlight link %s\""
+msgstr "E412: Ikke nok argumenter: \":highlight link %s\""
+
+#, c-format
+msgid "E413: Too many arguments: \":highlight link %s\""
+msgstr "E413: For mange argumenter: \":highlight link %s\""
+
+msgid "E414: group has settings, highlight link ignored"
+msgstr "E414: gruppe har indstillinger, highlight link ignoreret"
+
+#, c-format
+msgid "E415: unexpected equal sign: %s"
+msgstr "E415: uventet lighedstegn: %s"
+
+#, c-format
+msgid "E416: missing equal sign: %s"
+msgstr "E416: manglende lighedstegn: %s"
+
+#, c-format
+msgid "E417: missing argument: %s"
+msgstr "E417: manglende argument: %s"
+
+#, c-format
+msgid "E418: Illegal value: %s"
+msgstr "E418: Ulovlig værdi: %s"
+
+msgid "E419: FG color unknown"
+msgstr "E419: Forgrundsfarve ukendt"
+
+msgid "E420: BG color unknown"
+msgstr "E420: Baggrundsfarve ukendt"
+
+#, c-format
+msgid "E421: Color name or number not recognized: %s"
+msgstr "E421: Farvenavn eller -nummer ikke genkendt: %s"
+
+#, c-format
+msgid "E422: terminal code too long: %s"
+msgstr "E422: terminalkode for lang: %s"
+
+#, c-format
+msgid "E423: Illegal argument: %s"
+msgstr "E423: Ulovligt argument: %s"
+
+msgid "E424: Too many different highlighting attributes in use"
+msgstr "E424: For mange forskellige fremhævningsattributter i brug"
+
+msgid "E669: Unprintable character in group name"
+msgstr "E669: Tegn som ikke kan udskrives i gruppenavn"
+
+msgid "W18: Invalid character in group name"
+msgstr "W18: Ugyldige tegn i gruppenavn"
+
+msgid "E849: Too many highlight and syntax groups"
+msgstr "E849: For mange fremhævnings- og syntaksgrupper"
+
+msgid "E555: at bottom of tag stack"
+msgstr "E555: nederst i tag-stak"
+
+msgid "E556: at top of tag stack"
+msgstr "E556: øverst i tag-stak"
+
+msgid "E425: Cannot go before first matching tag"
+msgstr "E425: Kan ikke gå efter første matchende tag"
+
+#, c-format
+msgid "E426: tag not found: %s"
+msgstr "E426: tag ikke fundet: %s"
+
+msgid " # pri kind tag"
+msgstr " # pri kind tag"
+
+msgid "file\n"
+msgstr "fil\n"
+
+msgid "E427: There is only one matching tag"
+msgstr "E427: Der er kun ét matchende tag"
+
+msgid "E428: Cannot go beyond last matching tag"
+msgstr "E428: Kan ikke gå efter sidste matchende tag"
+
+#, c-format
+msgid "File \"%s\" does not exist"
+msgstr "Filen \"%s\" findes ikke"
+
+#, c-format
+msgid "tag %d of %d%s"
+msgstr "tag %d af %d%s"
+
+msgid " or more"
+msgstr " eller flere"
+
+msgid " Using tag with different case!"
+msgstr " Bruger tag med anden versaltype!"
+
+#, c-format
+msgid "E429: File \"%s\" does not exist"
+msgstr "E429: Filen \"%s\" findes ikke"
+
+msgid ""
+"\n"
+" # TO tag FROM line in file/text"
+msgstr ""
+"\n"
+" # TIL tag FRA linje i fil/tekst"
+
+#, c-format
+msgid "Searching tags file %s"
+msgstr "Søger i tags-filen %s"
+
+#, c-format
+msgid "E430: Tag file path truncated for %s\n"
+msgstr "E430: Tag-filens sti afkortet for %s\n"
+
+msgid "Ignoring long line in tags file"
+msgstr "Ignorerer lang linje i tags-fil"
+
+#, c-format
+msgid "E431: Format error in tags file \"%s\""
+msgstr "E431: Fejl ved format i tags-filen \"%s\""
+
+#, c-format
+msgid "Before byte %ld"
+msgstr "Inden byte %ld"
+
+#, c-format
+msgid "E432: Tags file not sorted: %s"
+msgstr "E432: Tags-fil ikke sorteret: %s"
+
+msgid "E433: No tags file"
+msgstr "E433: Ingen tags-fil"
+
+msgid "E434: Can't find tag pattern"
+msgstr "E434: Kan ikke finde tag-mønster"
+
+msgid "E435: Couldn't find tag, just guessing!"
+msgstr "E435: Kunne ikke finde tag, gætter bare!"
+
+#, c-format
+msgid "Duplicate field name: %s"
+msgstr "Duplikeret feltnavn: %s"
+
+msgid "' not known. Available builtin terminals are:"
+msgstr "' ikke kendt. Tilgængelige indbyggede terminaler:"
+
+msgid "defaulting to '"
+msgstr "bruger standarden '"
+
+msgid "E557: Cannot open termcap file"
+msgstr "E557: Kan ikke åbne termcap-fil"
+
+msgid "E558: Terminal entry not found in terminfo"
+msgstr "E558: Terminal-post ikke fundet i terminfo"
+
+msgid "E559: Terminal entry not found in termcap"
+msgstr "E559: Terminal-post ikke fundet i termcap"
+
+#, c-format
+msgid "E436: No \"%s\" entry in termcap"
+msgstr "E436: Ingen \"%s\"-post i termcap"
+
+msgid "E437: terminal capability \"cm\" required"
+msgstr "E437: terminal-formåenheden \"cm\" kræves"
+
+msgid ""
+"\n"
+"--- Terminal keys ---"
+msgstr ""
+"\n"
+"--- Terminal-taster ---"
+
+msgid "Cannot open $VIMRUNTIME/rgb.txt"
+msgstr "Kan ikke åbne $VIMRUNTIME/rgb.txt"
+
+#, c-format
+msgid "Kill job in \"%s\"?"
+msgstr "Dræb job i \"%s\"?"
+
+msgid "Terminal"
+msgstr "Terminal"
+
+msgid "Terminal-finished"
+msgstr "Terminal-færdig"
+
+msgid "active"
+msgstr "aktiv"
+
+msgid "running"
+msgstr "køre"
+
+msgid "finished"
+msgstr "færdig"
+
+#, c-format
+msgid "E953: File exists: %s"
+msgstr "E953: Filen findes: %s"
+
+msgid "E955: Not a terminal buffer"
+msgstr "E955: Ikke en terminal-buffer"
+
+msgid "new shell started\n"
+msgstr "ny skal startet\n"
+
+msgid "Vim: Error reading input, exiting...\n"
+msgstr "Vim: Fejl ved læsning af input, afslutter...\n"
+
+msgid "Used CUT_BUFFER0 instead of empty selection"
+msgstr "Brugte CUT_BUFFER0 i stedet for tom markering"
+
+msgid "E881: Line count changed unexpectedly"
+msgstr "E881: Linjeantal ændret uventet"
+
+msgid "No undo possible; continue anyway"
+msgstr "Ingen fortryd mulig; fortsætter alligevel"
+
+#, c-format
+msgid "E828: Cannot open undo file for writing: %s"
+msgstr "E828: Kan ikke åbne fortrydelsesfil til skrivning: %s"
+
+#, c-format
+msgid "E825: Corrupted undo file (%s): %s"
+msgstr "E825: Korrupt fortrydelsesfil (%s): %s"
+
+msgid "Cannot write undo file in any directory in 'undodir'"
+msgstr "Kan ikke skrive fortrydelsesfil i nogen mappe i 'undodir'"
+
+#, c-format
+msgid "Will not overwrite with undo file, cannot read: %s"
+msgstr "Overskriver ikke med fortrydelsesfil, kan ikke læse: %s"
+
+#, c-format
+msgid "Will not overwrite, this is not an undo file: %s"
+msgstr "Overskriver ikke, det er ikke en fortrydelsesfil: %s"
+
+msgid "Skipping undo file write, nothing to undo"
+msgstr "Springer skrivning af fortrydelsesfil over, intet at fortryde"
+
+#, c-format
+msgid "Writing undo file: %s"
+msgstr "Skriver fortrydelsesfil: %s"
+
+#, c-format
+msgid "E829: write error in undo file: %s"
+msgstr "E829: fejl ved skrivning i fortrydelsesfil: %s"
+
+#, c-format
+msgid "Not reading undo file, owner differs: %s"
+msgstr "Læser ikke fortrydelsesfil, ejer er ikke den samme: %s"
+
+#, c-format
+msgid "Reading undo file: %s"
+msgstr "Læser fortrydelsesfil: %s"
+
+#, c-format
+msgid "E822: Cannot open undo file for reading: %s"
+msgstr "E822: Kan ikke åbne fortrydelsesfil til læsning: %s"
+
+#, c-format
+msgid "E823: Not an undo file: %s"
+msgstr "E823: Ikke en fortrydelsesfil: %s"
+
+#, c-format
+msgid "E832: Non-encrypted file has encrypted undo file: %s"
+msgstr "E832: Ikke-krypteret fil har krypteret fortrydelsesfil: %s"
+
+#, c-format
+msgid "E826: Undo file decryption failed: %s"
+msgstr "E826: Dekryptering af fortrydelsesfil mislykkedes: %s"
+
+#, c-format
+msgid "E827: Undo file is encrypted: %s"
+msgstr "E827: Fortrydelsesfilen er krypteret: %s"
+
+#, c-format
+msgid "E824: Incompatible undo file: %s"
+msgstr "E824: Inkompatibel fortrydelsesfil: %s"
+
+msgid "File contents changed, cannot use undo info"
+msgstr "Filindholdet ændret, kan ikke bruge fortrydelsesinfo"
+
+#, c-format
+msgid "Finished reading undo file %s"
+msgstr "Færdig med at læse fortrydelsesfilen %s"
+
+msgid "Already at oldest change"
+msgstr "Allerede ved ældste ændring"
+
+msgid "Already at newest change"
+msgstr "Allerede ved nyeste ændring"
+
+#, c-format
+msgid "E830: Undo number %ld not found"
+msgstr "E830: Fortrydelsesnummer %ld ikke fundet"
+
+msgid "E438: u_undo: line numbers wrong"
+msgstr "E438: u_undo: linjenumre forkerte"
+
+msgid "more line"
+msgstr "linje mere"
+
+msgid "more lines"
+msgstr "linjer mere"
+
+msgid "line less"
+msgstr "linje mindre"
+
+msgid "fewer lines"
+msgstr "linjere mindre"
+
+msgid "change"
+msgstr "ændring"
+
+msgid "changes"
+msgstr "ændringer"
+
+#, c-format
+msgid "%ld %s; %s #%ld %s"
+msgstr "%ld %s; %s #%ld %s"
+
+msgid "before"
+msgstr "inden"
+
+msgid "after"
+msgstr "efter"
+
+msgid "Nothing to undo"
+msgstr "Intet at fortryde"
+
+msgid "number changes when saved"
+msgstr "nummer ændrin. hvornår gemt"
+
+#, c-format
+msgid "%ld seconds ago"
+msgstr "%ld sekunder siden"
+
+msgid "E790: undojoin is not allowed after undo"
+msgstr "E790: undojoin ikke tilladt efter undo"
+
+msgid "E439: undo list corrupt"
+msgstr "E439: fortrydelsesliste korrupt"
+
+msgid "E440: undo line missing"
+msgstr "E440: fortrydelseslinje mangler"
+
+#, c-format
+msgid "E122: Function %s already exists, add ! to replace it"
+msgstr "E122: Funktionen %s findes allerede, tilføj ! for at erstatte den"
+
+msgid "E717: Dictionary entry already exists"
+msgstr "E717: Ordbog-post findes allerede"
+
+msgid "E718: Funcref required"
+msgstr "E718: Funcref kræves"
+
+#, c-format
+msgid "E130: Unknown function: %s"
+msgstr "E130: Ukendt funktion: %s"
+
+#, c-format
+msgid "E125: Illegal argument: %s"
+msgstr "E125: Ulovligt argument: %s"
+
+#, c-format
+msgid "E853: Duplicate argument name: %s"
+msgstr "E853: Duplikeret argumentnavn: %s"
+
+#, c-format
+msgid "E740: Too many arguments for function %s"
+msgstr "E740: For mange argumenter til funktionen %s"
+
+#, c-format
+msgid "E116: Invalid arguments for function %s"
+msgstr "E116: Ugyldige argumenter til funktionen %s"
+
+msgid "E132: Function call depth is higher than 'maxfuncdepth'"
+msgstr "E132: Dybden af funktionskald er større end 'maxfuncdepth'"
+
+#, c-format
+msgid "calling %s"
+msgstr "kalder %s"
+
+#, c-format
+msgid "%s aborted"
+msgstr "%s afbrudt"
+
+#, c-format
+msgid "%s returning #%ld"
+msgstr "%s returnerer #%ld"
+
+#, c-format
+msgid "%s returning %s"
+msgstr "%s returnerer %s"
+
+msgid "E699: Too many arguments"
+msgstr "E699: For mange argumenter"
+
+#, c-format
+msgid "E117: Unknown function: %s"
+msgstr "E117: Ukendt funktion: %s"
+
+#, c-format
+msgid "E933: Function was deleted: %s"
+msgstr "E933: Funktion blev slettet: %s"
+
+#, c-format
+msgid "E119: Not enough arguments for function: %s"
+msgstr "E119: Ikke nok argumenter til funktionen: %s"
+
+#, c-format
+msgid "E120: Using <SID> not in a script context: %s"
+msgstr "E120: Bruger <SID> ikke i et script kontekst: %s"
+
+#, c-format
+msgid "E725: Calling dict function without Dictionary: %s"
+msgstr "E725: Kalder dict-funktion uden ordbog: %s"
+
+msgid "E129: Function name required"
+msgstr "E129: Funktionsnavn kræves"
+
+#, c-format
+msgid "E128: Function name must start with a capital or \"s:\": %s"
+msgstr "E128: Funktionsnavnet skal begynde med et stort bogstav eller \"s:\": %s"
+
+#, c-format
+msgid "E884: Function name cannot contain a colon: %s"
+msgstr "E884: Funktionsnavnet må ikke indeholdet et kolon: %s"
+
+#, c-format
+msgid "E123: Undefined function: %s"
+msgstr "E123: Udefineret funktion: %s"
+
+#, c-format
+msgid "E124: Missing '(': %s"
+msgstr "E124: Manglende '(': %s"
+
+msgid "E862: Cannot use g: here"
+msgstr "E862: Kan ikke bruge g: her"
+
+#, c-format
+msgid "E932: Closure function should not be at top level: %s"
+msgstr "E932: Closure-funktion skal ikke være på topniveau: %s"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: Manglende :endfunction"
+
+#, c-format
+msgid "W22: Text found after :endfunction: %s"
+msgstr "W22: Tekst fundet efter :endfunction: %s"
+
+#, c-format
+msgid "E707: Function name conflicts with variable: %s"
+msgstr "E707: Funktionsnavnet er i konflikt med variablen: %s"
+
+#, c-format
+msgid "E127: Cannot redefine function %s: It is in use"
+msgstr "E127: Kan ikke redefinere funktionen %s: Den er i brug"
+
+#, c-format
+msgid "E746: Function name does not match script file name: %s"
+msgstr "E746: Funktionsnavn matcher ikke scriptfilnavn: %s"
+
+#, c-format
+msgid "E131: Cannot delete function %s: It is in use"
+msgstr "E131: Kan ikke slette funktionen %s: Den er i brug"
+
+msgid "E133: :return not inside a function"
+msgstr "E133: :return ikke i en funktion"
+
+#, c-format
+msgid "E107: Missing parentheses: %s"
+msgstr "E107: Manglende parenteser: %s"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit GUI version"
+msgstr ""
+"\n"
+"MS-Windows 64-bit GUI-version"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit GUI version"
+msgstr ""
+"\n"
+"MS-Windows 32-bit GUI-version"
+
+msgid " with OLE support"
+msgstr " med understøttelse af OLE"
+
+msgid ""
+"\n"
+"MS-Windows 64-bit console version"
+msgstr ""
+"\n"
+"MS-Windows 64-bit konsol-version"
+
+msgid ""
+"\n"
+"MS-Windows 32-bit console version"
+msgstr ""
+"\n"
+"MS-Windows 32-bit konsol-version"
+
+msgid ""
+"\n"
+"macOS version"
+msgstr ""
+"\n"
+"macOS-version"
+
+msgid ""
+"\n"
+"macOS version w/o darwin feat."
+msgstr ""
+"\n"
+"macOS-version med/uden darwin-funktionalitet."
+
+msgid ""
+"\n"
+"OpenVMS version"
+msgstr ""
+"\n"
+"OpenVMS-version"
+
+msgid ""
+"\n"
+"Included patches: "
+msgstr ""
+"\n"
+"Rettelser som er med: "
+
+msgid ""
+"\n"
+"Extra patches: "
+msgstr ""
+"\n"
+"Ekstra rettelser: "
+
+msgid "Modified by "
+msgstr "Ændret af "
+
+msgid ""
+"\n"
+"Compiled "
+msgstr ""
+"\n"
+"Kompileret "
+
+msgid "by "
+msgstr "af "
+
+msgid ""
+"\n"
+"Huge version "
+msgstr ""
+"\n"
+"Huge-version "
+
+msgid ""
+"\n"
+"Big version "
+msgstr ""
+"\n"
+"Big-version "
+
+msgid ""
+"\n"
+"Normal version "
+msgstr ""
+"\n"
+"Normal-version "
+
+msgid ""
+"\n"
+"Small version "
+msgstr ""
+"\n"
+"Small-version "
+
+msgid ""
+"\n"
+"Tiny version "
+msgstr ""
+"\n"
+"Tiny-version "
+
+msgid "without GUI."
+msgstr "uden GUI."
+
+msgid "with GTK3 GUI."
+msgstr "med GTK3-GUI."
+
+msgid "with GTK2-GNOME GUI."
+msgstr "med GTK2-GNOME-GUI."
+
+msgid "with GTK2 GUI."
+msgstr "med GTK2-GUI."
+
+msgid "with X11-Motif GUI."
+msgstr "med X11-Motif-GUI."
+
+msgid "with X11-neXtaw GUI."
+msgstr "med X11-neXtaw-GUI."
+
+msgid "with X11-Athena GUI."
+msgstr "med X11-Athena-GUI."
+
+msgid "with Photon GUI."
+msgstr "med Photon-GUI."
+
+msgid "with GUI."
+msgstr "med GUI."
+
+msgid "with Carbon GUI."
+msgstr "med Carbon-GUI."
+
+msgid "with Cocoa GUI."
+msgstr "med Cocoa-GUI."
+
+msgid " Features included (+) or not (-):\n"
+msgstr " Funktionaliteter som er med (+) eller ikke (-):\n"
+
+msgid " system vimrc file: \""
+msgstr " system vimrc-fil: \""
+
+msgid " user vimrc file: \""
+msgstr " bruger vimrc-fil: \""
+
+msgid " 2nd user vimrc file: \""
+msgstr " 2. bruger vimrc-fil: \""
+
+msgid " 3rd user vimrc file: \""
+msgstr " 3. bruger vimrc-fil: \""
+
+msgid " user exrc file: \""
+msgstr " bruger exrc-fil: \""
+
+msgid " 2nd user exrc file: \""
+msgstr " 2. bruger exrc-fil: \""
+
+msgid " system gvimrc file: \""
+msgstr " system gvimrc-fil: \""
+
+msgid " user gvimrc file: \""
+msgstr " bruger gvimrc-fil: \""
+
+msgid "2nd user gvimrc file: \""
+msgstr "2. bruger gvimrc-fil: \""
+
+msgid "3rd user gvimrc file: \""
+msgstr "3. bruger gvimrc-fil: \""
+
+msgid " defaults file: \""
+msgstr " defaults-fil: \""
+
+msgid " system menu file: \""
+msgstr " system menu-fil: \""
+
+msgid " fall-back for $VIM: \""
+msgstr " fall-back for $VIM: \""
+
+msgid " f-b for $VIMRUNTIME: \""
+msgstr " f-b for $VIMRUNTIME: \""
+
+msgid "Compilation: "
+msgstr "Kompilering: "
+
+msgid "Compiler: "
+msgstr "Kompiler: "
+
+msgid "Linking: "
+msgstr "Linking: "
+
+msgid " DEBUG BUILD"
+msgstr " FEJLRETNINGSBYG"
+
+msgid "VIM - Vi IMproved"
+msgstr "VIM - Vi IMproved"
+
+msgid "version "
+msgstr "version "
+
+msgid "by Bram Moolenaar et al."
+msgstr "af Bram Moolenaar og andre"
+
+msgid "Vim is open source and freely distributable"
+msgstr "Vim er open source og kan frit distribueres"
+
+msgid "Help poor children in Uganda!"
+msgstr "Hjælp fattige børn i Uganda!"
+
+msgid "type :help iccf<Enter> for information "
+msgstr "skriv :help iccf<Enter> for information "
+
+msgid "type :q<Enter> to exit "
+msgstr "skriv :q<Enter> for at afslutte "
+
+msgid "type :help<Enter> or <F1> for on-line help"
+msgstr "skriv :help<Enter> eller <F1> for onlinehjælp "
+
+msgid "type :help version8<Enter> for version info"
+msgstr "skriv :help version8<Enter> for versionsinfo"
+
+msgid "Running in Vi compatible mode"
+msgstr "Kører i Vi-kompatibel-tilstand"
+
+msgid "type :set nocp<Enter> for Vim defaults"
+msgstr "skriv :set nocp<Enter> for Vim-standarder"
+
+msgid "type :help cp-default<Enter> for info on this"
+msgstr "skriv :help cp-default<Enter> for info om det "
+
+msgid "menu Help->Orphans for information "
+msgstr "menu Hjælp->Forældreløse børnfor information "
+
+msgid "Running modeless, typed text is inserted"
+msgstr "Kører tilstandsløs, skrevet tekst indsættes"
+
+msgid "menu Edit->Global Settings->Toggle Insert Mode "
+msgstr "menu Rediger->Globale indstillinger->Indsæt-tilstand til/fra "
+
+msgid " for two modes "
+msgstr " for to-tilstande "
+
+msgid "menu Edit->Global Settings->Toggle Vi Compatible"
+msgstr "menu Rediger->Globale indstillinger->Vi-kompatibel til/fra"
+
+msgid " for Vim defaults "
+msgstr " for Vim-standarder "
+
+msgid "Sponsor Vim development!"
+msgstr "Sponsorer udviklingen af Vim!"
+
+msgid "Become a registered Vim user!"
+msgstr "Bliv en registreret Vim-bruger!"
+
+msgid "type :help sponsor<Enter> for information "
+msgstr "skriv :help sponsor<Enter> for information "
+
+msgid "type :help register<Enter> for information "
+msgstr "skriv :help register<Enter> for information "
+
+msgid "menu Help->Sponsor/Register for information "
+msgstr "menu Hjælp->Sponsorer/registrer for information "
+
+msgid "Already only one window"
+msgstr "Allerede kun ét vindue"
+
+msgid "E441: There is no preview window"
+msgstr "E441: Der er ikke noget forhåndsvisningsvindue"
+
+msgid "E442: Can't split topleft and botright at the same time"
+msgstr "E442: Kan ikke opdele øverste venstre og nederste højre på samme tid"
+
+msgid "E443: Cannot rotate when another window is split"
+msgstr "E443: Kan ikke rotere når et andet vindue er opdelt"
+
+msgid "E444: Cannot close last window"
+msgstr "E444: Kan ikke lukke sidste vindue"
+
+msgid "E813: Cannot close autocmd window"
+msgstr "E813: Kan ikke lukke autocmd-vindue"
+
+msgid "E814: Cannot close window, only autocmd window would remain"
+msgstr "E814: Kan ikke lukke vindue, kun autocmd-vindue ville være tilbage"
+
+msgid "E445: Other window contains changes"
+msgstr "E445: Et andet vindue indeholder ændringer"
+
+msgid "E446: No file name under cursor"
+msgstr "E446: Intet filnavn under markør"
+
+#, c-format
+msgid "E447: Can't find file \"%s\" in path"
+msgstr "E447: Kan ikke finde filen \"%s\" i sti"
+
+#, c-format
+msgid "E799: Invalid ID: %ld (must be greater than or equal to 1)"
+msgstr "E799: Ugyldigt ID: %ld (skal være større end eller lig med 1)"
+
+#, c-format
+msgid "E801: ID already taken: %ld"
+msgstr "E801: ID allerede taget: %ld"
+
+msgid "List or number required"
+msgstr "Liste eller nummer kræves"
+
+#, c-format
+msgid "E802: Invalid ID: %ld (must be greater than or equal to 1)"
+msgstr "E802: Ugyldigt ID: %ld (skal være større end eller lig med 1)"
+
+#, c-format
+msgid "E803: ID not found: %ld"
+msgstr "E803: ID ikke fundet: %ld"
+
+#, c-format
+msgid "E370: Could not load library %s"
+msgstr "E370: Kunne ikke indlæse biblioteket %s"
+
+msgid "Sorry, this command is disabled: the Perl library could not be loaded."
+msgstr ""
+"Beklager, kommandoen er deaktiveret: Perl-biblioteket kunne ikke indlæses."
+
+msgid "E299: Perl evaluation forbidden in sandbox without the Safe module"
+msgstr "E299: Perl-evaluering forbudt i sandbox uden Safe-modulet"
+
+msgid "Edit with &multiple Vims"
+msgstr "Rediger med &flere Vim'er"
+
+msgid "Edit with single &Vim"
+msgstr "Rediger med én &Vim"
+
+msgid "Diff with Vim"
+msgstr "Diff med Vim"
+
+msgid "Edit with &Vim"
+msgstr "Rediger med &Vim"
+
+msgid "Edit with existing Vim - "
+msgstr "Rediger med eksisterende Vim - "
+
+msgid "Edits the selected file(s) with Vim"
+msgstr "Redigerer den valgt fil(er) med Vim"
+
+msgid "Error creating process: Check if gvim is in your path!"
+msgstr "Fejl ved oprettelse af proces: Tjek om gvim er i din sti!"
+
+msgid "gvimext.dll error"
+msgstr "fejl ved gvimext.dll"
+
+msgid "Path length too long!"
+msgstr "Stiens længde er for lang!"
+
+msgid "--No lines in buffer--"
+msgstr "--Ingen linjer i buffer--"
+
+msgid "E470: Command aborted"
+msgstr "E470: Kommando afbrudt"
+
+msgid "E471: Argument required"
+msgstr "E471: Argument kræves"
+
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: \\ skal efterføles af /, ? eller &"
+
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr "E11: Ugyldig i kommandolinjevindue; <CR> udfører, CTRL-C afslutter"
+
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+msgstr ""
+"E12: Kommando ikke tilladt fra exrc/vimrc i nuværende mappe- eller "
+"tagsøgning"
+
+msgid "E171: Missing :endif"
+msgstr "E171: Manglende :endif"
+
+msgid "E600: Missing :endtry"
+msgstr "E600: Manglende :endtry"
+
+msgid "E170: Missing :endwhile"
+msgstr "E170: Manglende :endwhile"
+
+msgid "E170: Missing :endfor"
+msgstr "E170: Manglende :endfor"
+
+msgid "E588: :endwhile without :while"
+msgstr "E588: :endwhile uden :while"
+
+msgid "E588: :endfor without :for"
+msgstr "E588: :endfor uden :for"
+
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: Filen findes (tilføj ! for at tilsidesætte)"
+
+msgid "E472: Command failed"
+msgstr "E472: Kommando mislykkede"
+
+#, c-format
+msgid "E234: Unknown fontset: %s"
+msgstr "E234: Ukendt skrifttypesæt: %s"
+
+#, c-format
+msgid "E235: Unknown font: %s"
+msgstr "E235: Ukendt skrifttype: %s"
+
+#, c-format
+msgid "E236: Font \"%s\" is not fixed-width"
+msgstr "E236: Skrifttypen \"%s\" er ikke med fast bredde"
+
+msgid "E473: Internal error"
+msgstr "E473: Intern fejl"
+
+#, c-format
+msgid "E685: Internal error: %s"
+msgstr "E685: Intern fejl: %s"
+
+msgid "Interrupted"
+msgstr "Afbrudt"
+
+msgid "E14: Invalid address"
+msgstr "E14: Ugyldig adresse"
+
+msgid "E474: Invalid argument"
+msgstr "E474: Ugyldigt argument"
+
+#, c-format
+msgid "E475: Invalid argument: %s"
+msgstr "E475: Ugyldigt argument: %s"
+
+#, c-format
+msgid "E475: Invalid value for argument %s"
+msgstr "E475: Ugyldig værdi for argumentet %s"
+
+#, c-format
+msgid "E475: Invalid value for argument %s: %s"
+msgstr "E475: Ugyldig værdi for argumentet %s: %s"
+
+#, c-format
+msgid "E15: Invalid expression: %s"
+msgstr "E15: Ugyldigt udtryk: %s"
+
+msgid "E16: Invalid range"
+msgstr "E16: Ugyldigt område"
+
+msgid "E476: Invalid command"
+msgstr "E476: Ugyldig kommando"
+
+#, c-format
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: \"%s\" er en mappe"
+
+#, c-format
+msgid "E364: Library call failed for \"%s()\""
+msgstr "E364: Kald af bibliotek mislykkedes for \"%s()\""
+
+msgid "E667: Fsync failed"
+msgstr "E667: Fsync mislykkedes"
+
+#, c-format
+msgid "E448: Could not load library function %s"
+msgstr "E448: Kunne ikke indlæse biblioteksfunktionen %s"
+
+msgid "E19: Mark has invalid line number"
+msgstr "E19: Mærke har ugyldigt linjenummer"
+
+msgid "E20: Mark not set"
+msgstr "E20: Mærke ikke sat"
+
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: Kan ikke foretage ændringer, 'modifiable' er slået fra"
+
+msgid "E22: Scripts nested too deep"
+msgstr "E22: Scripts indlejret for dybt"
+
+msgid "E23: No alternate file"
+msgstr "E23: Ingen alternate-fil"
+
+msgid "E24: No such abbreviation"
+msgstr "E24: Ingen sådan forkortelse"
+
+msgid "E477: No ! allowed"
+msgstr "E477: Ingen ! tilladt"
+
+msgid "E25: GUI cannot be used: Not enabled at compile time"
+msgstr "E25: GUI kan ikke bruges: Ikke aktiveret ved kompileringstid"
+
+msgid "E26: Hebrew cannot be used: Not enabled at compile time\n"
+msgstr "E26: Hebraisk kan ikke bruges: Ikke aktiveret ved kompileringstid\n"
+
+msgid "E27: Farsi cannot be used: Not enabled at compile time\n"
+msgstr ""
+"E27: Persisk kan ikke bruges: Ikke aktiveret ved kompileringstid\n"
+"\n"
+
+msgid "E800: Arabic cannot be used: Not enabled at compile time\n"
+msgstr "E800: Arabisk kan ikke bruges: Ikke aktiveret ved kompileringstid\n"
+
+#, c-format
+msgid "E28: No such highlight group name: %s"
+msgstr "E28: Intet sådan fremhævningsgruppenavn: %s"
+
+msgid "E29: No inserted text yet"
+msgstr "E29: Endnu ingen indsat tekst"
+
+msgid "E30: No previous command line"
+msgstr "E30: Ingen tidligere kommandolinje"
+
+msgid "E31: No such mapping"
+msgstr "E31: Ingen sådan mapping"
+
+msgid "E479: No match"
+msgstr "E479: Intet match"
+
+#, c-format
+msgid "E480: No match: %s"
+msgstr "E480: Intet match: %s"
+
+msgid "E32: No file name"
+msgstr "E32: Intet filnavn"
+
+msgid "E33: No previous substitute regular expression"
+msgstr "E33: Ingen tidligere erstatnings regulært udtryk"
+
+msgid "E34: No previous command"
+msgstr "E34: Ingen tidligere kommando"
+
+msgid "E35: No previous regular expression"
+msgstr "E35: Ingen tidligere regulære udtryk"
+
+msgid "E481: No range allowed"
+msgstr "E481: Intet område tilladt"
+
+msgid "E36: Not enough room"
+msgstr "E36: Ikke plads nok"
+
+#, c-format
+msgid "E247: no registered server named \"%s\""
+msgstr "E247: ingen registreret server ved navn \"%s\""
+
+#, c-format
+msgid "E482: Can't create file %s"
+msgstr "E482: Kan ikke oprette filen %s"
+
+msgid "E483: Can't get temp file name"
+msgstr "E483: Kan ikke hente midlertidigt filnavn"
+
+#, c-format
+msgid "E484: Can't open file %s"
+msgstr "E484: Kan ikke åbne filen %s"
+
+#, c-format
+msgid "E485: Can't read file %s"
+msgstr "E485: Kan ikke læse filen %s"
+
+msgid "E38: Null argument"
+msgstr "E38: Null-argument"
+
+msgid "E39: Number expected"
+msgstr "E39: Nummer ventet"
+
+#, c-format
+msgid "E40: Can't open errorfile %s"
+msgstr "E40: Kan ikke åbne fejlfilen %s"
+
+msgid "E233: cannot open display"
+msgstr "E233: kan ikke åbne display"
+
+msgid "E41: Out of memory!"
+msgstr "E41: Ikke mere ledig hukommelse!"
+
+msgid "Pattern not found"
+msgstr "Mønster ikke fundet"
+
+#, c-format
+msgid "E486: Pattern not found: %s"
+msgstr "E486: Mønster ikke fundet: %s"
+
+msgid "E487: Argument must be positive"
+msgstr "E487: Argument skal være positivt"
+
+msgid "E459: Cannot go back to previous directory"
+msgstr "E459: Kan ikke gå tilbage til tidligere mappe"
+
+msgid "E42: No Errors"
+msgstr "E42: Ingen fejl"
+
+msgid "E776: No location list"
+msgstr "E776: Ingen placeringsliste"
+
+msgid "E43: Damaged match string"
+msgstr "E43: Beskadiget matchstreng"
+
+msgid "E44: Corrupted regexp program"
+msgstr "E44: Korrupt regexp-program"
+
+msgid "E45: 'readonly' option is set (add ! to override)"
+msgstr "E45: 'readonly'-tilvalget er sat (tilføj ! for at tilsidesætte)"
+
+#, c-format
+msgid "E46: Cannot change read-only variable \"%s\""
+msgstr "E46: Kan ikke ændre skrivebeskyttet variabel \"%s\""
+
+#, c-format
+msgid "E794: Cannot set variable in the sandbox: \"%s\""
+msgstr "E794: Kan ikke sætte variabel i sandboksen: \"%s\""
+
+msgid "E713: Cannot use empty key for Dictionary"
+msgstr "E713: Kan ikke bruge tom nøgle til ordbog"
+
+msgid "E715: Dictionary required"
+msgstr "E715: Ordbog kræves"
+
+#, c-format
+msgid "E684: list index out of range: %ld"
+msgstr "E684: listeindeks udenfor område: %ld"
+
+#, c-format
+msgid "E118: Too many arguments for function: %s"
+msgstr "E118: For mange argumenter til funktion: %s"
+
+#, c-format
+msgid "E716: Key not present in Dictionary: %s"
+msgstr "E716: Nøgle findes ikke i ordbog: %s"
+
+msgid "E714: List required"
+msgstr "E714: Liste kræves"
+
+#, c-format
+msgid "E712: Argument of %s must be a List or Dictionary"
+msgstr "E712: Argument af %s skal være en liste eller ordbog"
+
+msgid "E47: Error while reading errorfile"
+msgstr "E47: Fejl ved læsning af fejlfil"
+
+msgid "E48: Not allowed in sandbox"
+msgstr "E48: Ikke tilladt i sandboks"
+
+msgid "E523: Not allowed here"
+msgstr "E523: Ikke tilladt her"
+
+msgid "E359: Screen mode setting not supported"
+msgstr "E359: Skærmtilstand-indstilling understøttes ikke"
+
+msgid "E49: Invalid scroll size"
+msgstr "E49: Ugyldig rullestørrelse"
+
+msgid "E91: 'shell' option is empty"
+msgstr "E91: 'shell'-tilvalget er tomt"
+
+msgid "E255: Couldn't read in sign data!"
+msgstr "E255: Kunne ikke læse i sign-data!"
+
+msgid "E72: Close error on swap file"
+msgstr "E72: Fejl ved lukning af swap-fil"
+
+msgid "E73: tag stack empty"
+msgstr "E73: tag-stak tom"
+
+msgid "E74: Command too complex"
+msgstr "E74: Kommando for kompleks"
+
+msgid "E75: Name too long"
+msgstr "E75: Navn for langt"
+
+msgid "E76: Too many ["
+msgstr "E76: For mange ["
+
+msgid "E77: Too many file names"
+msgstr "E77: For mange filnavne"
+
+msgid "E488: Trailing characters"
+msgstr "E488: Efterstillede tegn"
+
+msgid "E78: Unknown mark"
+msgstr "E78: Ukendt mærke"
+
+msgid "E79: Cannot expand wildcards"
+msgstr "E79: Kan ikke udvide jokertegn"
+
+msgid "E591: 'winheight' cannot be smaller than 'winminheight'"
+msgstr "E591: 'winheight' må ikke være mindre end 'winminheight'"
+
+msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'"
+msgstr "E592: 'winwidth' må ikke være mindre end 'winminwidth'"
+
+msgid "E80: Error while writing"
+msgstr "E80: Fejl ved skrivning"
+
+msgid "E939: Positive count required"
+msgstr "E939: Positiv tælling kræves"
+
+msgid "E81: Using <SID> not in a script context"
+msgstr "E81: Bruger <SID> ikke i et script kontekst"
+
+msgid "E449: Invalid expression received"
+msgstr "E449: Ugyldigt udtryk modtaget"
+
+msgid "E463: Region is guarded, cannot modify"
+msgstr "E463: Regionen er beskyttet, kan ikke ændre"
+
+msgid "E744: NetBeans does not allow changes in read-only files"
+msgstr "E744: NetBeans tillader ikke ændringer i skrivebeskyttede filer"
+
+msgid "E363: pattern uses more memory than 'maxmempattern'"
+msgstr "E363: mønster bruger mere hukommelse end 'maxmempattern'"
+
+msgid "E749: empty buffer"
+msgstr "E749: tom buffer"
+
+#, c-format
+msgid "E86: Buffer %ld does not exist"
+msgstr "E86: Bufferen %ld findes ikke"
+
+msgid "E682: Invalid search pattern or delimiter"
+msgstr "E682: Ugyldigt søgemønster eller -afgrænser"
+
+msgid "E139: File is loaded in another buffer"
+msgstr "E139: Filen er indlæst i en anden buffer"
+
+#, c-format
+msgid "E764: Option '%s' is not set"
+msgstr "E764: Tilvalget '%s' er ikke sat"
+
+msgid "E850: Invalid register name"
+msgstr "E850: Ugyldigt registernavn"
+
+#, c-format
+msgid "E919: Directory not found in '%s': \"%s\""
+msgstr "E919: Mappe ikke fundet i '%s': \"%s\""
+
+msgid "E952: Autocommand caused recursive behavior"
+msgstr "E952: Autokommando forårsagede rekursiv opførsel"
+
+msgid "search hit TOP, continuing at BOTTOM"
+msgstr "søgning ramte ØVERST, fortsætter ved NEDERST"
+
+msgid "search hit BOTTOM, continuing at TOP"
+msgstr "søgning ramte NEDERST, fortsætter ved ØVERST"
+
+#, c-format
+msgid "Need encryption key for \"%s\""
+msgstr "Behøver krypteringsnøgle til \"%s\""
+
+msgid "empty keys are not allowed"
+msgstr "tomme nøgler er ikke tilladt"
+
+msgid "dictionary is locked"
+msgstr "ordbog er låst"
+
+msgid "list is locked"
+msgstr "liste er låst"
+
+#, c-format
+msgid "failed to add key '%s' to dictionary"
+msgstr "kunne ikke tilføje nøglen '%s' til ordbog"
+
+#, c-format
+msgid "index must be int or slice, not %s"
+msgstr "indeks skal være heltal eller slice, ikke %s"
+
+#, c-format
+msgid "expected str() or unicode() instance, but got %s"
+msgstr "ventede str()- eller unicode()-instans, men fik %s"
+
+#, c-format
+msgid "expected bytes() or str() instance, but got %s"
+msgstr "ventede bytes()- eller str()-instans, min fik %s"
+
+#, c-format
+msgid ""
+"expected int(), long() or something supporting coercing to long(), but got %s"
+msgstr ""
+"ventede int(), long() eller noget som understøtter coercing til long(), min "
+"fik %s"
+
+#, c-format
+msgid "expected int() or something supporting coercing to int(), but got %s"
+msgstr ""
+"ventede int() eller noget som understøtter coercing til int(), min fik %s"
+
+msgid "value is too large to fit into C int type"
+msgstr "værdi er for stor til at passe i C-heltalstype"
+
+msgid "value is too small to fit into C int type"
+msgstr "værdi er for lille til at passe i C-heltalstype"
+
+msgid "number must be greater than zero"
+msgstr "nummer skal være større end nul"
+
+msgid "number must be greater or equal to zero"
+msgstr "nummer skal være større end eller lig med nul"
+
+msgid "can't delete OutputObject attributes"
+msgstr "kan ikke slette OutputObject-attributter"
+
+#, c-format
+msgid "invalid attribute: %s"
+msgstr "ugyldig attribut: %s"
+
+msgid "E264: Python: Error initialising I/O objects"
+msgstr "E264: Python: Fejl ved initialisering af I/O-objekter"
+
+msgid "failed to change directory"
+msgstr "kunne ikke skifte mappe"
+
+#, c-format
+msgid "expected 3-tuple as imp.find_module() result, but got %s"
+msgstr "ventede 3-tuple som imp.find_module() resultat, men fik %s"
+
+#, c-format
+msgid "expected 3-tuple as imp.find_module() result, but got tuple of size %d"
+msgstr ""
+"ventede 3-tuple som imp.find_module() resultat, men fik tuple af størrelse %"
+"d"
+
+msgid "internal error: imp.find_module returned tuple with NULL"
+msgstr "intern fejl: imp.find_module returnerede tuple med NULL"
+
+msgid "cannot delete vim.Dictionary attributes"
+msgstr "kan ikke slette vim.Dictionary-attributter"
+
+msgid "cannot modify fixed dictionary"
+msgstr "kan ikke ændre fast ordbog"
+
+#, c-format
+msgid "cannot set attribute %s"
+msgstr "kan ikke sætte attributten %s"
+
+msgid "hashtab changed during iteration"
+msgstr "hashtab ændret under gennemløb"
+
+#, c-format
+msgid "expected sequence element of size 2, but got sequence of size %d"
+msgstr "ventede sekvenselement af størrelse 2, men fik sekvens af størrelse %d"
+
+msgid "list constructor does not accept keyword arguments"
+msgstr "liste-constructor accepterer ikke nøgleord-argumenter"
+
+msgid "list index out of range"
+msgstr "listeindeks udenfor område"
+
+#, c-format
+msgid "internal error: failed to get vim list item %d"
+msgstr "intern fejl: kunne ikke hente vim-listepunkt %d"
+
+msgid "slice step cannot be zero"
+msgstr "slice-trin må ikke være nul"
+
+#, c-format
+msgid "attempt to assign sequence of size greater than %d to extended slice"
+msgstr "forsøg på at tildele sekvens som er større end %d til udvidet slice"
+
+#, c-format
+msgid "internal error: no vim list item %d"
+msgstr "intern fejl: intet vim-listepunkt %d"
+
+msgid "internal error: not enough list items"
+msgstr "intern fejl: ikke nok listepunkter"
+
+msgid "internal error: failed to add item to list"
+msgstr "intern fejl: kunne ikke tilføje punkt til liste"
+
+#, c-format
+msgid "attempt to assign sequence of size %d to extended slice of size %d"
+msgstr ""
+"forsøg på at tildele sekvens af størrelsen %d til udvidet slice af "
+"størrelsen %d"
+
+msgid "failed to add item to list"
+msgstr "kunne ikke tilføje punkt til liste"
+
+msgid "cannot delete vim.List attributes"
+msgstr "kan ikke slette vim.List-attributter"
+
+msgid "cannot modify fixed list"
+msgstr "kan ikke ændre fast liste"
+
+#, c-format
+msgid "unnamed function %s does not exist"
+msgstr "unavngivet funktion %s findes ikke"
+
+#, c-format
+msgid "function %s does not exist"
+msgstr "funktionen %s findes ikke"
+
+#, c-format
+msgid "failed to run function %s"
+msgstr "kunne ikke køre funktionen %s"
+
+msgid "unable to get option value"
+msgstr "kan ikke hente tilvalgsværdi"
+
+msgid "internal error: unknown option type"
+msgstr "intern fejl: ukendt tilvalgstype"
+
+msgid "problem while switching windows"
+msgstr "problem ved skift af vinduer"
+
+#, c-format
+msgid "unable to unset global option %s"
+msgstr "kan ikke fjerne det globale tilvalg %s"
+
+#, c-format
+msgid "unable to unset option %s which does not have global value"
+msgstr "kan ikke fjerne tilvalget %s som ikke har global værdi"
+
+msgid "attempt to refer to deleted tab page"
+msgstr "forsøg på at referere til slettet fanebladsside"
+
+msgid "no such tab page"
+msgstr "ingen sådan fanebladsside"
+
+msgid "attempt to refer to deleted window"
+msgstr "forsøg på at referere til slettet vindue"
+
+msgid "readonly attribute: buffer"
+msgstr "skrivebeskyttet attribut: buffer"
+
+msgid "cursor position outside buffer"
+msgstr "markørposition udenfor buffer"
+
+msgid "no such window"
+msgstr "intet sådan vindue"
+
+msgid "attempt to refer to deleted buffer"
+msgstr "forsøg på at referere til slettet buffer"
+
+msgid "failed to rename buffer"
+msgstr "kunne ikke omdøbe bufferen"
+
+msgid "mark name must be a single character"
+msgstr "mærkenavn skal være ét tegn"
+
+#, c-format
+msgid "expected vim.Buffer object, but got %s"
+msgstr "ventede vim.Buffer-objekt, men fik %s"
+
+#, c-format
+msgid "failed to switch to buffer %d"
+msgstr "kunne ikke skifte til bufferen %d"
+
+#, c-format
+msgid "expected vim.Window object, but got %s"
+msgstr "ventede vim.Window-objekt, men fik %s"
+
+msgid "failed to find window in the current tab page"
+msgstr "kunne ikke finde vindue i den nuværende fanebladsside"
+
+msgid "did not switch to the specified window"
+msgstr "skiftede ikke til det angivne vindue"
+
+#, c-format
+msgid "expected vim.TabPage object, but got %s"
+msgstr "ventede vim.TabPage-objekt, men fik %s"
+
+msgid "did not switch to the specified tab page"
+msgstr "skiftede ikke til den angivne fanebladsside"
+
+msgid "failed to run the code"
+msgstr "kunne ikke køre koden"
+
+msgid "E858: Eval did not return a valid python object"
+msgstr "E858: Eval returnerede ikke et gyldigt python-objekt"
+
+msgid "E859: Failed to convert returned python object to vim value"
+msgstr "E859: Kunne ikke konvertere returnerede python-objekt til vim-værdi"
+
+#, c-format
+msgid "unable to convert %s to vim dictionary"
+msgstr "kan ikke konvertere %s til vim-ordbog"
+
+#, c-format
+msgid "unable to convert %s to vim list"
+msgstr "kan ikke konvertere %s til vim-liste"
+
+#, c-format
+msgid "unable to convert %s to vim structure"
+msgstr "kan ikke konvertere %s til vim-struktur"
+
+msgid "internal error: NULL reference passed"
+msgstr "intern fejl: NULL-reference givet"
+
+msgid "internal error: invalid value type"
+msgstr "intern fejl: ugyldig værditype"
+
+msgid ""
+"Failed to set path hook: sys.path_hooks is not a list\n"
+"You should now do the following:\n"
+"- append vim.path_hook to sys.path_hooks\n"
+"- append vim.VIM_SPECIAL_PATH to sys.path\n"
+msgstr ""
+"Kunne ikke sætte sti-hook: sys.path_hooks er ikke en liste\n"
+"Du bør nu gøre følgende:\n"
+"- tilføj vim.path_hook til slutningen af sys.path_hooks\n"
+"- tilføj vim.VIM_SPECIAL_PATH til slutningen af sys.path\n"
+
+msgid ""
+"Failed to set path: sys.path is not a list\n"
+"You should now append vim.VIM_SPECIAL_PATH to sys.path"
+msgstr ""
+"Kunne ikke sætte sti: sys.path er ikke en liste\n"
+"Du bør nu tilføje vim.VIM_SPECIAL_PATH til slutningen af sys.path"
+
+msgid ""
+"Vim macro files (*.vim)\t*.vim\n"
+"All Files (*.*)\t*.*\n"
+msgstr ""
+"Vim-makrofiler (*.vim)\t*.vim\n"
+"Alle filer (*.*)\t*.*\n"
+
+msgid "All Files (*.*)\t*.*\n"
+msgstr "Alle filer (*.*)\t*.*\n"
+
+msgid ""
+"All Files (*.*)\t*.*\n"
+"C source (*.c, *.h)\t*.c;*.h\n"
+"C++ source (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"VB code (*.bas, *.frm)\t*.bas;*.frm\n"
+"Vim files (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+msgstr ""
+"Alle filer (*.*)\t*.*\n"
+"C-kildekode (*.c, *.h)\t*.c;*.h\n"
+"C++-kildekode (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"VB-kode (*.bas, *.frm)\t*.bas;*.frm\n"
+"Vim-filer (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+
+msgid ""
+"Vim macro files (*.vim)\t*.vim\n"
+"All Files (*)\t*\n"
+msgstr ""
+"Vim-makrofiler (*.vim)\t*.vim\n"
+"Alle filer (*)\t*\n"
+
+msgid "All Files (*)\t*\n"
+msgstr "Alle filer (*)\t*\n"
+
+msgid ""
+"All Files (*)\t*\n"
+"C source (*.c, *.h)\t*.c;*.h\n"
+"C++ source (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"Vim files (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
+msgstr ""
+"Alle filer (*)\t*\n"
+"C-kildekode (*.c, *.h)\t*.c;*.h\n"
+"C++-kildekode (*.cpp, *.hpp)\t*.cpp;*.hpp\n"
+"Vim-filer (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n"
diff --git a/src/nvim/po/uk.po b/src/nvim/po/uk.po
index 4c5d169ec9..211d38e53a 100644
--- a/src/nvim/po/uk.po
+++ b/src/nvim/po/uk.po
@@ -14,13 +14,13 @@ msgid ""
msgstr ""
"Project-Id-Version: vim 7.4\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-06-20 22:34+0300\n"
-"PO-Revision-Date: 2010-06-18 21:53+0300\n"
+"POT-Creation-Date: 2018-12-18 22:42+0200\n"
+"PO-Revision-Date: 2018-12-18 22:42+0200\n"
"Last-Translator: Ðнатолій Сахнік <sakhnik@gmail.com>\n"
"Language-Team: Ukrainian\n"
"Language: uk\n"
"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=utf-8\n"
+"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "[Location List]"
@@ -77,7 +77,6 @@ msgstr "E90: Ðе можу вивантажити оÑтанній буфер"
msgid "E84: No modified buffer found"
msgstr "E84: Жоден буфер не змінено"
-#. back where we started, didn't find anything.
msgid "E85: There is no listed buffer"
msgstr "E85: У ÑпиÑку немає буферів"
@@ -96,7 +95,6 @@ msgid ""
"E89: No write since last change for buffer %<PRId64> (add ! to override)"
msgstr "E89: Буфер %<PRId64> має зміни (! щоб не зважати)"
-#. wrap around (may cause duplicates)
msgid "W14: Warning: List of file names overflow"
msgstr "W14: Обережно: СпиÑок назв файлів переповнено"
@@ -152,7 +150,6 @@ msgstr "Ñ€Ñдок %<PRId64> з %<PRId64> --%d%%-- колонка "
msgid "[No Name]"
msgstr "[Без назви]"
-#. Must be a help buffer.
msgid "help"
msgstr "допомога"
@@ -217,18 +214,28 @@ msgstr "E549: Ðеправильний відÑоток"
msgid "E96: Cannot diff more than %<PRId64> buffers"
msgstr "E96: Ðе можна порівнювати понад %<PRId64> буфери(ів)"
+#, c-format
+msgid "Not enough memory to use internal diff for buffer \"%s\""
+msgstr "ÐедоÑтатньо пам’Ñті Ð´Ð»Ñ Ð²Ð½ÑƒÑ‚Ñ€Ñ–ÑˆÐ½ÑŒÐ¾Ð³Ð¾ порівнÑÐ½Ð½Ñ Ñƒ буфері \"%s\""
+
msgid "E810: Cannot read or write temp files"
msgstr "E810: Ðе можна читати чи запиÑувати тимчаÑові файли"
msgid "E97: Cannot create diffs"
msgstr "E97: Ðе вдалоÑÑ Ñтворити порівнÑннÑ"
+msgid "E960: Problem creating the internal diff"
+msgstr "E960: Ðе вдалоÑÑ Ñтворити внутрішнє порівнÑннÑ"
+
msgid "E816: Cannot read patch output"
msgstr "E816: Ðе вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ результат patch"
msgid "E98: Cannot read diff output"
msgstr "E98: Ðе вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ результат diff"
+msgid "E959: Invalid diff format."
+msgstr "E959: Ðеправильний формат порівнÑннÑ."
+
msgid "E99: Current buffer is not in diff mode"
msgstr "E99: Цей буфер не в режимі порівнÑннÑ"
@@ -269,7 +276,6 @@ msgstr "E791: Елемент розкладки порожній"
msgid " Keyword completion (^N^P)"
msgstr " Ð”Ð¾Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ ÐºÐ»ÑŽÑ‡Ð¾Ð²Ð¸Ñ… Ñлів (^N^P)"
-#. ctrl_x_mode == 0, ^P/^N compl.
msgid " ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
msgstr " Режим ^X (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
@@ -329,7 +335,7 @@ msgid "Scanning dictionary: %s"
msgstr "СкануєтьÑÑ Ñловник: %s"
msgid " (insert) Scroll (^E/^Y)"
-msgstr " (вÑтавка) Прогорнути (^E/^Y)"
+msgstr " (вÑтавити) Прогорнути (^E/^Y)"
msgid " (replace) Scroll (^E/^Y)"
msgstr " (заміна) Прогорнути (^E/^Y)"
@@ -347,10 +353,6 @@ msgstr "збіг у файлі"
msgid " Adding"
msgstr " ДодаєтьÑÑ"
-#. showmode might reset the internal line pointers, so it must
-#. * be called before line = ml_get(), or when this address is no
-#. * longer needed. -- Acevedo.
-#.
msgid "-- Searching..."
msgstr "-- Пошук..."
@@ -427,7 +429,6 @@ msgstr "E461: ÐеприпуÑтима назва змінної: %s"
msgid "E46: Cannot change read-only variable \"%.*s\""
msgstr "E46: Змінна тільки Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ: «%.*s»"
-#. TODO(ZyX-I): move to eval/executor
#, c-format
msgid "E734: Wrong variable type for %s="
msgstr "E734: Ðеправильний тип змінної Ð´Ð»Ñ %s="
@@ -484,8 +485,6 @@ msgstr "E107: Пропущено дужки: %s"
msgid "E108: No such variable: \"%s\""
msgstr "E108: Змінної немає: «%s»"
-#. For historical reasons this error is not given for Lists and
-#. Dictionaries. E.g. b: dictionary may be locked/unlocked.
#, c-format
msgid "E940: Cannot lock or unlock variable %s"
msgstr "E940: Ðеможливо заблокувати чи розблокувати змінну %s"
@@ -615,7 +614,7 @@ msgid "Invalid channel stream \"%s\""
msgstr "Ðекоректний потік Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Â«%s»"
msgid "E785: complete() can only be used in Insert mode"
-msgstr "E785: complete() можна вживати тільки в режимі вÑтавки"
+msgstr "E785: complete() можна вживати тільки в режимі вÑтавлÑннÑ"
msgid "&Ok"
msgstr "&O:Гаразд"
@@ -739,7 +738,6 @@ msgstr "аргумент uniq()"
msgid "E702: Sort compare function failed"
msgstr "E702: Помилка у функції порівнÑннÑ"
-#. -V547
msgid "E882: Uniq compare function failed"
msgstr "E882: Помилка у функції порівнÑÐ½Ð½Ñ uniq"
@@ -754,6 +752,10 @@ msgstr "(Ðеможливо)"
msgid "E935: invalid submatch number: %d"
msgstr "E935: неправильний номер групи ÑпівпадіннÑ: %d"
+#, c-format
+msgid "Executing command: \"%s\""
+msgstr "ВиконуєтьÑÑ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð°: «%s»"
+
msgid "Can only call this function in an unmodified buffer"
msgstr "Цю функцію можна викликати тільки у незміненому буфері"
@@ -764,7 +766,6 @@ msgstr "E921: Ðекоректний аргумент функції звороÑ
msgid "E80: Error while writing: %s"
msgstr "E80: Помилка під Ñ‡Ð°Ñ Ð·Ð°Ð¿Ð¸Ñу: %s"
-#. Using %s, p and not %c, *p to preserve multibyte characters
#, c-format
msgid "E5060: Unknown flag: %s"
msgstr "E5060: Ðевідомий прапорець: %s"
@@ -781,6 +782,10 @@ msgid "E80: Error when closing file %s: %s"
msgstr "E80: Помилка при закритті файлу %s: %s"
#, c-format
+msgid "E963: setting %s to value with wrong type"
+msgstr "E963: вÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ %s до Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð· неправильним типом"
+
+#, c-format
msgid "E794: Cannot set variable in the sandbox: \"%.*s\""
msgstr "E794: Ðе можна вÑтановити змінну у піÑочниці: «%.*s»"
@@ -818,6 +823,10 @@ msgid "E126: Missing :endfunction"
msgstr "E126: Бракує :endfunction"
#, c-format
+msgid "W22: Text found after :endfunction: %s"
+msgstr "W22: ТрапивÑÑ Ñ‚ÐµÐºÑÑ‚ піÑÐ»Ñ :endfunction: %s"
+
+#, c-format
msgid "E707: Function name conflicts with variable: %s"
msgstr "E707: Ðазва функції Ñпівпадає зі змінною: %s"
@@ -1091,8 +1100,6 @@ msgstr "чаÑтковий Ñловник self"
msgid "itself"
msgstr "Ñам Ñебе"
-#. Only give this message once for a recursive call to avoid
-#. flooding the user with errors.
msgid "E724: unable to correctly dump variable with self-referencing container"
msgstr ""
"E724: не вдалоÑÑ ÐºÐ¾Ñ€ÐµÐºÑ‚Ð½Ð¾ злити змінну з контейнером, Ñкий Ñам на Ñебе "
@@ -1244,10 +1251,22 @@ msgid "connection refused"
msgstr "з'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð²Ñ–Ð´Ð¼Ð¾Ð²Ð»ÐµÐ½Ð¾"
#, c-format
+msgid "<%s>%s%s %d, Hex %02x, Oct %03o, Digr %s"
+msgstr "<%s>%s%s %d, шіÑÑ‚ %02x, Ð²Ñ–Ñ %03o, дигр %s"
+
+#, c-format
msgid "<%s>%s%s %d, Hex %02x, Octal %03o"
msgstr "<%s>%s%s %d, шіÑÑ‚ %02x, Ð²Ñ–Ñ %03o"
#, c-format
+msgid "> %d, Hex %04x, Oct %o, Digr %s"
+msgstr "> %d, шіÑÑ‚ %04x, Ð²Ñ–Ñ %o, дигр %s"
+
+#, c-format
+msgid "> %d, Hex %08x, Oct %o, Digr %s"
+msgstr "> %d, шіÑÑ‚ %08x, Ð²Ñ–Ñ %o, дигр %s"
+
+#, c-format
msgid "> %d, Hex %04x, Octal %o"
msgstr "> %d, шіÑÑ‚ %04x, Ð²Ñ–Ñ %o"
@@ -1255,8 +1274,8 @@ msgstr "> %d, шіÑÑ‚ %04x, Ð²Ñ–Ñ %o"
msgid "> %d, Hex %08x, Octal %o"
msgstr "> %d, шіÑÑ‚ %08x, Ð²Ñ–Ñ %o"
-msgid "E134: Move lines into themselves"
-msgstr "E134: Ðеможливо переміÑтити Ñ€Ñдки Ñамі в Ñебе"
+msgid "E134: Cannot move a range of lines into itself"
+msgstr "E134: Ðеможливо переміÑтити діапазон Ñ€Ñдків Ñам у Ñебе"
msgid "1 line moved"
msgstr "Переміщено один Ñ€Ñдок"
@@ -1367,8 +1386,8 @@ msgstr " в одному Ñ€Ñдку"
msgid " on %<PRId64> lines"
msgstr " в %<PRId64> Ñ€Ñдках"
-msgid "E147: Cannot do :global recursive"
-msgstr "E147: :global не можна рекурÑивно"
+msgid "E147: Cannot do :global recursive with a range"
+msgstr "E147: :global не можна рекурÑивно з діапазоном"
msgid "E148: Regular expression missing from global"
msgstr "E148: У global бракує зразка"
@@ -1505,8 +1524,9 @@ msgstr "E750: Спочатку зробіть «:profile start {файл}»"
msgid "Save changes to \"%s\"?"
msgstr "Зберегти зміни в «%s»?"
-msgid "Untitled"
-msgstr "Ðеназваний"
+#, c-format
+msgid "Close \"%s\"?"
+msgstr "Закрити «%s»?"
#, c-format
msgid "E162: No write since last change for buffer \"%s\""
@@ -1604,8 +1624,6 @@ msgstr "Мова (%s): «%s»"
msgid "E197: Cannot set language to \"%s\""
msgstr "E197: Ðе вдалоÑÑ Ð²Ñтановити мову «%s»"
-#. don't redisplay the window
-#. don't wait for return
msgid "Entering Ex mode. Type \"visual\" to go to Normal mode."
msgstr "Режим Ex. Ð”Ð»Ñ Ð¿Ð¾Ð²ÐµÑ€Ð½ÐµÐ½Ð½Ñ Ð´Ð¾ нормального режиму виконайте «visual»"
@@ -1640,8 +1658,6 @@ msgstr "E493: Інтервал задано навиворіт"
msgid "Backwards range given, OK to swap"
msgstr "Інтервал задано навиворіт, щоб помінÑти міÑцÑми — ГÐРÐЗД"
-#. append
-#. typed wrong
msgid "E494: Use w or w>>"
msgstr "E494: Спробуйте w або w>>"
@@ -1765,7 +1781,6 @@ msgstr "E189: Файл «%s» Ñ–Ñнує (! щоб не зважати)"
msgid "E190: Cannot open \"%s\" for writing"
msgstr "E190: Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ «%s» Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñу"
-#. set mark
msgid "E191: Argument must be a letter or forward/backward quote"
msgstr "E191: Ðргумент має бути літерою, ` або '"
@@ -1797,15 +1812,16 @@ msgstr "E499: Ðазва файлу Ð´Ð»Ñ '%' чи '#' порожнÑ, прац
msgid "E500: Evaluates to an empty string"
msgstr "E500: Результат — порожній Ñ€Ñдок"
+msgid "Untitled"
+msgstr "Ðеназваний"
+
msgid "E608: Cannot :throw exceptions with 'Vim' prefix"
msgstr "E608: Ðе можна викидати (:throw) винÑтки з префікÑом 'Vim'"
-#. always scroll up, don't overwrite
#, c-format
msgid "Exception thrown: %s"
msgstr "ВинÑткова ÑитуаціÑ: %s"
-#. always scroll up, don't overwrite
#, c-format
msgid "Exception finished: %s"
msgstr "ВинÑток закінчено: %s"
@@ -1818,7 +1834,6 @@ msgstr "ВинÑток Ñкинуто: %s"
msgid "%s, line %<PRId64>"
msgstr "%s, Ñ€Ñдок %<PRId64>"
-#. always scroll up, don't overwrite
#, c-format
msgid "Exception caught: %s"
msgstr "Спіймано винÑткову Ñитуацію: %s"
@@ -1844,7 +1859,6 @@ msgstr "Помилка, перервано"
msgid "Error"
msgstr "Помилка"
-#. if (pending & CSTP_INTERRUPT)
msgid "Interrupt"
msgstr "Перервано"
@@ -1887,15 +1901,12 @@ msgstr "E601: Забагато вкладених :try"
msgid "E603: :catch without :try"
msgstr "E603: :catch без :try"
-#. Give up for a ":catch" after ":finally" and ignore it.
-#. * Just parse.
msgid "E604: :catch after :finally"
msgstr "E604: :catch піÑÐ»Ñ :finally"
msgid "E606: :finally without :try"
msgstr "E606: :finally без :try"
-#. Give up for a multiple ":finally" and ignore it.
msgid "E607: multiple :finally"
msgstr "E607: Ðе одне :finally"
@@ -1927,8 +1938,8 @@ msgid "E5401: List item %i is not a List"
msgstr "E5401: Елемент ÑпиÑку %i не List"
#, c-format
-msgid "E5402: List item %i has incorrect length: %li /= 3"
-msgstr "E5402: Елемент ÑпиÑку %i має неправильну довжину: %li /= 3"
+msgid "E5402: List item %i has incorrect length: %d /= 3"
+msgstr "E5402: Елемент ÑпиÑку %i має неправильну довжину: %d /= 3"
msgid "E5403: Chunk %i start %"
msgstr "E5403: Початок шматка %i %"
@@ -2002,8 +2013,6 @@ msgstr "[Ðовий файл]"
msgid "[New DIRECTORY]"
msgstr "[Ðовий каталог]"
-#. libuv only returns -errno in Unix and in Windows open() does not
-#. set EOVERFLOW
msgid "[File too big]"
msgstr "[Файл завеликий]"
@@ -2016,23 +2025,18 @@ msgstr "E200: Ðвтокоманди *ReadPre унеможливили читаÐ
msgid "E201: *ReadPre autocommands must not change current buffer"
msgstr "E201: Ðвтокоманди *ReadPre не повинні змінювати цей буфер"
-#. Re-opening the original file failed!
msgid "E202: Conversion made file unreadable!"
msgstr "E202: ÐšÐ¾Ð½Ð²ÐµÑ€Ñ‚Ð°Ñ†Ñ–Ñ ÑƒÐ½ÐµÐ¼Ð¾Ð¶Ð»Ð¸Ð²Ð¸Ð»Ð° Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñƒ!"
-#. fifo or socket
msgid "[fifo/socket]"
msgstr "[канал/Ñокет]"
-#. fifo
msgid "[fifo]"
msgstr "[канал]"
-#. or socket
msgid "[socket]"
msgstr "[Ñокет]"
-#. or character special
msgid "[character special]"
msgstr "[Ñпец. Ñимвольний]"
@@ -2098,7 +2102,6 @@ msgstr "E509: Ðе вдалоÑÑ Ñтворити резервну копію (
msgid "E510: Can't make backup file (add ! to override)"
msgstr "E510: Ðе вдалоÑÑ Ð·Ñ€Ð¾Ð±Ð¸Ñ‚Ð¸ резервну копію (! щоб не зважати)"
-#. Can't write without a tempfile!
msgid "E214: Can't find temp file for writing"
msgstr "E214: Ðе вдалоÑÑ Ð¿Ñ–Ð´ÑˆÑƒÐºÐ°Ñ‚Ð¸ тимчаÑовий файл Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñу"
@@ -2163,7 +2166,6 @@ msgstr "E206: ЛатаннÑ: не вдалоÑÑ Ñтворити оригінÐ
msgid "E207: Can't delete backup file"
msgstr "E207: Ðе вдалоÑÑ Ð·Ð½Ð¸Ñ‰Ð¸Ñ‚Ð¸ резервний файл"
-#. Set highlight for error messages.
msgid ""
"\n"
"WARNING: Original file may be lost or damaged\n"
@@ -2212,9 +2214,6 @@ msgstr "[Ðеповний оÑтанній Ñ€Ñдок]"
msgid "[noeol]"
msgstr "[noeol]"
-#. Don't overwrite messages here.
-#. Must give this prompt.
-#. Don't use emsg() here, don't want to flush the buffers.
msgid "WARNING: The file has been changed since reading it!!!"
msgstr "ЗÐСТЕРЕЖЕÐÐЯ: Файл змінивÑÑ Ð· чаÑу оÑтаннього читаннÑ!!!"
@@ -2292,7 +2291,6 @@ msgstr "--Знищено--"
msgid "auto-removing autocommand: %s <buffer=%d>"
msgstr "Ðвтоматичне Ð·Ð½Ð¸Ñ‰ÐµÐ½Ð½Ñ Ð°Ð²Ñ‚Ð¾ÐºÐ¾Ð¼Ð°Ð½Ð´Ð¸: %s <буфер=%d>"
-#. the group doesn't exist
#, c-format
msgid "E367: No such group: \"%s\""
msgstr "E367: Ðемає такої групи: «%s»"
@@ -2315,10 +2313,9 @@ msgstr "E216: Ðемає такої події: %s"
msgid "E216: No such group or event: %s"
msgstr "E216: Ðемає такої групи чи події: %s"
-#. Highlight title
msgid ""
"\n"
-"--- Auto-Commands ---"
+"--- Autocommands ---"
msgstr ""
"\n"
"--- Ðвтокоманди ---"
@@ -2337,8 +2334,8 @@ msgid "E218: autocommand nesting too deep"
msgstr "E218: Забагато вкладених автокоманд"
#, c-format
-msgid "%s Auto commands for \"%s\""
-msgstr "Ðвтокоманди %s Ð´Ð»Ñ Â«%s»"
+msgid "%s Autocommands for \"%s\""
+msgstr "%s Ðвтокоманди Ð´Ð»Ñ Â«%s»"
#, c-format
msgid "Executing %s"
@@ -2363,7 +2360,6 @@ msgstr "E350: Ðе вдалоÑÑ Ñтворити згортку методом
msgid "E351: Cannot delete fold with current 'foldmethod'"
msgstr "E351: Ðе вдалоÑÑ Ð·Ð½Ð¸Ñ‰Ð¸Ñ‚Ð¸ згортку методом 'foldmethod'"
-#. buffer has already been read
msgid "E222: Add to read buffer"
msgstr "E222: Додати до буфера читаннÑ"
@@ -2395,17 +2391,9 @@ msgstr "Заміни клавіш не знайдено"
msgid "E228: makemap: Illegal mode"
msgstr "E228: makemap: ÐеприпуÑтимий режим"
-#. /< key value of 'cedit' option
-#. /< type of cmdline window or 0
-#. /< result of cmdline window or 0
-#. /< cmdline recursion level
msgid "--No lines in buffer--"
msgstr "--Жодного Ñ€Ñдка--"
-#.
-#. * The error messages that can be shared are included here.
-#. * Excluded are errors that are only used once and debugging messages.
-#.
msgid "E470: Command aborted"
msgstr "E470: Команду перервано"
@@ -2516,7 +2504,8 @@ msgstr "E906: Ðекоректний потік Ð´Ð»Ñ ÐºÐ°Ð½Ð°Ð»Ñƒ rpc, use 'rp
msgid ""
"E5210: dict key '%s' already set for buffered stream in channel %<PRIu64>"
msgstr ""
-"E5210: ключ Ñловника '%s' вже вÑтановлено Ð´Ð»Ñ Ð±ÑƒÑ„ÐµÑ€Ð¸Ð·Ð¾Ð²Ð°Ð½Ð¾Ð³Ð¾ потоку у каналі %<PRIu64>"
+"E5210: ключ Ñловника '%s' вже вÑтановлено Ð´Ð»Ñ Ð±ÑƒÑ„ÐµÑ€Ð¸Ð·Ð¾Ð²Ð°Ð½Ð¾Ð³Ð¾ потоку у каналі "
+"%<PRIu64>"
#, c-format
msgid "E364: Library call failed for \"%s()\""
@@ -2741,6 +2730,9 @@ msgstr "E850: Ðеправильна назва регіÑтру"
msgid "E919: Directory not found in '%s': \"%s\""
msgstr "E919: Каталог не знайдено у '%s': «%s»"
+msgid "E952: Autocommand caused recursive behavior"
+msgstr "E952: Ðвтокоманди призвели до рекурÑÑ–Ñ—"
+
msgid "E519: Option not supported"
msgstr "E519: ÐžÐ¿Ñ†Ñ–Ñ Ð½Ðµ підтримуєтьÑÑ"
@@ -2864,6 +2856,9 @@ msgstr "E365: Ðе вдалоÑÑ Ð½Ð°Ð´Ñ€ÑƒÐºÑƒÐ²Ð°Ñ‚Ð¸ файл PostScript"
msgid "Print job sent."
msgstr "Ð—Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð´Ñ€ÑƒÐºÑƒ відіÑлано."
+msgid "E424: Too many different highlighting attributes in use"
+msgstr "E424: ВикориÑтано забагато різних атрибутів кольору"
+
msgid "Add a new database"
msgstr "Додати нову базу даних"
@@ -2988,7 +2983,6 @@ msgstr "E261: З'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð· cscope %s не знайдено"
msgid "cscope connection %s closed"
msgstr "З'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð· cscope %s закінчено"
-#. should not reach here
msgid "E570: fatal error in cs_manage_matches"
msgstr "E570: Фатальна помилка в cs_manage_matches"
@@ -2996,7 +2990,6 @@ msgstr "E570: Фатальна помилка в cs_manage_matches"
msgid "Cscope tag: %s"
msgstr "Мітка cscope: %s"
-#. Column headers for match number, line number and filename.
msgid ""
"\n"
" # line"
@@ -3028,8 +3021,8 @@ msgid ""
"E5100: Cannot convert given lua table: table should either have a sequence "
"of positive integer keys or contain only string keys"
msgstr ""
-"E5100: Ðе вдалоÑÑ Ð¿ÐµÑ€ÐµÑ‚Ð²Ð¾Ñ€Ð¸Ñ‚Ð¸ таблицю lua: Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ Ð¿Ð¾Ð²Ð¸Ð½Ð½Ð° мати поÑлідовніÑть "
-"додатних чиÑел Ñк ключі або текÑтові ключі"
+"E5100: Ðе вдалоÑÑ Ð¿ÐµÑ€ÐµÑ‚Ð²Ð¾Ñ€Ð¸Ñ‚Ð¸ таблицю lua: Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ Ð¿Ð¾Ð²Ð¸Ð½Ð½Ð° мати "
+"поÑлідовніÑть додатних чиÑел Ñк ключі або текÑтові ключі"
msgid "E5101: Cannot convert given lua type"
msgstr "E5101: Ðе вдалоÑÑ Ð¿ÐµÑ€ÐµÑ‚Ð²Ð¾Ñ€Ð¸Ñ‚Ð¸ тип lua"
@@ -3045,7 +3038,6 @@ msgstr "E5106: Помилка ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¼Ð¾Ð´ÑƒÐ»Ñ vim: %.*s"
msgid "E970: Failed to initialize lua interpreter"
msgstr "E970: Ðе вдалоÑÑ Ñ–Ð½Ñ–Ñ†Ñ–Ð°Ð»Ñ–Ð·ÑƒÐ²Ð°Ñ‚Ð¸ інтерпретатор lua"
-#. stack: vim, error
#, c-format
msgid "E5117: Error while updating package paths: %.*s"
msgstr "E5117: Помилка Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ ÑˆÐ»Ñхів пакунку: %.*s"
@@ -3101,7 +3093,6 @@ msgstr "E5112: Помилка ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ ÑˆÐ¼Ð°Ñ‚ÐºÑƒ lua: %.*s"
msgid "E5113: Error while calling lua chunk: %.*s"
msgstr "E5113: Помилка виклику шматку lua: %.*s"
-#. Error messages
msgid "Argument missing after"
msgstr "Пропущено аргумент піÑлÑ"
@@ -3132,7 +3123,6 @@ msgstr "Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ: \"%s\": %s\n
msgid "Cannot open for script output: \""
msgstr "Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ Ñк вихідний файл: \""
-#. just in case..
msgid "pre-vimrc command line"
msgstr "команди перед vimrc"
@@ -3147,7 +3137,6 @@ msgstr ""
"\n"
"ДізнайтеÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ: \""
-#. kill us with CTRL-C here, if you like
msgid "Usage:\n"
msgstr "Вжиток:\n"
@@ -3155,8 +3144,7 @@ msgid " nvim [options] [file ...] Edit file(s)\n"
msgstr " nvim [опції] [файл ...] Редагувати файли\n"
msgid " nvim [options] -t <tag> Edit file where tag is defined\n"
-msgstr ""
-" nvim [опції] -t <мітка> Редагувати файл, де визначено мітку\n"
+msgstr " nvim [опції] -t <мітка> Редагувати файл, де визначено мітку\n"
msgid " nvim [options] -q [errorfile] Edit file with first error\n"
msgstr " nvim [опції] -q [ф.помилки] Редагувати файл з першою помилкою\n"
@@ -3175,7 +3163,8 @@ msgid " + Start at end of file\n"
msgstr " + Розпочати в кінці файлу\n"
msgid " --cmd <cmd> Execute <cmd> before any config\n"
-msgstr " --cmd <команда> Виконати <команду> перед будь-Ñкою конфігурацією\n"
+msgstr ""
+" --cmd <команда> Виконати <команду> перед будь-Ñкою конфігурацією\n"
msgid " +<cmd>, -c <cmd> Execute <cmd> after config and first file\n"
msgstr ""
@@ -3211,13 +3200,13 @@ msgstr ""
"пам'Ñті\n"
msgid " -o[N] Open N windows (default: one per file)\n"
-msgstr ""
-" -o[N] Відкрити N вікон (Ñтандартно: одне на файл)\n"
+msgstr " -o[N] Відкрити N вікон (Ñтандартно: одне на файл)\n"
msgid ""
" -O[N] Open N vertical windows (default: one per file)\n"
msgstr ""
-" -o[N] Відкрити N вертикальних вікон (Ñтандартно: одне на файл)\n"
+" -o[N] Відкрити N вертикальних вікон (Ñтандартно: одне на "
+"файл)\n"
msgid " -p[N] Open N tab pages (default: one per file)\n"
msgstr ""
@@ -3244,19 +3233,18 @@ msgid " -u <config> Use this config file\n"
msgstr " -u <config> Вжити цей файл конфігурації\n"
msgid " -v, --version Print version information\n"
-msgstr ""
-" -v, --version Ðадрукувати інформацію про верÑÑ–ÑŽ програми\n"
+msgstr " -v, --version Ðадрукувати інформацію про верÑÑ–ÑŽ програми\n"
msgid " -V[N][file] Verbose [level][file]\n"
-msgstr ""
-" -V[N][файл] Більше повідомлень [рівень][файл]\n"
+msgstr " -V[N][файл] Більше повідомлень [рівень][файл]\n"
msgid " -Z Restricted mode\n"
msgstr " -Z Обмежений режим\n"
msgid " --api-info Write msgpack-encoded API metadata to stdout\n"
msgstr ""
-" --api-info ЗапиÑати метадані API, Ñеріалізовані у msgpack, у stdout\n"
+" --api-info ЗапиÑати метадані API, Ñеріалізовані у msgpack, у "
+"stdout\n"
msgid " --embed Use stdin/stdout as a msgpack-rpc channel\n"
msgstr ""
@@ -3288,7 +3276,6 @@ msgstr "Ðе вÑтановлено жодної помітки"
msgid "E283: No marks matching \"%s\""
msgstr "E283: Помітку «%s» не знайдено"
-#. Highlight title
msgid ""
"\n"
"mark line col file/text"
@@ -3296,7 +3283,6 @@ msgstr ""
"\n"
"пом. Ñ€Ñд. кол. файл/текÑÑ‚"
-#. Highlight title
msgid ""
"\n"
" jump line col file/text"
@@ -3304,7 +3290,6 @@ msgstr ""
"\n"
" точка Ñ€Ñд. Ñтовп. файл/текÑÑ‚"
-#. Highlight title
msgid ""
"\n"
"change line col text"
@@ -3339,7 +3324,6 @@ msgstr "E298: Ðемає блоку 1?"
msgid "E298: Didn't get block nr 2?"
msgstr "E298: Ðемає блоку 2?"
-#. could not (re)open the swap file, what can we do????
msgid "E301: Oops, lost the swap file!!!"
msgstr "E301: Ой, втрачено файл обміну!!!"
@@ -3353,7 +3337,6 @@ msgstr "E303: Ðе вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ файл обміну длÑ
msgid "E304: ml_upd_block0(): Didn't get block 0??"
msgstr "E304: ml_upd_block0(): Ðемає блоку 0??"
-#. no swap files found
#, c-format
msgid "E305: No swap file found for %s"
msgstr "E305: Ðе знайдено файлу обміну Ð´Ð»Ñ %s"
@@ -3481,7 +3464,6 @@ msgstr ""
"Можливо, тепер ви хочете знищити файл обміну .swp.\n"
"\n"
-#. use msg() to start the scrolling properly
msgid "Swap files found:"
msgstr "Знайдено файли обміну:"
@@ -3555,8 +3537,8 @@ msgstr ""
"\n"
" ID процеÑу: "
-msgid " (still running)"
-msgstr " (виконуєтьÑÑ)"
+msgid " (STILL RUNNING)"
+msgstr " (ЩЕ ВИКОÐУЄТЬСЯ)"
msgid ""
"\n"
@@ -3644,11 +3626,12 @@ msgstr ""
msgid "While opening file \""
msgstr "При відкритті файлу \""
+msgid " CANNOT BE FOUND"
+msgstr " ÐЕ ЗÐÐЙДЕÐО"
+
msgid " NEWER than swap file!\n"
msgstr " ÐОВІШИЙ за файл обміну!\n"
-#. Some of these messages are long to allow translation to
-#. * other languages.
msgid ""
"\n"
"(1) Another program may be editing the same file. If this is the case,\n"
@@ -3720,14 +3703,6 @@ msgstr ""
"&Q:Вийти\n"
"&A:Перервати"
-#.
-#. * Change the ".swp" extension to find another file that can be used.
-#. * First decrement the last char: ".swo", ".swn", etc.
-#. * If that still isn't enough decrement the last but one char: ".svz"
-#. * Can happen when editing many "No Name" buffers.
-#.
-#. ".s?a"
-#. ".saa": tried enough, give up
msgid "E326: Too many swap files found"
msgstr "E326: Знайдено забагато файлів обміну"
@@ -3756,7 +3731,6 @@ msgstr "E328: Меню може бути тільки в іншому режим
msgid "E329: No menu \"%s\""
msgstr "E329: Ðемає меню «%s»"
-#. Only a mnemonic or accelerator is not valid.
msgid "E792: Empty menu name"
msgstr "E792: ÐŸÐ¾Ñ€Ð¾Ð¶Ð½Ñ Ð½Ð°Ð·Ð²Ð° меню"
@@ -3769,8 +3743,6 @@ msgstr "E331: Ðе можна додавати елементи меню проÑ
msgid "E332: Separator cannot be part of a menu path"
msgstr "E332: Роздільник не може бути чаÑтиною шлÑху меню"
-#. Now we have found the matching menu, and we list the mappings
-#. Highlight title
msgid ""
"\n"
"--- Menus ---"
@@ -3878,15 +3850,6 @@ msgstr " (Перервано)"
msgid "Beep!"
msgstr "Дзень!"
-#, c-format
-msgid "Calling shell to execute: \"%s\""
-msgstr "ВикликаєтьÑÑ Ð¾Ð±Ð¾Ð»Ð¾Ð½ÐºÐ° щоб виконати: «%s»"
-
-#.
-#. * nv_*(): functions called to handle Normal and Visual mode commands.
-#. * n_*(): functions called to handle Normal mode commands.
-#. * v_*(): functions called to handle Visual mode commands.
-#.
msgid "E349: No identifier under cursor"
msgstr "E349: Ðемає ідентифікатора над курÑором"
@@ -3912,7 +3875,8 @@ msgid "E663: At end of changelist"
msgstr "E663: Кінець ÑпиÑку змін"
msgid "Type :qa! and press <Enter> to abandon all changes and exit Nvim"
-msgstr "Введіть :qa! Ñ– натиÑніÑть <Enter> щоб відкинути вÑÑ– зміни Ñ– вийти Nvim"
+msgstr ""
+"Введіть :qa! Ñ– натиÑніÑть <Enter> щоб відкинути вÑÑ– зміни Ñ– вийти Nvim"
#, c-format
msgid "1 line %sed 1 time"
@@ -3951,25 +3915,30 @@ msgstr "Один Ñ€Ñдок змінено"
msgid "%<PRId64> lines changed"
msgstr "Змінено Ñ€Ñдків: %<PRId64>"
-msgid "block of 1 line yanked"
-msgstr "Запам'Ñтав блок з одного Ñ€Ñдка"
+#, c-format
+msgid " into \"%c"
+msgstr " у \"%c"
+
+#, c-format
+msgid "block of 1 line yanked%s"
+msgstr "Запам'Ñтав блок з одного Ñ€Ñдка%s"
-msgid "1 line yanked"
-msgstr "Запам'Ñтав один Ñ€Ñдок"
+#, c-format
+msgid "1 line yanked%s"
+msgstr "Запам'Ñтав один Ñ€Ñдок%s"
#, c-format
-msgid "block of %<PRId64> lines yanked"
-msgstr "Запам'Ñтав блок із %<PRId64> Ñ€Ñдків"
+msgid "block of %<PRId64> lines yanked%s"
+msgstr "Запам'Ñтав блок із %<PRId64> Ñ€Ñдків%s"
#, c-format
-msgid "%<PRId64> lines yanked"
-msgstr "Запам'Ñтав Ñ€Ñдків: %<PRId64>"
+msgid "%<PRId64> lines yanked%s"
+msgstr "Запам'Ñтав Ñ€Ñдків: %<PRId64>%s"
#, c-format
msgid "E353: Nothing in register %s"
msgstr "E353: У регіÑтрі %s нічого немає"
-#. Highlight title
msgid ""
"\n"
"--- Registers ---"
@@ -4023,7 +3992,6 @@ msgstr ""
msgid "(+%<PRId64> for BOM)"
msgstr "(+%<PRId64> Ð´Ð»Ñ BOM)"
-#. found a mismatch: skip
msgid "E518: Unknown option"
msgstr "E518: Ðевідома опціÑ"
@@ -4111,9 +4079,6 @@ msgstr "E594: Потрібно щонайменше %d Ñтовпців"
msgid "E355: Unknown option: %s"
msgstr "E355: Ðевідома опціÑ: %s"
-#. There's another character after zeros or the string
-#. is empty. In both cases, we are trying to set a
-#. num option using a string.
#, c-format
msgid "E521: Number required: &%s = '%s'"
msgstr "E521: Потрібно вказати Number: &%s = '%s'"
@@ -4175,8 +4140,6 @@ msgstr ""
"\n"
"не вдалоÑÑ Ð·Ð°Ð¿ÑƒÑтити оболонку: "
-#. Can happen if system() tries to send input to a shell command that was
-#. backgrounded (:call system("cat - &", "foo")). #3529 #5241
#, c-format
msgid "E5677: Error writing input to shell-command: %s"
msgstr "E5677: Ðе вдалоÑÑ Ð·Ð°Ð¿Ð¸Ñати на вхід команди оболонки: %s"
@@ -4222,7 +4185,6 @@ msgstr "E376: Помилковий `%%%c' у префікÑÑ– Ñ€Ñдку форÐ
msgid "E377: Invalid %%%c in format string"
msgstr "E377: Помилковий `%%%c' у Ñ€Ñдку формату"
-#. nothing found
msgid "E378: 'errorformat' contains no pattern"
msgstr "E378: 'errorformat' не міÑтить зразок"
@@ -4306,8 +4268,8 @@ msgstr "E55: Ðемає пари %s)"
msgid "E66: \\z( not allowed here"
msgstr "E66: \\z( тут не дозволено"
-msgid "E67: \\z1 et al. not allowed here"
-msgstr "E67: \\z1 та ін. тут не дозволено"
+msgid "E67: \\z1 - \\z9 not allowed here"
+msgstr "E67: \\z1 - \\z9 тут не дозволено"
#, c-format
msgid "E69: Missing ] after %s%%["
@@ -4401,10 +4363,10 @@ msgid " REVERSE"
msgstr " ÐÐВИВОРІТ"
msgid " INSERT"
-msgstr " ВСТÐВКÐ"
+msgstr " ВСТÐВИТИ"
msgid " (insert)"
-msgstr " (вÑтавка)"
+msgstr " (вÑтавити)"
msgid " (replace)"
msgstr " (заміна)"
@@ -4460,7 +4422,6 @@ msgstr "E386: ПіÑÐ»Ñ `;' має бути `?' або `/'"
msgid " (includes previously listed match)"
msgstr " (разом з попередніми збігами)"
-#. cursor at status line
msgid "--- Included files "
msgstr "--- Включені файли "
@@ -4523,8 +4484,8 @@ msgid "System error while writing ShaDa file: %s"
msgstr "СиÑтемна помилка при читанні з файлу ShaDa: %s"
#, c-format
-msgid "Reading ShaDa file \"%s\"%s%s%s"
-msgstr "ЗчитуєтьÑÑ Ñ„Ð°Ð¹Ð» ShaDa: «%s»%s%s%s"
+msgid "Reading ShaDa file \"%s\"%s%s%s%s"
+msgstr "ЗчитуєтьÑÑ Ñ„Ð°Ð¹Ð» ShaDa: «%s»%s%s%s%s"
msgid " info"
msgstr " інформаціÑ"
@@ -4582,8 +4543,6 @@ msgstr ""
"СиÑтемна помилка при відкритті файлу ShaDa %s Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ Ñ‰Ð¾Ð± виконати "
"Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð¿ÐµÑ€ÐµÐ´ запиÑом: %s"
-#. Tried names from .tmp.a to .tmp.z, all failed. Something must be
-#. wrong then.
#, c-format
msgid "E138: All %s.tmp.X files exist, cannot write ShaDa file!"
msgstr "E138: УÑÑ– файли %s.tmp.X зайнÑто, неможливо запиÑати файл ShaDa!"
@@ -4657,12 +4616,8 @@ msgstr ""
msgid ""
"Error while reading ShaDa file: there is an item at position %<PRIu64> that "
"is stated to be too long"
-msgstr ""
-"Помилка Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñƒ ShaDa: Ñ” задовгий елемент у позиції %<PRIu64>"
+msgstr "Помилка Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñƒ ShaDa: Ñ” задовгий елемент у позиції %<PRIu64>"
-#. kSDItemUnknown cannot possibly pass that far because it is -1 and that
-#. will fail in msgpack_read_uint64. But kSDItemMissing may and it will
-#. otherwise be skipped because (1 << 0) will never appear in flags.
#, c-format
msgid ""
"Error while reading ShaDa file: there is an item at position %<PRIu64> that "
@@ -4703,24 +4658,6 @@ msgstr ""
"Помилка при читанні файлу ShaDa: ÑпиÑок буферів у позиції %<PRIu64> міÑтить "
"поле, Ñке не має назву файлу"
-#. values for ts_isdiff
-#. no different byte (yet)
-#. different byte found
-#. inserting character
-#. values for ts_flags
-#. already checked that prefix is OK
-#. tried split at this point
-#. did a delete, "ts_delidx" has index
-#. special values ts_prefixdepth
-#. not using prefixes
-#. walking through the prefix tree
-#. highest value that's not special
-#. mode values for find_word
-#. find word case-folded
-#. find keep-case word
-#. find word after prefix
-#. find case-folded compound word
-#. find keep-case compound word
msgid "E759: Format error in spell file"
msgstr "E759: Помилка формату у файлі орфографії"
@@ -4735,8 +4672,6 @@ msgstr ""
msgid "E797: SpellFileMissing autocommand deleted buffer"
msgstr "E797: Ðвтокоманда SpellFileMissing знищила буфер"
-#. This is probably an error. Give a warning and
-#. accept the words anyway.
#, c-format
msgid "Warning: region %s not supported"
msgstr "ЗаÑтереженнÑ: регіон %s не підтримуєтьÑÑ"
@@ -4748,8 +4683,6 @@ msgstr "Пробачте, немає пропозицій"
msgid "Sorry, only %<PRId64> suggestions"
msgstr "Пробачте, тільки %<PRId64> пропозицій"
-#. for when 'cmdheight' > 1
-#. avoid more prompt
#, c-format
msgid "Change \"%.*s\" to:"
msgstr "Замінити «%.*s» на:"
@@ -4967,8 +4900,8 @@ msgid "E760: No word count in %s"
msgstr "E760: Ðемає кількоÑті Ñлів у %s"
#, c-format
-msgid "line %6d, word %6d - %s"
-msgstr "Ñ€Ñдок %6d, Ñлово %6d - %s"
+msgid "line %6d, word %6ld - %s"
+msgstr "Ñ€Ñдок %6d, Ñлово %6ld - %s"
#, c-format
msgid "Duplicate word in %s line %d: %s"
@@ -4991,32 +4924,36 @@ msgid "Reading word file %s..."
msgstr "ЧитаєтьÑÑ Ñ„Ð°Ð¹Ð» Ñлів %s..."
#, c-format
-msgid "Duplicate /encoding= line ignored in %s line %d: %s"
-msgstr "ÐŸÐ¾Ð²Ñ‚Ð¾Ñ€ÐµÐ½Ð½Ñ Ñ€Ñдка /encoding= проігноровано у %s у Ñ€Ñдку %d: %s"
+msgid "Conversion failure for word in %s line %ld: %s"
+msgstr "Помилка Ð¿ÐµÑ€ÐµÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñлова у %s у Ñ€Ñдку %ld: %s"
+
+#, c-format
+msgid "Duplicate /encoding= line ignored in %s line %ld: %s"
+msgstr "ÐŸÐ¾Ð²Ñ‚Ð¾Ñ€ÐµÐ½Ð½Ñ Ñ€Ñдка /encoding= проігноровано у %s у Ñ€Ñдку %ld: %s"
#, c-format
-msgid "/encoding= line after word ignored in %s line %d: %s"
-msgstr "РÑдок /encoding= піÑÐ»Ñ Ñлова проігноровано у %s у Ñ€Ñдку %d: %s"
+msgid "/encoding= line after word ignored in %s line %ld: %s"
+msgstr "РÑдок /encoding= піÑÐ»Ñ Ñлова проігноровано у %s у Ñ€Ñдку %ld: %s"
#, c-format
-msgid "Duplicate /regions= line ignored in %s line %d: %s"
-msgstr "ÐŸÐ¾Ð²Ñ‚Ð¾Ñ€ÐµÐ½Ð½Ñ Ñ€Ñдка /regions= проігноровано у %s у Ñ€Ñдку %d: %s"
+msgid "Duplicate /regions= line ignored in %s line %ld: %s"
+msgstr "ÐŸÐ¾Ð²Ñ‚Ð¾Ñ€ÐµÐ½Ð½Ñ Ñ€Ñдка /regions= проігноровано у %s у Ñ€Ñдку %ld: %s"
#, c-format
-msgid "Too many regions in %s line %d: %s"
-msgstr "Забагато регіонів у %s у Ñ€Ñдку %d: %s"
+msgid "Too many regions in %s line %ld: %s"
+msgstr "Забагато регіонів у %s у Ñ€Ñдку %ld: %s"
#, c-format
-msgid "/ line ignored in %s line %d: %s"
-msgstr "РÑдок / проігноровано у %s у Ñ€Ñдку %d: %s"
+msgid "/ line ignored in %s line %ld: %s"
+msgstr "РÑдок / проігноровано у %s у Ñ€Ñдку %ld: %s"
#, c-format
-msgid "Invalid region nr in %s line %d: %s"
-msgstr "Ðекоректний номер регіону у %s у Ñ€Ñдку %d: %s"
+msgid "Invalid region nr in %s line %ld: %s"
+msgstr "Ðекоректний номер регіону у %s у Ñ€Ñдку %ld: %s"
#, c-format
-msgid "Unrecognized flags in %s line %d: %s"
-msgstr "Ðерозпізнані прапорці у %s у Ñ€Ñдку %d: %s"
+msgid "Unrecognized flags in %s line %ld: %s"
+msgstr "Ðерозпізнані прапорці у %s у Ñ€Ñдку %ld: %s"
#, c-format
msgid "Ignored %d words with non-ASCII characters"
@@ -5029,8 +4966,6 @@ msgstr "СтиÑнено %d з %d вузлів; залишилоÑÑ %d (%d%%)"
msgid "Reading back spell file..."
msgstr "ПеречитуєтьÑÑ Ñ„Ð°Ð¹Ð» орфографії..."
-#. Go through the trie of good words, soundfold each word and add it to
-#. the soundfold trie.
msgid "Performing soundfolding..."
msgstr "ВиконуєтьÑÑ Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½Ð½Ñ Ð·Ð²ÑƒÐºÑ–Ð²..."
@@ -5053,8 +4988,9 @@ msgstr "Оцінка ÑÐ¿Ð¾Ð¶Ð¸Ð²Ð°Ð½Ð½Ñ Ð¿Ð°Ð¼'Ñті: %d байт"
msgid "E751: Output file name must not have region name"
msgstr "E751: Вихідний файл не повинен мати назву регіону"
-msgid "E754: Only up to 8 regions supported"
-msgstr "E754: ПідтримуєтьÑÑ Ñ‚Ñ–Ð»ÑŒÐºÐ¸ до воÑьми регіонів"
+#, c-format
+msgid "E754: Only up to %d regions supported"
+msgstr "E754: ПідтримуєтьÑÑ Ñ‚Ñ–Ð»ÑŒÐºÐ¸ до %d регіонів"
#, c-format
msgid "E755: Invalid region in %s"
@@ -5085,8 +5021,6 @@ msgstr "Слово '%.*s' додано до %s"
msgid "E763: Word characters differ between spell files"
msgstr "E763: Символи у Ñлові відрізнÑютьÑÑ Ñƒ файлах орфографії"
-#. This should have been checked when generating the .spl
-#. file.
msgid "E783: duplicate char in MAP entry"
msgstr "E783: Повторено Ñимвол у елементі MAP"
@@ -5102,11 +5036,11 @@ msgstr "E767: Забагато аргументів Ð´Ð»Ñ printf()"
msgid "No Syntax items defined for this buffer"
msgstr "Ð”Ð»Ñ Ð±ÑƒÑ„ÐµÑ€Ð° не визначено елементів ÑинтакÑиÑу"
-msgid "syn conceal on"
-msgstr "Ð¿Ñ€Ð¸Ñ…Ð¾Ð²ÑƒÐ²Ð°Ð½Ð½Ñ ÑƒÐ²Ñ–Ð¼Ðº"
+msgid "syntax conceal on"
+msgstr "ÑинтакÑичне Ð¿Ñ€Ð¸Ñ…Ð¾Ð²ÑƒÐ²Ð°Ð½Ð½Ñ ÑƒÐ²Ñ–Ð¼Ðº"
-msgid "syn conceal off"
-msgstr "Ð¿Ñ€Ð¸Ñ…Ð¾Ð²ÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ð¸Ð¼Ðº"
+msgid "syntax conceal off"
+msgstr "ÑинтакÑичне Ð¿Ñ€Ð¸Ñ…Ð¾Ð²ÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ð¸Ð¼Ðº"
#, c-format
msgid "E390: Illegal argument: %s"
@@ -5224,7 +5158,6 @@ msgstr "E848: Забагато ÑинтакÑичних клаÑтерів"
msgid "E400: No cluster specified"
msgstr "E400: КлаÑтер не вказано"
-#. end delimiter not found
#, c-format
msgid "E401: Pattern delimiter not found: %s"
msgstr "E401: Кінець зразку не знайдено: %s"
@@ -5318,9 +5251,6 @@ msgstr "E421: Ðерозпізнана назва або номер кольор
msgid "E423: Illegal argument: %s"
msgstr "E423: Ðеправильний аргумент: %s"
-msgid "E424: Too many different highlighting attributes in use"
-msgstr "E424: ВикориÑтано забагато різних атрибутів кольору"
-
msgid "E669: Unprintable character in group name"
msgstr "E669: Ðедруковний Ñимвол у назві групи"
@@ -5359,7 +5289,6 @@ msgstr "E428: Це вже оÑÑ‚Ð°Ð½Ð½Ñ Ð²Ñ–Ð´Ð¿Ð¾Ð²Ñ–Ð´Ð½Ð° мітка"
msgid "File \"%s\" does not exist"
msgstr "Файл «%s» не Ñ–Ñнує"
-#. Give an indication of the number of matching tags
#, c-format
msgid "tag %d of %d%s"
msgstr "мітка %d з %d%s"
@@ -5374,7 +5303,6 @@ msgstr " ВикориÑтано мітку, не розрізнÑючи велÐ
msgid "E429: File \"%s\" does not exist"
msgstr "E429: Файл «%s» не Ñ–Ñнує"
-#. Highlight title
msgid ""
"\n"
" # TO tag FROM line in file/text"
@@ -5401,7 +5329,6 @@ msgstr "Перед байтом %<PRId64>"
msgid "E432: Tags file not sorted: %s"
msgstr "E432: Файл теґів не впорÑдкований: %s"
-#. never opened any tags file
msgid "E433: No tags file"
msgstr "E433: Ðемає файлу теґів"
@@ -5415,8 +5342,6 @@ msgstr "E435: Ðе вдалоÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ мітку, тільки прип
msgid "Duplicate field name: %s"
msgstr "Ðазва Ð¿Ð¾Ð»Ñ Ð¿Ð¾Ð²Ñ‚Ð¾Ñ€ÑŽÑ”Ñ‚ÑŒÑÑ: %s"
-#. This happens when the FileChangedRO autocommand changes the
-#. * file in a way it becomes shorter.
msgid "E881: Line count changed unexpectedly"
msgstr "E881: КількіÑть Ñ€Ñдків неÑподівано змінилаÑÑ"
@@ -5572,8 +5497,8 @@ msgstr " заміна Ð´Ð»Ñ $VIMRUNTIME: \""
msgid "Nvim is open source and freely distributable"
msgstr "Nvim — це відкрита й вільно розповÑюджувана програма"
-msgid "https://neovim.io/community"
-msgstr "https://neovim.io/community"
+msgid "https://neovim.io/#chat"
+msgstr "https://neovim.io/#chat"
msgid "type :help nvim<Enter> if you are new! "
msgstr ":help nvim<Enter> Ñкщо ви вперше! "
@@ -5628,17 +5553,6 @@ msgstr "E15: Ðерозпізнаний Ñимвол: %.*s"
msgid "E15: Operator is not associative: %.*s"
msgstr "E15: Оператор не аÑоціативний: %.*s"
-#. / Record missing operator: for things like
-#. /
-#. / :echo @a @a
-#. /
-#. / (allowed) or
-#. /
-#. / :echo (@a @a)
-#. /
-#. / (parsed as OpMissing(@a, @a)).
-#. Multiple expressions allowed, return without calling
-#. viml_parser_advance().
#, c-format
msgid "E15: Missing operator: %.*s"
msgstr "E15: Бракує оператора: %.*s"
@@ -5705,7 +5619,6 @@ msgstr "E15: ОчікуєтьÑÑ Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ, отримано праву
msgid "E15: Don't know what figure brace means: %.*s"
msgstr "E15: Ðе знаю, що означає фігурна дужка: %.*s"
-#. Only first branch is valid.
#, c-format
msgid "E15: Unexpected arrow: %.*s"
msgstr "E15: Ðеочікувано Ñтрілка: %.*s"
@@ -5744,7 +5657,8 @@ msgstr "E115: Бракує одинарних лапок: %.*s"
#, c-format
msgid "E475: Expected closing bracket to end list assignment lvalue: %.*s"
-msgstr "E475: ОчікуєтьÑÑ Ð¿Ñ€Ð°Ð²Ð° квадратна дужка щоб закінчити приÑÐ²Ð¾Ñ”Ð½Ð½Ñ ÑпиÑку: %.*s"
+msgstr ""
+"E475: ОчікуєтьÑÑ Ð¿Ñ€Ð°Ð²Ð° квадратна дужка щоб закінчити приÑÐ²Ð¾Ñ”Ð½Ð½Ñ ÑпиÑку: %.*s"
#, c-format
msgid "E15: Misplaced assignment: %.*s"
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index 51a7dd670f..d9e307bb71 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -2661,6 +2661,8 @@ void ex_copen(exarg_T *eap)
}
}
} else {
+ int flags = 0;
+
qf_buf = qf_find_buf(qi);
/* The current window becomes the previous window afterwards. */
@@ -2668,11 +2670,17 @@ void ex_copen(exarg_T *eap)
if ((eap->cmdidx == CMD_copen || eap->cmdidx == CMD_cwindow)
&& cmdmod.split == 0)
- /* Create the new window at the very bottom, except when
- * :belowright or :aboveleft is used. */
+ // Create the new quickfix window at the very bottom, except when
+ // :belowright or :aboveleft is used.
win_goto(lastwin);
- if (win_split(height, WSP_BELOW | WSP_NEWLOC) == FAIL)
- return; /* not enough room for window */
+ // Default is to open the window below the current window
+ if (cmdmod.split == 0) {
+ flags = WSP_BELOW;
+ }
+ flags |= WSP_NEWLOC;
+ if (win_split(height, flags) == FAIL) {
+ return; // not enough room for window
+ }
RESET_BINDING(curwin);
if (eap->cmdidx == CMD_lopen || eap->cmdidx == CMD_lwindow) {
diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c
index 15a701f022..d62a009fbc 100644
--- a/src/nvim/regexp.c
+++ b/src/nvim/regexp.c
@@ -485,7 +485,7 @@ static char_u e_unmatchedpp[] = N_("E53: Unmatched %s%%(");
static char_u e_unmatchedp[] = N_("E54: Unmatched %s(");
static char_u e_unmatchedpar[] = N_("E55: Unmatched %s)");
static char_u e_z_not_allowed[] = N_("E66: \\z( not allowed here");
-static char_u e_z1_not_allowed[] = N_("E67: \\z1 et al. not allowed here");
+static char_u e_z1_not_allowed[] = N_("E67: \\z1 - \\z9 not allowed here");
static char_u e_missing_sb[] = N_("E69: Missing ] after %s%%[");
static char_u e_empty_sb[] = N_("E70: Empty %s%%[]");
#define NOT_MULTI 0
@@ -1952,7 +1952,7 @@ static char_u *regatom(int *flagp)
{
c = no_Magic(getchr());
switch (c) {
- case '(': if (reg_do_extmatch != REX_SET)
+ case '(': if ((reg_do_extmatch & REX_SET) == 0)
EMSG_RET_NULL(_(e_z_not_allowed));
if (one_exactly)
EMSG_ONE_RET_NULL;
@@ -1971,7 +1971,7 @@ static char_u *regatom(int *flagp)
case '6':
case '7':
case '8':
- case '9': if (reg_do_extmatch != REX_USE)
+ case '9': if ((reg_do_extmatch & REX_USE) == 0)
EMSG_RET_NULL(_(e_z1_not_allowed));
ret = regnode(ZREF + c - '0');
re_has_z = REX_USE;
@@ -7257,15 +7257,13 @@ int vim_regexec_nl(regmatch_T *rmp, char_u *line, colnr_T col)
return vim_regexec_both(rmp, line, col, true);
}
-/*
- * Match a regexp against multiple lines.
- * "rmp->regprog" is a compiled regexp as returned by vim_regcomp().
- * Note: "rmp->regprog" may be freed and changed.
- * Uses curbuf for line count and 'iskeyword'.
- *
- * Return zero if there is no match. Return number of lines contained in the
- * match otherwise.
- */
+/// Match a regexp against multiple lines.
+/// "rmp->regprog" must be a compiled regexp as returned by vim_regcomp().
+/// Note: "rmp->regprog" may be freed and changed, even set to NULL.
+/// Uses curbuf for line count and 'iskeyword'.
+///
+/// Return zero if there is no match. Return number of lines contained in the
+/// match otherwise.
long vim_regexec_multi(
regmmatch_T *rmp,
win_T *win, /* window in which to search or NULL */
@@ -7297,7 +7295,12 @@ long vim_regexec_multi(
p_re = BACKTRACKING_ENGINE;
vim_regfree(rmp->regprog);
report_re_switch(pat);
+ // checking for \z misuse was already done when compiling for NFA,
+ // allow all here
+ reg_do_extmatch = REX_ALL;
rmp->regprog = vim_regcomp(pat, re_flags);
+ reg_do_extmatch = 0;
+
if (rmp->regprog != NULL) {
result = rmp->regprog->engine->regexec_multi(rmp, win, buf, lnum, col,
tm);
diff --git a/src/nvim/regexp.h b/src/nvim/regexp.h
index 97595c4d29..74ed34188c 100644
--- a/src/nvim/regexp.h
+++ b/src/nvim/regexp.h
@@ -5,19 +5,20 @@
#include "nvim/buffer_defs.h"
#include "nvim/regexp_defs.h"
-/* Second argument for vim_regcomp(). */
-#define RE_MAGIC 1 /* 'magic' option */
-#define RE_STRING 2 /* match in string instead of buffer text */
-#define RE_STRICT 4 /* don't allow [abc] without ] */
-#define RE_AUTO 8 /* automatic engine selection */
+// Second argument for vim_regcomp().
+#define RE_MAGIC 1 ///< 'magic' option
+#define RE_STRING 2 ///< match in string instead of buffer text
+#define RE_STRICT 4 ///< don't allow [abc] without ]
+#define RE_AUTO 8 ///< automatic engine selection
-/* values for reg_do_extmatch */
-#define REX_SET 1 /* to allow \z\(...\), */
-#define REX_USE 2 /* to allow \z\1 et al. */
+// values for reg_do_extmatch
+#define REX_SET 1 ///< to allow \z\(...\),
+#define REX_USE 2 ///< to allow \z\1 et al.
+#define REX_ALL (REX_SET | REX_USE)
-/* regexp.c */
+// regexp.c
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "regexp.h.generated.h"
#endif
-#endif /* NVIM_REGEXP_H */
+#endif // NVIM_REGEXP_H
diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c
index fe18cb4389..08ef7da9c1 100644
--- a/src/nvim/regexp_nfa.c
+++ b/src/nvim/regexp_nfa.c
@@ -1367,20 +1367,23 @@ static int nfa_regatom(void)
case '7':
case '8':
case '9':
- /* \z1...\z9 */
- if (reg_do_extmatch != REX_USE)
+ // \z1...\z9
+ if ((reg_do_extmatch & REX_USE) == 0) {
EMSG_RET_FAIL(_(e_z1_not_allowed));
+ }
EMIT(NFA_ZREF1 + (no_Magic(c) - '1'));
/* No need to set nfa_has_backref, the sub-matches don't
* change when \z1 .. \z9 matches or not. */
re_has_z = REX_USE;
break;
case '(':
- /* \z( */
- if (reg_do_extmatch != REX_SET)
+ // \z(
+ if (reg_do_extmatch != REX_SET) {
EMSG_RET_FAIL(_(e_z_not_allowed));
- if (nfa_reg(REG_ZPAREN) == FAIL)
- return FAIL; /* cascaded error */
+ }
+ if (nfa_reg(REG_ZPAREN) == FAIL) {
+ return FAIL; // cascaded error
+ }
re_has_z = REX_SET;
break;
default:
@@ -5052,10 +5055,11 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start,
/* swap lists */
thislist = &list[flag];
nextlist = &list[flag ^= 1];
- nextlist->n = 0; /* clear nextlist */
- nextlist->has_pim = FALSE;
- ++nfa_listid;
- if (prog->re_engine == AUTOMATIC_ENGINE && nfa_listid >= NFA_MAX_STATES) {
+ nextlist->n = 0; // clear nextlist
+ nextlist->has_pim = false;
+ nfa_listid++;
+ if (prog->re_engine == AUTOMATIC_ENGINE
+ && (nfa_listid >= NFA_MAX_STATES)) {
// Too many states, retry with old engine.
nfa_match = NFA_TOO_EXPENSIVE;
goto theend;
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 46aa771a89..d095bdb7c8 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -669,8 +669,8 @@ static void win_update(win_T *wp)
type = wp->w_redr_type;
- if (type == NOT_VALID) {
- wp->w_redr_status = TRUE;
+ if (type >= NOT_VALID) {
+ wp->w_redr_status = true;
wp->w_lines_valid = 0;
}
@@ -888,10 +888,7 @@ static void win_update(win_T *wp)
// Try to insert the correct number of lines.
// If not the last window, delete the lines at the bottom.
// win_ins_lines may fail when the terminal can't do it.
- if (i > 0) {
- check_for_delay(false);
- }
- if (win_ins_lines(wp, 0, i, false) == OK) {
+ if (win_ins_lines(wp, 0, i) == OK) {
if (wp->w_lines_valid != 0) {
/* Need to update rows that are new, stop at the
* first one that scrolled down. */
@@ -949,8 +946,7 @@ static void win_update(win_T *wp)
/* ... but don't delete new filler lines. */
row -= wp->w_topfill;
if (row > 0) {
- check_for_delay(false);
- if (win_del_lines(wp, 0, row, false) == OK) {
+ if (win_del_lines(wp, 0, row) == OK) {
bot_start = wp->w_height - row;
} else {
mid_start = 0; // redraw all lines
@@ -1305,8 +1301,7 @@ static void win_update(win_T *wp)
if (row - xtra_rows >= wp->w_height - 2) {
mod_bot = MAXLNUM;
} else {
- check_for_delay(false);
- if (win_del_lines(wp, row, -xtra_rows, false) == FAIL) {
+ if (win_del_lines(wp, row, -xtra_rows) == FAIL) {
mod_bot = MAXLNUM;
} else {
bot_start = wp->w_height + xtra_rows;
@@ -1319,8 +1314,7 @@ static void win_update(win_T *wp)
if (row + xtra_rows >= wp->w_height - 2) {
mod_bot = MAXLNUM;
} else {
- check_for_delay(false);
- if (win_ins_lines(wp, row + old_rows, xtra_rows, false) == FAIL) {
+ if (win_ins_lines(wp, row + old_rows, xtra_rows) == FAIL) {
mod_bot = MAXLNUM;
} else if (top_end > row + old_rows) {
// Scrolled the part at the top that requires
@@ -1513,8 +1507,7 @@ static void win_update(win_T *wp)
wp->w_botline = lnum;
}
} else {
- draw_vsep_win(wp, row);
- if (eof) { /* we hit the end of the file */
+ if (eof) { // we hit the end of the file
wp->w_botline = buf->b_ml.ml_line_count + 1;
j = diff_check_fill(wp, wp->w_botline);
if (j > 0 && !wp->w_botfill) {
@@ -1538,6 +1531,10 @@ static void win_update(win_T *wp)
win_draw_end(wp, fill_eob, ' ', row, wp->w_height, HLF_EOB);
}
+ if (wp->w_redr_type >= REDRAW_TOP) {
+ draw_vsep_win(wp, 0);
+ }
+
/* Reset the type of redrawing required, the window has been updated. */
wp->w_redr_type = 0;
wp->w_old_topfill = wp->w_topfill;
@@ -2172,21 +2169,21 @@ win_line (
static linenr_T checked_lnum = 0; /* line number for "checked_col" */
static int checked_col = 0; /* column in "checked_lnum" up to which
* there are no spell errors */
- static int cap_col = -1; /* column to check for Cap word */
- static linenr_T capcol_lnum = 0; /* line number where "cap_col" used */
- int cur_checked_col = 0; /* checked column for current line */
- int extra_check; /* has syntax or linebreak */
- int multi_attr = 0; /* attributes desired by multibyte */
- int mb_l = 1; /* multi-byte byte length */
- int mb_c = 0; /* decoded multi-byte character */
- int mb_utf8 = FALSE; /* screen char is UTF-8 char */
- int u8cc[MAX_MCO]; /* composing UTF-8 chars */
- int filler_lines; /* nr of filler lines to be drawn */
- int filler_todo; /* nr of filler lines still to do + 1 */
- hlf_T diff_hlf = (hlf_T)0; /* type of diff highlighting */
- int change_start = MAXCOL; /* first col of changed area */
- int change_end = -1; /* last col of changed area */
- colnr_T trailcol = MAXCOL; /* start of trailing spaces */
+ static int cap_col = -1; // column to check for Cap word
+ static linenr_T capcol_lnum = 0; // line number where "cap_col"
+ int cur_checked_col = 0; // checked column for current line
+ int extra_check = 0; // has syntax or linebreak
+ int multi_attr = 0; // attributes desired by multibyte
+ int mb_l = 1; // multi-byte byte length
+ int mb_c = 0; // decoded multi-byte character
+ bool mb_utf8 = false; // screen char is UTF-8 char
+ int u8cc[MAX_MCO]; // composing UTF-8 chars
+ int filler_lines; // nr of filler lines to be drawn
+ int filler_todo; // nr of filler lines still to do + 1
+ hlf_T diff_hlf = (hlf_T)0; // type of diff highlighting
+ int change_start = MAXCOL; // first col of changed area
+ int change_end = -1; // last col of changed area
+ colnr_T trailcol = MAXCOL; // start of trailing spaces
int need_showbreak = false; // overlong line, skip first x chars
int line_attr = 0; // attribute for the whole line
int line_attr_lowprio = 0; // low-priority attribute for the line
@@ -2829,7 +2826,7 @@ win_line (
draw_state = WL_BRI - 1;
}
- // draw 'breakindent': indent wrapped text accodringly
+ // draw 'breakindent': indent wrapped text accordingly
if (draw_state == WL_BRI - 1 && n_extra == 0) {
draw_state = WL_BRI;
// if need_showbreak is set, breakindent also applies
@@ -3055,8 +3052,13 @@ win_line (
diff_hlf = HLF_CHD; // changed line
}
line_attr = win_hl_attr(wp, diff_hlf);
+ // Overlay CursorLine onto diff-mode highlight.
if (wp->w_p_cul && lnum == wp->w_cursor.lnum) {
- line_attr = hl_combine_attr(line_attr, win_hl_attr(wp, HLF_CUL));
+ line_attr = 0 != line_attr_lowprio // Low-priority CursorLine
+ ? hl_combine_attr(hl_combine_attr(win_hl_attr(wp, HLF_CUL),
+ line_attr),
+ hl_get_underline())
+ : hl_combine_attr(line_attr, win_hl_attr(wp, HLF_CUL));
}
}
@@ -3103,8 +3105,9 @@ win_line (
mb_utf8 = true;
u8cc[0] = 0;
c = 0xc0;
- } else
- mb_utf8 = FALSE;
+ } else {
+ mb_utf8 = false;
+ }
} else {
c = *p_extra;
if (has_mbyte) {
@@ -3275,7 +3278,7 @@ win_line (
&& (*mb_char2cells)(mb_c) == 2) {
c = '>';
mb_c = c;
- mb_utf8 = FALSE;
+ mb_utf8 = false;
mb_l = 1;
multi_attr = win_hl_attr(wp, HLF_AT);
// Put pointer back so that the character will be
@@ -3298,7 +3301,7 @@ win_line (
saved_attr2 = char_attr; // save current attr
}
mb_c = c;
- mb_utf8 = FALSE;
+ mb_utf8 = false;
mb_l = 1;
}
@@ -3576,7 +3579,7 @@ win_line (
}
}
- mb_utf8 = (int)false; // don't draw as UTF-8
+ mb_utf8 = false; // don't draw as UTF-8
if (wp->w_p_list) {
c = lcs_tab1;
if (wp->w_p_lbr) {
@@ -3639,8 +3642,9 @@ win_line (
mb_utf8 = true;
u8cc[0] = 0;
c = 0xc0;
- } else
- mb_utf8 = FALSE; /* don't draw as UTF-8 */
+ } else {
+ mb_utf8 = false; // don't draw as UTF-8
+ }
} else if (c != NUL) {
p_extra = transchar(c);
if (n_extra == 0) {
@@ -3729,8 +3733,9 @@ win_line (
mb_utf8 = true;
u8cc[0] = 0;
c = 0xc0;
- } else
- mb_utf8 = FALSE; /* don't draw as UTF-8 */
+ } else {
+ mb_utf8 = false; // don't draw as UTF-8
+ }
} else {
prev_syntax_id = 0;
is_concealing = FALSE;
@@ -4056,8 +4061,9 @@ win_line (
mb_utf8 = true;
u8cc[0] = 0;
c = 0xc0;
- } else
- mb_utf8 = FALSE;
+ } else {
+ mb_utf8 = false;
+ }
}
/* advance to the next 'colorcolumn' */
@@ -4262,7 +4268,6 @@ win_line (
&& filler_todo <= 0
) {
win_draw_end(wp, '@', ' ', row, wp->w_height, HLF_AT);
- draw_vsep_win(wp, row);
row = endrow;
}
@@ -4348,7 +4353,6 @@ static void screen_line(int row, int coloff, int endcol, int clear_width,
unsigned max_off_from;
unsigned max_off_to;
int col = 0;
- int hl;
bool redraw_this; // Does character need redraw?
bool redraw_next; // redraw_this for next character
bool clear_next = false;
@@ -4474,24 +4478,10 @@ static void screen_line(int row, int coloff, int endcol, int clear_width,
}
}
- if (clear_width > 0) {
- // For a window that's left of another, draw the separator char.
- if (col + coloff < Columns && wp->w_vsep_width > 0) {
- int c = fillchar_vsep(wp, &hl);
- schar_T sc;
- schar_from_char(sc, c);
-
- if (schar_cmp(ScreenLines[off_to], sc)
- || ScreenAttrs[off_to] != hl) {
- schar_copy(ScreenLines[off_to], sc);
- ScreenAttrs[off_to] = hl;
- if (start_dirty == -1) {
- start_dirty = col;
- }
- end_dirty = col+1;
- }
- } else
- LineWraps[row] = FALSE;
+ if (clear_width > 0 || wp->w_width != Columns) {
+ // If we cleared after the end of the line, it did not wrap.
+ // For vsplit, line wrapping is not possible.
+ LineWraps[row] = false;
}
if (clear_end < end_dirty) {
@@ -5613,6 +5603,7 @@ next_search_hl (
linenr_T l;
colnr_T matchcol;
long nmatched = 0;
+ int save_called_emsg = called_emsg;
if (shl->lnum != 0) {
/* Check for three situations:
@@ -5705,6 +5696,9 @@ next_search_hl (
shl->lnum += shl->rm.startpos[0].lnum;
break; /* useful match found */
}
+
+ // Restore called_emsg for assert_fails().
+ called_emsg = save_called_emsg;
}
}
@@ -6071,10 +6065,10 @@ static void screenclear2(void)
return;
}
- /* blank out ScreenLines */
- for (i = 0; i < Rows; ++i) {
- lineclear(LineOffset[i], (int)Columns);
- LineWraps[i] = FALSE;
+ // blank out ScreenLines
+ for (i = 0; i < Rows; i++) {
+ lineclear(LineOffset[i], (int)Columns, true);
+ LineWraps[i] = false;
}
ui_call_grid_clear(1); // clear the display
@@ -6098,12 +6092,13 @@ static void screenclear2(void)
/*
* Clear one line in ScreenLines.
*/
-static void lineclear(unsigned off, int width)
+static void lineclear(unsigned off, int width, bool valid)
{
for (int col = 0; col < width; col++) {
schar_from_ascii(ScreenLines[off + col], ' ');
}
- (void)memset(ScreenAttrs + off, 0, (size_t)width * sizeof(sattr_T));
+ int fill = valid ? 0 : -1;
+ (void)memset(ScreenAttrs + off, fill, (size_t)width * sizeof(sattr_T));
}
/// Copy part of a Screenline for vertically split window.
@@ -6139,53 +6134,36 @@ void setcursor(void)
}
/// Insert 'line_count' lines at 'row' in window 'wp'.
-/// If 'invalid' is TRUE the wp->w_lines[].wl_lnum is invalidated.
-/// If 'mayclear' is TRUE the screen will be cleared if it is faster than
-/// scrolling.
/// Returns FAIL if the lines are not inserted, OK for success.
-int win_ins_lines(win_T *wp, int row, int line_count, int invalid)
+int win_ins_lines(win_T *wp, int row, int line_count)
{
- if (wp->w_height < 5) {
- return FAIL;
- }
-
- return win_do_lines(wp, row, line_count, invalid, false);
+ return win_do_lines(wp, row, line_count, false);
}
/// Delete "line_count" window lines at "row" in window "wp".
-/// If "invalid" is TRUE curwin->w_lines[] is invalidated.
-/// If "mayclear" is TRUE the screen will be cleared if it is faster than
-/// scrolling
/// Return OK for success, FAIL if the lines are not deleted.
-int win_del_lines(win_T *wp, int row, int line_count, int invalid)
+int win_del_lines(win_T *wp, int row, int line_count)
{
- return win_do_lines(wp, row, line_count, invalid, true);
+ return win_do_lines(wp, row, line_count, true);
}
// Common code for win_ins_lines() and win_del_lines().
// Returns OK or FAIL when the work has been done.
-static int win_do_lines(win_T *wp, int row, int line_count,
- int invalid, int del)
+static int win_do_lines(win_T *wp, int row, int line_count, int del)
{
- if (invalid) {
- wp->w_lines_valid = 0;
- }
-
if (!redrawing() || line_count <= 0) {
return FAIL;
}
- // Delete all remaining lines
+ // No lines are being moved, just draw over the entire area
if (row + line_count >= wp->w_height) {
- screen_fill(wp->w_winrow + row, wp->w_winrow + wp->w_height,
- wp->w_wincol, W_ENDCOL(wp),
- ' ', ' ', 0);
return OK;
}
// when scrolling, the message on the command line should be cleared,
// otherwise it will stay there forever.
- clear_cmdline = TRUE;
+ check_for_delay(false);
+ clear_cmdline = true;
int retval;
if (del) {
@@ -6237,7 +6215,7 @@ int screen_ins_lines(int row, int line_count, int end, int col, int width)
linecopy(j + line_count, j, col, width);
}
j += line_count;
- lineclear(LineOffset[j] + col, width);
+ lineclear(LineOffset[j] + col, width, false);
LineWraps[j] = false;
} else {
j = end - 1 - i;
@@ -6248,7 +6226,7 @@ int screen_ins_lines(int row, int line_count, int end, int col, int width)
}
LineOffset[j + line_count] = temp;
LineWraps[j + line_count] = false;
- lineclear(temp, (int)Columns);
+ lineclear(temp, (int)Columns, false);
}
}
@@ -6283,7 +6261,7 @@ int screen_del_lines(int row, int line_count, int end, int col, int width)
linecopy(j - line_count, j, col, width);
}
j -= line_count;
- lineclear(LineOffset[j] + col, width);
+ lineclear(LineOffset[j] + col, width, false);
LineWraps[j] = false;
} else {
// whole width, moving the line pointers is faster
@@ -6295,7 +6273,7 @@ int screen_del_lines(int row, int line_count, int end, int col, int width)
}
LineOffset[j - line_count] = temp;
LineWraps[j - line_count] = false;
- lineclear(temp, (int)Columns);
+ lineclear(temp, (int)Columns, false);
}
}
diff --git a/src/nvim/strings.c b/src/nvim/strings.c
index 3b0a950ff2..4921824316 100644
--- a/src/nvim/strings.c
+++ b/src/nvim/strings.c
@@ -999,10 +999,13 @@ int vim_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap,
} else if (fmt_spec == 'd') {
// signed
switch (length_modifier) {
- case '\0':
+ case '\0': {
+ arg = (int)(tvs ? tv_nr(tvs, &arg_idx) : va_arg(ap, int));
+ break;
+ }
case 'h': {
- // char and short arguments are passed as int
- arg = (tvs ? (int)tv_nr(tvs, &arg_idx) : va_arg(ap, int));
+ // char and short arguments are passed as int16_t
+ arg = (int16_t)(tvs ? tv_nr(tvs, &arg_idx) : va_arg(ap, int));
break;
}
case 'l': {
@@ -1031,11 +1034,16 @@ int vim_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap,
} else {
// unsigned
switch (length_modifier) {
- case '\0':
+ case '\0': {
+ uarg = (unsigned int)(tvs
+ ? tv_nr(tvs, &arg_idx)
+ : va_arg(ap, unsigned int));
+ break;
+ }
case 'h': {
- uarg = (tvs
- ? (unsigned)tv_nr(tvs, &arg_idx)
- : va_arg(ap, unsigned));
+ uarg = (uint16_t)(tvs
+ ? tv_nr(tvs, &arg_idx)
+ : va_arg(ap, unsigned int));
break;
}
case 'l': {
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index 22eabc75c1..973d09d065 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -61,6 +61,7 @@ struct hl_group {
scid_T sg_scriptID; ///< script in which the group was last set
// for terminal UIs
int sg_cterm; ///< "cterm=" highlighting attr
+ ///< (combination of \ref HlAttrFlags)
int sg_cterm_fg; ///< terminal fg color number + 1
int sg_cterm_bg; ///< terminal bg color number + 1
bool sg_cterm_bold; ///< bold attr was set for light color
@@ -2893,6 +2894,13 @@ static int syn_regexec(regmmatch_T *rmp, linenr_T lnum, colnr_T col, syn_time_T
pt = profile_start();
}
+ if (rmp->regprog == NULL) {
+ // This can happen if a previous call to vim_regexec_multi() tried to
+ // use the NFA engine, which resulted in NFA_TOO_EXPENSIVE, and
+ // compiling the pattern with the other engine fails.
+ return false;
+ }
+
rmp->rmm_maxcol = syn_buf->b_p_smc;
r = vim_regexec_multi(rmp, syn_win, syn_buf, lnum, col, NULL);
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index d831979022..f715344689 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -603,13 +603,14 @@ void terminal_get_line_attributes(Terminal *term, win_T *wp, int linenr,
int attr_id = 0;
if (hl_attrs || vt_fg != -1 || vt_bg != -1) {
- attr_id = get_term_attr_entry(&(HlAttrs) {
+ attr_id = hl_get_term_attr(&(HlAttrs) {
.cterm_ae_attr = (int16_t)hl_attrs,
.cterm_fg_color = vt_fg_idx,
.cterm_bg_color = vt_bg_idx,
.rgb_ae_attr = (int16_t)hl_attrs,
.rgb_fg_color = vt_fg,
.rgb_bg_color = vt_bg,
+ .rgb_sp_color = -1,
});
}
diff --git a/src/nvim/testdir/runtest.vim b/src/nvim/testdir/runtest.vim
index 99b2b940d7..4fe7db135b 100644
--- a/src/nvim/testdir/runtest.vim
+++ b/src/nvim/testdir/runtest.vim
@@ -245,6 +245,7 @@ let s:flaky = [
\ 'Test_oneshot()',
\ 'Test_out_cb()',
\ 'Test_paused()',
+ \ 'Test_popup_and_window_resize()',
\ 'Test_quoteplus()',
\ 'Test_quotestar()',
\ 'Test_reltime()',
diff --git a/src/nvim/testdir/shared.vim b/src/nvim/testdir/shared.vim
index b1f1d8fe66..eb6798f353 100644
--- a/src/nvim/testdir/shared.vim
+++ b/src/nvim/testdir/shared.vim
@@ -136,29 +136,27 @@ endfunc
" Wait for up to a second for "expr" to become true.
" Return time slept in milliseconds. With the +reltime feature this can be
" more than the actual waiting time. Without +reltime it can also be less.
-func WaitFor(expr)
+func WaitFor(expr, ...)
+ let timeout = get(a:000, 0, 1000)
" using reltime() is more accurate, but not always available
if has('reltime')
let start = reltime()
else
let slept = 0
endif
- for i in range(100)
- try
- if eval(a:expr)
- if has('reltime')
- return float2nr(reltimefloat(reltime(start)) * 1000)
- endif
- return slept
+ for i in range(timeout / 10)
+ if eval(a:expr)
+ if has('reltime')
+ return float2nr(reltimefloat(reltime(start)) * 1000)
endif
- catch
- endtry
+ return slept
+ endif
if !has('reltime')
let slept += 10
endif
sleep 10m
endfor
- return 1000
+ return timeout
endfunc
" Wait for up to a given milliseconds.
diff --git a/src/nvim/testdir/test_alot.vim b/src/nvim/testdir/test_alot.vim
index 36dcdc3386..0602ff6a45 100644
--- a/src/nvim/testdir/test_alot.vim
+++ b/src/nvim/testdir/test_alot.vim
@@ -28,6 +28,7 @@ source test_lambda.vim
source test_mapping.vim
source test_menu.vim
source test_messages.vim
+source test_move.vim
source test_partial.vim
source test_popup.vim
source test_put.vim
diff --git a/src/nvim/testdir/test_arglist.vim b/src/nvim/testdir/test_arglist.vim
index 19d0cee47a..20171bb599 100644
--- a/src/nvim/testdir/test_arglist.vim
+++ b/src/nvim/testdir/test_arglist.vim
@@ -297,6 +297,18 @@ func Test_argdelete()
%argd
endfunc
+func Test_argdelete_completion()
+ args foo bar
+
+ call feedkeys(":argdelete \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"argdelete bar foo', @:)
+
+ call feedkeys(":argdelete x \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"argdelete x bar foo', @:)
+
+ %argd
+endfunc
+
" Tests for the :next, :prev, :first, :last, :rewind commands
func Test_argpos()
call Reset_arglist()
diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim
index 9e8d2081c8..253d6750ed 100644
--- a/src/nvim/testdir/test_autocmd.vim
+++ b/src/nvim/testdir/test_autocmd.vim
@@ -818,6 +818,18 @@ func Test_QuitPre()
endfunc
func Test_Cmdline()
+ au! CmdlineChanged : let g:text = getcmdline()
+ let g:text = 0
+ call feedkeys(":echom 'hello'\<CR>", 'xt')
+ call assert_equal("echom 'hello'", g:text)
+ au! CmdlineChanged
+
+ au! CmdlineChanged : let g:entered = expand('<afile>')
+ let g:entered = 0
+ call feedkeys(":echom 'hello'\<CR>", 'xt')
+ call assert_equal(':', g:entered)
+ au! CmdlineChanged
+
au! CmdlineEnter : let g:entered = expand('<afile>')
au! CmdlineLeave : let g:left = expand('<afile>')
let g:entered = 0
@@ -828,6 +840,8 @@ func Test_Cmdline()
au! CmdlineEnter
au! CmdlineLeave
+ let save_shellslash = &shellslash
+ set noshellslash
au! CmdlineEnter / let g:entered = expand('<afile>')
au! CmdlineLeave / let g:left = expand('<afile>')
let g:entered = 0
@@ -840,6 +854,7 @@ func Test_Cmdline()
bwipe!
au! CmdlineEnter
au! CmdlineLeave
+ let &shellslash = save_shellslash
endfunc
" Test for BufWritePre autocommand that deletes or unloads the buffer.
diff --git a/src/nvim/testdir/test_compiler.vim b/src/nvim/testdir/test_compiler.vim
index 84fba0f9a4..4600a28da5 100644
--- a/src/nvim/testdir/test_compiler.vim
+++ b/src/nvim/testdir/test_compiler.vim
@@ -5,6 +5,11 @@ func Test_compiler()
return
endif
+ " $LANG changes the output of Perl.
+ if $LANG != ''
+ unlet $LANG
+ endif
+
e Xfoo.pl
compiler perl
call assert_equal('perl', b:current_compiler)
diff --git a/src/nvim/testdir/test_diffmode.vim b/src/nvim/testdir/test_diffmode.vim
index afe289b262..ad3eec3274 100644
--- a/src/nvim/testdir/test_diffmode.vim
+++ b/src/nvim/testdir/test_diffmode.vim
@@ -2,6 +2,9 @@
func Test_diff_fold_sync()
enew!
+ let g:update_count = 0
+ au DiffUpdated * let g:update_count += 1
+
let l = range(50)
call setline(1, l)
diffthis
@@ -27,12 +30,27 @@ func Test_diff_fold_sync()
call win_gotoid(winone)
call assert_equal(23, getcurpos()[1])
+ call assert_equal(1, g:update_count)
+ au! DiffUpdated
+
windo diffoff
close!
set nomodified
endfunc
func Test_vert_split()
+ set diffopt=filler
+ call Common_vert_split()
+ set diffopt&
+endfunc
+
+func Test_vert_split_internal()
+ set diffopt=internal,filler
+ call Common_vert_split()
+ set diffopt&
+endfunc
+
+func Common_vert_split()
" Disable the title to avoid xterm keeping the wrong one.
set notitle noicon
new
@@ -201,6 +219,26 @@ func Test_diffget_diffput()
%bwipe!
endfunc
+" Test putting two changes from one buffer to another
+func Test_diffput_two()
+ new a
+ let win_a = win_getid()
+ call setline(1, range(1, 10))
+ diffthis
+ new b
+ let win_b = win_getid()
+ call setline(1, range(1, 10))
+ 8del
+ 5del
+ diffthis
+ call win_gotoid(win_a)
+ %diffput
+ call win_gotoid(win_b)
+ call assert_equal(map(range(1, 10), 'string(v:val)'), getline(1, '$'))
+ bwipe! a
+ bwipe! b
+endfunc
+
func Test_dp_do_buffer()
e! one
let bn1=bufnr('%')
@@ -257,6 +295,28 @@ func Test_dp_do_buffer()
%bwipe!
endfunc
+func Test_do_lastline()
+ e! one
+ call setline(1, ['1','2','3','4','5','6'])
+ diffthis
+
+ new two
+ call setline(1, ['2','4','5'])
+ diffthis
+
+ 1
+ norm dp]c
+ norm dp]c
+ wincmd w
+ call assert_equal(4, line('$'))
+ norm G
+ norm do
+ call assert_equal(3, line('$'))
+
+ windo diffoff
+ %bwipe!
+endfunc
+
func Test_diffoff()
enew!
call setline(1, ['Two', 'Three'])
@@ -275,10 +335,8 @@ func Test_diffoff()
bwipe!
endfunc
-func Test_diffopt_icase()
- set diffopt=icase,foldcolumn:0
-
- e one
+func Common_icase_test()
+ edit one
call setline(1, ['One', 'Two', 'Three', 'Four', 'Fi#ve'])
redraw
let normattr = screenattr(1, 1)
@@ -300,32 +358,54 @@ func Test_diffopt_icase()
diffoff!
%bwipe!
+endfunc
+
+func Test_diffopt_icase()
+ set diffopt=icase,foldcolumn:0
+ call Common_icase_test()
set diffopt&
endfunc
-func Test_diffopt_iwhite()
- set diffopt=iwhite,foldcolumn:0
+func Test_diffopt_icase_internal()
+ set diffopt=icase,foldcolumn:0,internal
+ call Common_icase_test()
+ set diffopt&
+endfunc
- e one
- " Difference in trailing spaces should be ignored,
+func Common_iwhite_test()
+ edit one
+ " Difference in trailing spaces and amount of spaces should be ignored,
" but not other space differences.
- call setline(1, ["One \t", 'Two', 'Three', 'Four'])
+ call setline(1, ["One \t", 'Two', 'Three', 'one two', 'one two', 'Four'])
redraw
let normattr = screenattr(1, 1)
diffthis
botright vert new two
- call setline(1, ["One\t ", "Two\t ", 'Three', ' Four'])
+ call setline(1, ["One\t ", "Two\t ", 'Three', 'one two', 'onetwo', ' Four'])
diffthis
redraw
call assert_equal(normattr, screenattr(1, 1))
call assert_equal(normattr, screenattr(2, 1))
call assert_equal(normattr, screenattr(3, 1))
- call assert_notequal(normattr, screenattr(4, 1))
+ call assert_equal(normattr, screenattr(4, 1))
+ call assert_notequal(normattr, screenattr(5, 1))
+ call assert_notequal(normattr, screenattr(6, 1))
diffoff!
%bwipe!
+endfunc
+
+func Test_diffopt_iwhite()
+ set diffopt=iwhite,foldcolumn:0
+ call Common_iwhite_test()
+ set diffopt&
+endfunc
+
+func Test_diffopt_iwhite_internal()
+ set diffopt=internal,iwhite,foldcolumn:0
+ call Common_iwhite_test()
set diffopt&
endfunc
@@ -339,8 +419,13 @@ func Test_diffopt_context()
set diffopt=context:2
call assert_equal('+-- 2 lines: 1', foldtextresult(1))
+ set diffopt=internal,context:2
+ call assert_equal('+-- 2 lines: 1', foldtextresult(1))
+
set diffopt=context:1
call assert_equal('+-- 3 lines: 1', foldtextresult(1))
+ set diffopt=internal,context:1
+ call assert_equal('+-- 3 lines: 1', foldtextresult(1))
diffoff!
%bwipe!
@@ -348,7 +433,7 @@ func Test_diffopt_context()
endfunc
func Test_diffopt_horizontal()
- set diffopt=horizontal
+ set diffopt=internal,horizontal
diffsplit
call assert_equal(&columns, winwidth(1))
@@ -362,7 +447,7 @@ func Test_diffopt_horizontal()
endfunc
func Test_diffopt_vertical()
- set diffopt=vertical
+ set diffopt=internal,vertical
diffsplit
call assert_equal(&lines - 2, winheight(1))
@@ -376,7 +461,7 @@ func Test_diffopt_vertical()
endfunc
func Test_diffopt_hiddenoff()
- set diffopt=filler,foldcolumn:0,hiddenoff
+ set diffopt=internal,filler,foldcolumn:0,hiddenoff
e! one
call setline(1, ['Two', 'Three'])
redraw
@@ -399,7 +484,7 @@ func Test_diffopt_hiddenoff()
endfunc
func Test_diffoff_hidden()
- set diffopt=filler,foldcolumn:0
+ set diffopt=internal,filler,foldcolumn:0
e! one
call setline(1, ['Two', 'Three'])
redraw
@@ -480,7 +565,9 @@ func Test_diffexpr()
endif
func DiffExpr()
- silent exe '!diff ' . v:fname_in . ' ' . v:fname_new . '>' . v:fname_out
+ " Prepend some text to check diff type detection
+ call writefile(['warning', ' message'], v:fname_out)
+ silent exe '!diff ' . v:fname_in . ' ' . v:fname_new . '>>' . v:fname_out
endfunc
set diffexpr=DiffExpr()
set diffopt=foldcolumn:0
@@ -523,7 +610,7 @@ func Test_diffpatch()
3
+ 4
.
- saveas Xpatch
+ saveas! Xpatch
bwipe!
new
call assert_fails('diffpatch Xpatch', 'E816:')
@@ -569,6 +656,22 @@ func Test_diff_nomodifiable()
%bwipe!
endfunc
+func Test_diff_filler()
+ new
+ call setline(1, [1, 2, 3, 'x', 4])
+ diffthis
+ vnew
+ call setline(1, [1, 2, 'y', 'y', 3, 4])
+ diffthis
+ redraw
+
+ call assert_equal([0, 0, 0, 0, 0, 0, 0, 1, 0], map(range(-1, 7), 'diff_filler(v:val)'))
+ wincmd w
+ call assert_equal([0, 0, 0, 0, 2, 0, 0, 0], map(range(-1, 6), 'diff_filler(v:val)'))
+
+ %bwipe!
+endfunc
+
func Test_diff_lastline()
enew!
only!
@@ -615,3 +718,23 @@ func Test_diff_with_cursorline()
call StopVimInTerminal(buf)
call delete('Xtest_diff_cursorline')
endfunc
+
+func Test_diff_of_diff()
+ if !CanRunVimInTerminal()
+ return
+ endif
+
+ call writefile([
+ \ 'call setline(1, ["aa","bb","cc","@@ -3,2 +5,7 @@","dd","ee","ff"])',
+ \ 'vnew',
+ \ 'call setline(1, ["aa","bb","cc"])',
+ \ 'windo diffthis',
+ \ ], 'Xtest_diff_diff')
+ let buf = RunVimInTerminal('-S Xtest_diff_diff', {})
+
+ call VerifyScreenDump(buf, 'Test_diff_of_diff_01', {})
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('Xtest_diff_diff')
+endfunc
diff --git a/src/nvim/testdir/test_eval_stuff.vim b/src/nvim/testdir/test_eval_stuff.vim
index 92e1ec5335..111c85bb95 100644
--- a/src/nvim/testdir/test_eval_stuff.vim
+++ b/src/nvim/testdir/test_eval_stuff.vim
@@ -11,3 +11,13 @@ endfunction
func Test_catch_return_with_error()
call assert_equal(1, s:foo())
endfunc
+
+func Test_E963()
+ " These commands used to cause an internal error prior to vim 8.1.0563
+ let v_e = v:errors
+ let v_o = v:oldfiles
+ call assert_fails("let v:errors=''", 'E963:')
+ call assert_equal(v_e, v:errors)
+ call assert_fails("let v:oldfiles=''", 'E963:')
+ call assert_equal(v_o, v:oldfiles)
+endfunc
diff --git a/src/nvim/testdir/test_expr.vim b/src/nvim/testdir/test_expr.vim
index aaf32dff04..4f99625e73 100644
--- a/src/nvim/testdir/test_expr.vim
+++ b/src/nvim/testdir/test_expr.vim
@@ -177,6 +177,22 @@ function Test_printf_misc()
call assert_equal('173', printf('%O', 123))
call assert_equal('7b', printf('%x', 123))
call assert_equal('7B', printf('%X', 123))
+
+ call assert_equal('123', printf('%hd', 123))
+ call assert_equal('-123', printf('%hd', -123))
+ call assert_equal('-1', printf('%hd', 0xFFFF))
+ call assert_equal('-1', printf('%hd', 0x1FFFFF))
+
+ call assert_equal('123', printf('%hu', 123))
+ call assert_equal('65413', printf('%hu', -123))
+ call assert_equal('65535', printf('%hu', 0xFFFF))
+ call assert_equal('65535', printf('%hu', 0x1FFFFF))
+
+ call assert_equal('123', printf('%ld', 123))
+ call assert_equal('-123', printf('%ld', -123))
+ call assert_equal('65535', printf('%ld', 0xFFFF))
+ call assert_equal('131071', printf('%ld', 0x1FFFF))
+
call assert_equal('{', printf('%c', 123))
call assert_equal('abc', printf('%s', 'abc'))
call assert_equal('abc', printf('%S', 'abc'))
@@ -216,6 +232,11 @@ function Test_printf_misc()
call assert_equal(' 123', printf('% *d', 5, 123))
call assert_equal(' +123', printf('%+ *d', 5, 123))
+ call assert_equal('foobar', printf('%.*s', 9, 'foobar'))
+ call assert_equal('foo', printf('%.*s', 3, 'foobar'))
+ call assert_equal('', printf('%.*s', 0, 'foobar'))
+ call assert_equal('foobar', printf('%.*s', -1, 'foobar'))
+
" Simple quote (thousand grouping char) is ignored.
call assert_equal('+00123456', printf("%+'09d", 123456))
@@ -238,6 +259,11 @@ function Test_printf_misc()
call assert_equal(' 00123', printf('%6.5d', 123))
call assert_equal(' 0007b', printf('%6.5x', 123))
+ call assert_equal('123', printf('%.2d', 123))
+ call assert_equal('0123', printf('%.4d', 123))
+ call assert_equal('0000000123', printf('%.10d', 123))
+ call assert_equal('123', printf('%.0d', 123))
+
call assert_equal('abc', printf('%2s', 'abc'))
call assert_equal('abc', printf('%2S', 'abc'))
call assert_equal('abc', printf('%.4s', 'abc'))
@@ -335,6 +361,11 @@ function Test_printf_float()
call assert_equal("str2float('inf')", printf('%s', 1.0/0.0))
call assert_equal("-str2float('inf')", printf('%s', -1.0/0.0))
+ " Test special case where max precision is truncated at 340.
+ call assert_equal('1.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', printf('%.330f', 1.0))
+ call assert_equal('1.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', printf('%.340f', 1.0))
+ call assert_equal('1.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', printf('%.350f', 1.0))
+
" Float nan (not a number) has no sign.
call assert_equal('nan', printf('%f', sqrt(-1.0)))
call assert_equal('nan', printf('%f', 0.0/0.0))
diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim
index b0a1ea0225..5d4a0ff3cb 100644
--- a/src/nvim/testdir/test_filetype.vim
+++ b/src/nvim/testdir/test_filetype.vim
@@ -596,3 +596,7 @@ func Test_script_detection()
filetype off
endfunc
+func Test_setfiletype_completion()
+ call feedkeys(":setfiletype java\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"setfiletype java javacc javascript', @:)
+endfunc
diff --git a/src/nvim/testdir/test_fold.vim b/src/nvim/testdir/test_fold.vim
index b6a545f959..0b4b5d1922 100644
--- a/src/nvim/testdir/test_fold.vim
+++ b/src/nvim/testdir/test_fold.vim
@@ -514,6 +514,35 @@ func Test_fold_marker()
enew!
endfunc
+" test create fold markers with C filetype
+func Test_fold_create_marker_in_C()
+ enew!
+ set fdm=marker fdl=9
+ set filetype=c
+
+ let content = [
+ \ '/*',
+ \ ' * comment',
+ \ ' * ',
+ \ ' *',
+ \ ' */',
+ \ 'int f(int* p) {',
+ \ ' *p = 3;',
+ \ ' return 0;',
+ \ '}'
+ \]
+ for c in range(len(content) - 1)
+ bw!
+ call append(0, content)
+ call cursor(c + 1, 1)
+ norm! zfG
+ call assert_equal(content[c] . (c < 4 ? '{{{' : '/*{{{*/'), getline(c + 1))
+ endfor
+
+ set fdm& fdl&
+ enew!
+endfunc
+
" test folding with indent
func Test_fold_indent()
enew!
@@ -674,3 +703,20 @@ func Test_fold_last_line_with_pagedown()
set fdm&
enew!
endfunc
+
+func Test_folds_marker_in_comment2()
+ new
+ call setline(1, ['Lorem ipsum dolor sit', 'Lorem ipsum dolor sit', 'Lorem ipsum dolor sit'])
+ setl fen fdm=marker
+ setl commentstring=<!--%s-->
+ setl comments=s:<!--,m:\ \ \ \ ,e:-->
+ norm! zf2j
+ setl nofen
+ :1y
+ call assert_equal(['Lorem ipsum dolor sit<!--{{{-->'], getreg(0,1,1))
+ :+2y
+ call assert_equal(['Lorem ipsum dolor sit<!--}}}-->'], getreg(0,1,1))
+
+ set foldmethod&
+ bwipe!
+endfunc
diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim
index b1138bfc96..7dc9f31ce7 100644
--- a/src/nvim/testdir/test_functions.vim
+++ b/src/nvim/testdir/test_functions.vim
@@ -1018,3 +1018,22 @@ func Test_trim()
let chars = join(map(range(1, 0x20) + [0xa0], {n -> nr2char(n)}), '')
call assert_equal("x", trim(chars . "x" . chars))
endfunc
+
+func EditAnotherFile()
+ let word = expand('<cword>')
+ edit Xfuncrange2
+endfunc
+
+func Test_func_range_with_edit()
+ " Define a function that edits another buffer, then call it with a range that
+ " is invalid in that buffer.
+ call writefile(['just one line'], 'Xfuncrange2')
+ new
+ call setline(1, range(10))
+ write Xfuncrange1
+ call assert_fails('5,8call EditAnotherFile()', 'E16:')
+
+ call delete('Xfuncrange1')
+ call delete('Xfuncrange2')
+ bwipe!
+endfunc
diff --git a/src/nvim/testdir/test_history.vim b/src/nvim/testdir/test_history.vim
index ca31e3f06c..16aad9889e 100644
--- a/src/nvim/testdir/test_history.vim
+++ b/src/nvim/testdir/test_history.vim
@@ -104,3 +104,8 @@ function Test_Search_history_window()
call assert_equal('a', @/)
bwipe!
endfunc
+
+function Test_history_completion()
+ call feedkeys(":history \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"history / : = > ? @ all cmd debug expr input search', @:)
+endfunc
diff --git a/src/nvim/testdir/test_ins_complete.vim b/src/nvim/testdir/test_ins_complete.vim
index 5ff63e58ba..d3429617d0 100644
--- a/src/nvim/testdir/test_ins_complete.vim
+++ b/src/nvim/testdir/test_ins_complete.vim
@@ -142,6 +142,19 @@ function Test_CompleteDoneDict()
au! CompleteDone
endfunc
+func Test_CompleteDone_undo()
+ au CompleteDone * call append(0, "prepend1")
+ new
+ call setline(1, ["line1", "line2"])
+ call feedkeys("Go\<C-X>\<C-N>\<CR>\<ESC>", "tx")
+ call assert_equal(["prepend1", "line1", "line2", "line1", ""],
+ \ getline(1, '$'))
+ undo
+ call assert_equal(["line1", "line2"], getline(1, '$'))
+ bwipe!
+ au! CompleteDone
+endfunc
+
function! s:CompleteDone_CompleteFuncDictNoUserData( findstart, base )
if a:findstart
return 0
diff --git a/src/nvim/testdir/test_lambda.vim b/src/nvim/testdir/test_lambda.vim
index 311cc6e2cb..6e07c874b4 100644
--- a/src/nvim/testdir/test_lambda.vim
+++ b/src/nvim/testdir/test_lambda.vim
@@ -31,11 +31,11 @@ function! Test_lambda_with_timer()
endfunction
call s:Foo()
- sleep 200ms
+ sleep 210ms
" do not collect lambda
- call garbagecollect()
+ call test_garbagecollect_now()
let m = s:n
- sleep 200ms
+ sleep 230ms
call timer_stop(s:timer_id)
call assert_true(m > 1)
call assert_true(s:n > m + 1)
diff --git a/src/nvim/testdir/test_messages.vim b/src/nvim/testdir/test_messages.vim
index 188406e440..12101ec1f8 100644
--- a/src/nvim/testdir/test_messages.vim
+++ b/src/nvim/testdir/test_messages.vim
@@ -38,3 +38,8 @@ function Test_messages()
let &more = oldmore
endtry
endfunction
+
+func Test_message_completion()
+ call feedkeys(":message \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"message clear', @:)
+endfunc
diff --git a/src/nvim/testdir/test_move.vim b/src/nvim/testdir/test_move.vim
new file mode 100644
index 0000000000..d774c93dbd
--- /dev/null
+++ b/src/nvim/testdir/test_move.vim
@@ -0,0 +1,40 @@
+" Test the ":move" command.
+
+func Test_move()
+ enew!
+ call append(0, ['line 1', 'line 2', 'line 3'])
+ g /^$/ delete _
+ set nomodified
+
+ move .
+ call assert_equal(['line 1', 'line 2', 'line 3'], getline(1, 3))
+ call assert_false(&modified)
+
+ 1,2move 0
+ call assert_equal(['line 1', 'line 2', 'line 3'], getline(1, 3))
+ call assert_false(&modified)
+
+ 1,3move 3
+ call assert_equal(['line 1', 'line 2', 'line 3'], getline(1, 3))
+ call assert_false(&modified)
+
+ 1move 2
+ call assert_equal(['line 2', 'line 1', 'line 3'], getline(1, 3))
+ call assert_true(&modified)
+ set nomodified
+
+ 3move 0
+ call assert_equal(['line 3', 'line 2', 'line 1'], getline(1, 3))
+ call assert_true(&modified)
+ set nomodified
+
+ 2,3move 0
+ call assert_equal(['line 2', 'line 1', 'line 3'], getline(1, 3))
+ call assert_true(&modified)
+ set nomodified
+
+ call assert_fails('1,2move 1', 'E134')
+ call assert_fails('2,3move 2', 'E134')
+
+ %bwipeout!
+endfunc
diff --git a/src/nvim/testdir/test_popup.vim b/src/nvim/testdir/test_popup.vim
index 6fd58a1483..6c43cbc1dc 100644
--- a/src/nvim/testdir/test_popup.vim
+++ b/src/nvim/testdir/test_popup.vim
@@ -246,6 +246,10 @@ func! Test_popup_completion_insertmode()
iunmap <F5>
endfunc
+" TODO: Fix what breaks after this line.
+" - Do not use "q!", it may exit Vim if there is an error
+finish
+
func Test_noinsert_complete()
function! s:complTest1() abort
call complete(1, ['source', 'soundfold'])
@@ -571,6 +575,15 @@ func Test_completion_clear_candidate_list()
bw!
endfunc
+func Test_popup_complete_backwards()
+ new
+ call setline(1, ['Post', 'Port', 'Po'])
+ let expected=['Post', 'Port', 'Port']
+ call cursor(3,2)
+ call feedkeys("A\<C-X>". repeat("\<C-P>", 3). "rt\<cr>", 'tx')
+ call assert_equal(expected, getline(1,'$'))
+ bwipe!
+endfunc
func Test_popup_and_preview_autocommand()
" This used to crash Vim
@@ -678,18 +691,24 @@ func Test_popup_and_window_resize()
let g:buf = term_start([$NVIM_PRG, '--clean', '-c', 'set noswapfile'], {'term_rows': h / 3})
call term_sendkeys(g:buf, (h / 3 - 1)."o\<esc>G")
call term_sendkeys(g:buf, "i\<c-x>")
- call term_wait(g:buf, 100)
+ call term_wait(g:buf, 200)
call term_sendkeys(g:buf, "\<c-v>")
call term_wait(g:buf, 100)
+ " popup first entry "!" must be at the top
+ call WaitFor('term_getline(g:buf, 1) =~ "^!"')
call assert_match('^!\s*$', term_getline(g:buf, 1))
exe 'resize +' . (h - 1)
call term_wait(g:buf, 100)
redraw!
- call WaitFor('"" == term_getline(g:buf, 1)')
+ " popup shifted down, first line is now empty
+ call WaitFor('term_getline(g:buf, 1) == ""')
call assert_equal('', term_getline(g:buf, 1))
sleep 100m
- call WaitFor('"^!" =~ term_getline(g:buf, term_getcursor(g:buf)[0] + 1)')
+ " popup is below cursor line and shows first match "!"
+ call WaitFor('term_getline(g:buf, term_getcursor(g:buf)[0] + 1) =~ "^!"')
call assert_match('^!\s*$', term_getline(g:buf, term_getcursor(g:buf)[0] + 1))
+ " cursor line also shows !
+ call assert_match('^!\s*$', term_getline(g:buf, term_getcursor(g:buf)[0]))
bwipe!
endfunc
diff --git a/src/nvim/testdir/test_python2.vim b/src/nvim/testdir/test_python2.vim
index 63c38cd5d1..5ba9fd68cf 100644
--- a/src/nvim/testdir/test_python2.vim
+++ b/src/nvim/testdir/test_python2.vim
@@ -25,3 +25,30 @@ func Test_pydo()
bwipe!
endif
endfunc
+
+func Test_vim_function()
+ " Check creating vim.Function object
+ py import vim
+
+ func s:foo()
+ return matchstr(expand('<sfile>'), '<SNR>\zs\d\+_foo$')
+ endfunc
+ let name = '<SNR>' . s:foo()
+
+ try
+ py f = vim.bindeval('function("s:foo")')
+ call assert_equal(name, pyeval('f.name'))
+ catch
+ call assert_false(v:exception)
+ endtry
+
+ try
+ py f = vim.Function('\x80\xfdR' + vim.eval('s:foo()'))
+ call assert_equal(name, pyeval('f.name'))
+ catch
+ call assert_false(v:exception)
+ endtry
+
+ py del f
+ delfunc s:foo
+endfunc
diff --git a/src/nvim/testdir/test_python3.vim b/src/nvim/testdir/test_python3.vim
index f5b2c89853..2e3fc93674 100644
--- a/src/nvim/testdir/test_python3.vim
+++ b/src/nvim/testdir/test_python3.vim
@@ -25,3 +25,30 @@ func Test_py3do()
bwipe!
endif
endfunc
+
+func Test_vim_function()
+ " Check creating vim.Function object
+ py3 import vim
+
+ func s:foo()
+ return matchstr(expand('<sfile>'), '<SNR>\zs\d\+_foo$')
+ endfunc
+ let name = '<SNR>' . s:foo()
+
+ try
+ py3 f = vim.bindeval('function("s:foo")')
+ call assert_equal(name, py3eval('f.name'))
+ catch
+ call assert_false(v:exception)
+ endtry
+
+ try
+ py3 f = vim.Function(b'\x80\xfdR' + vim.eval('s:foo()').encode())
+ call assert_equal(name, py3eval('f.name'))
+ catch
+ call assert_false(v:exception)
+ endtry
+
+ py3 del f
+ delfunc s:foo
+endfunc
diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim
index 624e642e7f..cb3e7ca8f6 100644
--- a/src/nvim/testdir/test_quickfix.vim
+++ b/src/nvim/testdir/test_quickfix.vim
@@ -2235,6 +2235,35 @@ func Test_cclose_in_autocmd()
" call test_override('starting', 0)
endfunc
+" Check that ":file" without an argument is possible even when "curbuf_lock"
+" is set.
+func Test_file_from_copen()
+ " Works without argument.
+ augroup QF_Test
+ au!
+ au FileType qf file
+ augroup END
+ copen
+
+ augroup QF_Test
+ au!
+ augroup END
+ cclose
+
+ " Fails with argument.
+ augroup QF_Test
+ au!
+ au FileType qf call assert_fails(':file foo', 'E788')
+ augroup END
+ copen
+ augroup QF_Test
+ au!
+ augroup END
+ cclose
+
+ augroup! QF_Test
+endfunction
+
func Test_resize_from_copen()
augroup QF_Test
au!
@@ -2608,3 +2637,30 @@ func Test_shorten_fname()
silent! clist
call assert_equal('test_quickfix.vim', bufname('test_quickfix.vim'))
endfunc
+
+" Test for the position of the quickfix and location list window
+func Test_qfwin_pos()
+ " Open two windows
+ new | only
+ new
+ cexpr ['F1:10:L10']
+ copen
+ " Quickfix window should be the bottom most window
+ call assert_equal(3, winnr())
+ close
+ " Open at the very top
+ wincmd t
+ topleft copen
+ call assert_equal(1, winnr())
+ close
+ " open left of the current window
+ wincmd t
+ below new
+ leftabove copen
+ call assert_equal(2, winnr())
+ close
+ " open right of the current window
+ rightbelow copen
+ call assert_equal(3, winnr())
+ close
+endfunc
diff --git a/src/nvim/testdir/test_quotestar.vim b/src/nvim/testdir/test_quotestar.vim
index 3a7edcbd7c..3ce1a84281 100644
--- a/src/nvim/testdir/test_quotestar.vim
+++ b/src/nvim/testdir/test_quotestar.vim
@@ -87,6 +87,18 @@ func Do_test_quotestar_for_x11()
" Check that the *-register of this vim instance is changed as expected.
call WaitFor('@* == "yes"', 3000)
+ " Handle the large selection over 262040 byte.
+ let length = 262044
+ let sample = 'a' . repeat('b', length - 2) . 'c'
+ let @* = sample
+ call WaitFor('remote_expr("' . name . '", "len(@*) >= ' . length . '", "", 1)', 3000)
+ let res = remote_expr(name, "@*", "", 2)
+ call assert_equal(length, len(res))
+ " Check length to prevent a large amount of output at assertion failure.
+ if length == len(res)
+ call assert_equal(sample, res)
+ endif
+
if has('unix') && has('gui') && !has('gui_running')
let @* = ''
diff --git a/src/nvim/testdir/test_scriptnames.vim b/src/nvim/testdir/test_scriptnames.vim
new file mode 100644
index 0000000000..fc6c910bfa
--- /dev/null
+++ b/src/nvim/testdir/test_scriptnames.vim
@@ -0,0 +1,26 @@
+" Test for :scriptnames
+
+func Test_scriptnames()
+ call writefile(['let did_load_script = 123'], 'Xscripting')
+ source Xscripting
+ call assert_equal(123, g:did_load_script)
+
+ let scripts = split(execute('scriptnames'), "\n")
+ let last = scripts[-1]
+ call assert_match('\<Xscripting\>', last)
+ let lastnr = substitute(last, '\D*\(\d\+\):.*', '\1', '')
+ exe 'script ' . lastnr
+ call assert_equal('Xscripting', expand('%:t'))
+
+ call assert_fails('script ' . (lastnr + 1), 'E474:')
+ call assert_fails('script 0', 'E939:')
+
+ new
+ call setline(1, 'nothing')
+ call assert_fails('script ' . lastnr, 'E37:')
+ exe 'script! ' . lastnr
+ call assert_equal('Xscripting', expand('%:t'))
+
+ bwipe
+ call delete('Xscripting')
+endfunc
diff --git a/src/nvim/testdir/test_signs.vim b/src/nvim/testdir/test_signs.vim
index d3c6d05f4f..3960177acd 100644
--- a/src/nvim/testdir/test_signs.vim
+++ b/src/nvim/testdir/test_signs.vim
@@ -104,6 +104,33 @@ func Test_sign()
exe 'sign jump 43 file=' . fn
call assert_equal('B', getline('.'))
+ " can't define a sign with a non-printable character as text
+ call assert_fails("sign define Sign4 text=\e linehl=Comment", 'E239:')
+ call assert_fails("sign define Sign4 text=a\e linehl=Comment", 'E239:')
+ call assert_fails("sign define Sign4 text=\ea linehl=Comment", 'E239:')
+
+ " Only 1 or 2 character text is allowed
+ call assert_fails("sign define Sign4 text=abc linehl=Comment", 'E239:')
+ call assert_fails("sign define Sign4 text= linehl=Comment", 'E239:')
+ call assert_fails("sign define Sign4 text=\ ab linehl=Comment", 'E239:')
+
+ " define sign with whitespace
+ sign define Sign4 text=\ X linehl=Comment
+ sign undefine Sign4
+ sign define Sign4 linehl=Comment text=\ X
+ sign undefine Sign4
+
+ sign define Sign5 text=X\ linehl=Comment
+ sign undefine Sign5
+ sign define Sign5 linehl=Comment text=X\
+ sign undefine Sign5
+
+ " define sign with backslash
+ sign define Sign4 text=\\\\ linehl=Comment
+ sign undefine Sign4
+ sign define Sign4 text=\\ linehl=Comment
+ sign undefine Sign4
+
" After undefining the sign, we should no longer be able to place it.
sign undefine Sign1
sign undefine Sign2
diff --git a/src/nvim/testdir/test_spell.vim b/src/nvim/testdir/test_spell.vim
index a2828b21d2..b3438cc649 100644
--- a/src/nvim/testdir/test_spell.vim
+++ b/src/nvim/testdir/test_spell.vim
@@ -85,6 +85,36 @@ func Test_spellreall()
bwipe!
endfunc
+func Test_spellinfo()
+ throw 'skipped: Nvim does not support enc=latin1'
+ new
+
+ set enc=latin1 spell spelllang=en
+ call assert_match("^\nfile: .*/runtime/spell/en.latin1.spl\n$", execute('spellinfo'))
+
+ set enc=cp1250 spell spelllang=en
+ call assert_match("^\nfile: .*/runtime/spell/en.ascii.spl\n$", execute('spellinfo'))
+
+ if has('multi_byte')
+ set enc=utf-8 spell spelllang=en
+ call assert_match("^\nfile: .*/runtime/spell/en.utf-8.spl\n$", execute('spellinfo'))
+ endif
+
+ set enc=latin1 spell spelllang=en_us,en_nz
+ call assert_match("^\n" .
+ \ "file: .*/runtime/spell/en.latin1.spl\n" .
+ \ "file: .*/runtime/spell/en.latin1.spl\n$", execute('spellinfo'))
+
+ set spell spelllang=
+ call assert_fails('spellinfo', 'E756:')
+
+ set nospell spelllang=en
+ call assert_fails('spellinfo', 'E756:')
+
+ set enc& spell& spelllang&
+ bwipe
+endfunc
+
func Test_zz_basic()
call LoadAffAndDic(g:test_data_aff1, g:test_data_dic1)
call RunGoodBad("wrong OK puts. Test the end",
diff --git a/src/nvim/testdir/test_startup.vim b/src/nvim/testdir/test_startup.vim
index 2f4d857986..3bc9eaf756 100644
--- a/src/nvim/testdir/test_startup.vim
+++ b/src/nvim/testdir/test_startup.vim
@@ -150,6 +150,83 @@ func Test_compatible_args()
call delete('Xtestout')
endfunc
+" Test the -o[N] and -O[N] arguments to open N windows split
+" horizontally or vertically.
+func Test_o_arg()
+ let after = [
+ \ 'call writefile([winnr("$"),
+ \ winheight(1), winheight(2), &lines,
+ \ winwidth(1), winwidth(2), &columns,
+ \ bufname(winbufnr(1)), bufname(winbufnr(2))],
+ \ "Xtestout")',
+ \ 'qall',
+ \ ]
+ if RunVim([], after, '-o2')
+ " Open 2 windows split horizontally. Expect:
+ " - 2 windows
+ " - both windows should have the same or almost the same height
+ " - sum of both windows height (+ 3 for both statusline and Ex command)
+ " should be equal to the number of lines
+ " - both windows should have the same width which should be equal to the
+ " number of columns
+ " - buffer of both windows should have no name
+ let [wn, wh1, wh2, ln, ww1, ww2, cn, bn1, bn2] = readfile('Xtestout')
+ call assert_equal('2', wn)
+ call assert_inrange(0, 1, wh1 - wh2)
+ call assert_equal(string(wh1 + wh2 + 3), ln)
+ call assert_equal(ww1, ww2)
+ call assert_equal(ww1, cn)
+ call assert_equal('', bn1)
+ call assert_equal('', bn2)
+ endif
+
+ if RunVim([], after, '-o foo bar')
+ " Same expectations as for -o2 but buffer names should be foo and bar
+ let [wn, wh1, wh2, ln, ww1, ww2, cn, bn1, bn2] = readfile('Xtestout')
+ call assert_equal('2', wn)
+ call assert_inrange(0, 1, wh1 - wh2)
+ call assert_equal(string(wh1 + wh2 + 3), ln)
+ call assert_equal(ww1, ww2)
+ call assert_equal(ww1, cn)
+ call assert_equal('foo', bn1)
+ call assert_equal('bar', bn2)
+ endif
+
+ if RunVim([], after, '-O2')
+ " Open 2 windows split vertically. Expect:
+ " - 2 windows
+ " - both windows should have the same or almost the same width
+ " - sum of both windows width (+ 1 separator) should be equal to the
+ " number of columns
+ " - both windows should have the same height
+ " - window height (+ 2 for the statusline and Ex command) should be equal
+ " to the number of lines
+ " - buffer of both windowns should have no name
+ let [wn, wh1, wh2, ln, ww1, ww2, cn, bn1, bn2] = readfile('Xtestout')
+ call assert_equal('2', wn)
+ call assert_inrange(0, 1, ww1 - ww2)
+ call assert_equal(string(ww1 + ww2 + 1), cn)
+ call assert_equal(wh1, wh2)
+ call assert_equal(string(wh1 + 2), ln)
+ call assert_equal('', bn1)
+ call assert_equal('', bn2)
+ endif
+
+ if RunVim([], after, '-O foo bar')
+ " Same expectations as for -O2 but buffer names should be foo and bar
+ let [wn, wh1, wh2, ln, ww1, ww2, cn, bn1, bn2] = readfile('Xtestout')
+ call assert_equal('2', wn)
+ call assert_inrange(0, 1, ww1 - ww2)
+ call assert_equal(string(ww1 + ww2 + 1), cn)
+ call assert_equal(wh1, wh2)
+ call assert_equal(string(wh1 + 2), ln)
+ call assert_equal('foo', bn1)
+ call assert_equal('bar', bn2)
+ endif
+
+ call delete('Xtestout')
+endfunc
+
func Test_file_args()
let after = [
\ 'call writefile(argv(), "Xtestout")',
diff --git a/src/nvim/testdir/test_stat.vim b/src/nvim/testdir/test_stat.vim
index c276df0a92..253f74c2ad 100644
--- a/src/nvim/testdir/test_stat.vim
+++ b/src/nvim/testdir/test_stat.vim
@@ -1,31 +1,33 @@
" Tests for stat functions and checktime
func CheckFileTime(doSleep)
- let fname = 'Xtest.tmp'
+ let fnames = ['Xtest1.tmp', 'Xtest2.tmp', 'Xtest3.tmp']
+ let times = []
let result = 0
- let ts = localtime()
- if a:doSleep
- sleep 1
- endif
+ " Use three files istead of localtim(), with a network filesystem the file
+ " times may differ at bit
let fl = ['Hello World!']
- call writefile(fl, fname)
- let tf = getftime(fname)
- if a:doSleep
- sleep 1
- endif
- let te = localtime()
+ for fname in fnames
+ call writefile(fl, fname)
+ call add(times, getftime(fname))
+ if a:doSleep
+ sleep 1
+ endif
+ endfor
- let time_correct = (ts <= tf && tf <= te)
+ let time_correct = (times[0] <= times[1] && times[1] <= times[2])
if a:doSleep || time_correct
- call assert_true(time_correct)
- call assert_equal(strlen(fl[0] . "\n"), getfsize(fname))
- call assert_equal('file', getftype(fname))
- call assert_equal('rw-', getfperm(fname)[0:2])
+ call assert_true(time_correct, printf('Expected %s <= %s <= %s', times[0], times[1], times[2]))
+ call assert_equal(strlen(fl[0] . "\n"), getfsize(fnames[0]))
+ call assert_equal('file', getftype(fnames[0]))
+ call assert_equal('rw-', getfperm(fnames[0])[0:2])
let result = 1
endif
- call delete(fname)
+ for fname in fnames
+ call delete(fname)
+ endfor
return result
endfunc
@@ -141,17 +143,29 @@ func Test_getftype()
endif
for cdevfile in systemlist('find /dev -type c -maxdepth 2 2>/dev/null')
- call assert_equal('cdev', getftype(cdevfile))
+ let type = getftype(cdevfile)
+ " ignore empty result, can happen if the file disappeared
+ if type != ''
+ call assert_equal('cdev', type)
+ endif
endfor
for bdevfile in systemlist('find /dev -type b -maxdepth 2 2>/dev/null')
- call assert_equal('bdev', getftype(bdevfile))
+ let type = getftype(bdevfile)
+ " ignore empty result, can happen if the file disappeared
+ if type != ''
+ call assert_equal('bdev', type)
+ endif
endfor
" The /run/ directory typically contains socket files.
" If it does not, test won't fail but will not test socket files.
for socketfile in systemlist('find /run -type s -maxdepth 2 2>/dev/null')
- call assert_equal('socket', getftype(socketfile))
+ let type = getftype(socketfile)
+ " ignore empty result, can happen if the file disappeared
+ if type != ''
+ call assert_equal('socket', type)
+ endif
endfor
" TODO: file type 'other' is not tested. How can we test it?
diff --git a/src/nvim/testdir/test_syntax.vim b/src/nvim/testdir/test_syntax.vim
index e35c0f1105..6978faeb7b 100644
--- a/src/nvim/testdir/test_syntax.vim
+++ b/src/nvim/testdir/test_syntax.vim
@@ -114,6 +114,15 @@ func Test_syntime()
bd
endfunc
+func Test_syntime_completion()
+ if !has('profile')
+ return
+ endif
+
+ call feedkeys(":syntime \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"syntime clear off on report', @:)
+endfunc
+
func Test_syntax_list()
syntax on
let a = execute('syntax list')
@@ -482,3 +491,15 @@ fun Test_synstack_synIDtrans()
syn clear
bw!
endfunc
+
+" Using \z() in a region with NFA failing should not crash.
+func Test_syn_wrong_z_one()
+ new
+ call setline(1, ['just some text', 'with foo and bar to match with'])
+ syn region FooBar start="foo\z(.*\)bar" end="\z1"
+ " call test_override("nfa_fail", 1)
+ redraw!
+ redraw!
+ " call test_override("ALL", 0)
+ bwipe!
+endfunc
diff --git a/src/nvim/testdir/test_timers.vim b/src/nvim/testdir/test_timers.vim
index da61751bf4..cdfdd473b9 100644
--- a/src/nvim/testdir/test_timers.vim
+++ b/src/nvim/testdir/test_timers.vim
@@ -44,7 +44,7 @@ func Test_repeat_many()
let timer = timer_start(50, 'MyHandler', {'repeat': -1})
sleep 200m
call timer_stop(timer)
- call assert_inrange(2, 4, g:val)
+ call assert_inrange((has('mac') ? 1 : 2), 4, g:val)
endfunc
func Test_with_partial_callback()
@@ -121,7 +121,7 @@ func Test_paused()
let slept = WaitFor('g:val == 1')
call assert_equal(1, g:val)
if has('reltime')
- call assert_inrange(0, 100, slept)
+ call assert_inrange(0, 140, slept)
else
call assert_inrange(0, 10, slept)
endif
@@ -167,6 +167,9 @@ func Test_stop_all_in_callback()
let g:timer1 = timer_start(10, 'StopTimerAll')
let info = timer_info()
call assert_equal(1, len(info))
+ if has('mac')
+ sleep 100m
+ endif
sleep 40m
let info = timer_info()
call assert_equal(0, len(info))
diff --git a/src/nvim/testdir/test_undo.vim b/src/nvim/testdir/test_undo.vim
index 83ede1dc37..9729ca9f57 100644
--- a/src/nvim/testdir/test_undo.vim
+++ b/src/nvim/testdir/test_undo.vim
@@ -373,7 +373,7 @@ funct Test_undofile()
let cwd = getcwd()
if has('win32')
" Replace windows drive such as C:... into C%...
- let cwd = substitute(cwd, '^\([A-Z]\):', '\1%', 'g')
+ let cwd = substitute(cwd, '^\([a-zA-Z]\):', '\1%', 'g')
endif
let pathsep = has('win32') ? '\' : '/'
let cwd = substitute(cwd . pathsep . 'Xundofoo', pathsep, '%', 'g')
diff --git a/src/nvim/testdir/test_usercommands.vim b/src/nvim/testdir/test_usercommands.vim
index db603610da..1520c2f32a 100644
--- a/src/nvim/testdir/test_usercommands.vim
+++ b/src/nvim/testdir/test_usercommands.vim
@@ -206,3 +206,15 @@ func Test_CmdCompletion()
com! -complete=customlist,CustomComp DoCmd :
call assert_fails("call feedkeys(':DoCmd \<C-D>', 'tx')", 'E117:')
endfunc
+
+func CallExecute(A, L, P)
+ " Drop first '\n'
+ return execute('echo "hi"')[1:]
+endfunc
+
+func Test_use_execute_in_completion()
+ command! -nargs=* -complete=custom,CallExecute DoExec :
+ call feedkeys(":DoExec \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"DoExec hi', @:)
+ delcommand DoExec
+endfunc
diff --git a/src/nvim/tui/terminfo.c b/src/nvim/tui/terminfo.c
index 42237903ea..27792655c9 100644
--- a/src/nvim/tui/terminfo.c
+++ b/src/nvim/tui/terminfo.c
@@ -13,6 +13,7 @@
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/option.h"
+#include "nvim/os/os.h"
#include "nvim/tui/terminfo.h"
#include "nvim/tui/terminfo_defs.h"
@@ -33,6 +34,24 @@ bool terminfo_is_term_family(const char *term, const char *family)
&& ('\0' == term[flen] || '-' == term[flen]);
}
+bool terminfo_is_bsd_console(const char *term)
+{
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \
+ || defined(__DragonFly__)
+ if (strequal(term, "vt220") // OpenBSD
+ || strequal(term, "vt100")) { // NetBSD
+ return true;
+ }
+# if defined(__FreeBSD__)
+ // FreeBSD console sets TERM=xterm, but it does not support xterm features
+ // like cursor-shaping. Assume that TERM=xterm is degraded. #8644
+ return strequal(term, "xterm") && !!os_getenv("XTERM_VERSION");
+# endif
+#else
+ return false;
+#endif
+}
+
/// Loads a built-in terminfo db when we (unibilium) failed to load a terminfo
/// record from the environment (termcap systems, unrecognized $TERM, …).
/// We do not attempt to detect xterm pretenders here.
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index f444d1ec84..c73de1049c 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -99,6 +99,7 @@ typedef struct {
bool can_set_lr_margin;
bool can_set_left_right_margin;
bool can_scroll;
+ bool can_erase_chars;
bool immediate_wrap_after_last_column;
bool bce;
bool mouse_enabled;
@@ -108,8 +109,9 @@ typedef struct {
cursorentry_T cursor_shapes[SHAPE_IDX_COUNT];
HlAttrs clear_attrs;
kvec_t(HlAttrs) attrs;
- HlAttrs print_attrs;
+ int print_attr_id;
bool default_attr;
+ bool can_clear_attr;
ModeShape showing_mode;
struct {
int enable_mouse, disable_mouse;
@@ -124,6 +126,7 @@ typedef struct {
int set_cursor_style, reset_cursor_style;
int enter_undercurl_mode, exit_undercurl_mode, set_underline_color;
} unibi_ext;
+ char *space_buf;
} TUIData;
static bool volatile got_winch = false;
@@ -189,6 +192,7 @@ static void terminfo_start(UI *ui)
data->scroll_region_is_full_screen = true;
data->bufpos = 0;
data->default_attr = false;
+ data->can_clear_attr = false;
data->is_invisible = true;
data->busy = false;
data->cork = false;
@@ -281,14 +285,17 @@ static void terminfo_start(UI *ui)
const char *colorterm = os_getenv("COLORTERM");
const char *termprg = os_getenv("TERM_PROGRAM");
const char *vte_version_env = os_getenv("VTE_VERSION");
- long vte_version = vte_version_env ? strtol(vte_version_env, NULL, 10) : 0;
+ long vtev = vte_version_env ? strtol(vte_version_env, NULL, 10) : 0;
bool iterm_env = termprg && strstr(termprg, "iTerm.app");
bool konsole = terminfo_is_term_family(term, "konsole")
|| os_getenv("KONSOLE_PROFILE_NAME")
|| os_getenv("KONSOLE_DBUS_SESSION");
+ const char *konsolev_env = os_getenv("KONSOLE_VERSION");
+ long konsolev = konsolev_env ? strtol(konsolev_env, NULL, 10)
+ : (konsole ? 1 : 0);
- patch_terminfo_bugs(data, term, colorterm, vte_version, konsole, iterm_env);
- augment_terminfo(data, term, colorterm, vte_version, konsole, iterm_env);
+ patch_terminfo_bugs(data, term, colorterm, vtev, konsolev, iterm_env);
+ augment_terminfo(data, term, colorterm, vtev, konsolev, iterm_env);
data->can_change_scroll_region =
!!unibi_get_str(data->ut, unibi_change_scroll_region);
data->can_set_lr_margin =
@@ -301,6 +308,7 @@ static void terminfo_start(UI *ui)
&& !!unibi_get_str(data->ut, unibi_parm_delete_line)
&& !!unibi_get_str(data->ut, unibi_insert_line)
&& !!unibi_get_str(data->ut, unibi_parm_insert_line);
+ data->can_erase_chars = !!unibi_get_str(data->ut, unibi_erase_chars);
data->immediate_wrap_after_last_column =
conemu_ansi
|| terminfo_is_term_family(term, "cygwin")
@@ -366,7 +374,7 @@ static void terminfo_stop(UI *ui)
static void tui_terminal_start(UI *ui)
{
TUIData *data = ui->data;
- data->print_attrs = HLATTRS_INVALID;
+ data->print_attr_id = -1;
ugrid_init(&data->grid);
terminfo_start(ui);
update_size(ui);
@@ -465,6 +473,7 @@ static void tui_main(UIBridgeData *bridge, UI *ui)
loop_close(&tui_loop, false);
kv_destroy(data->invalid_regions);
kv_destroy(data->attrs);
+ xfree(data->space_buf);
xfree(data);
}
@@ -499,8 +508,17 @@ static void sigwinch_cb(SignalWatcher *watcher, int signum, void *data)
ui_schedule_refresh();
}
-static bool attrs_differ(HlAttrs a1, HlAttrs a2, bool rgb)
+static bool attrs_differ(UI *ui, int id1, int id2, bool rgb)
{
+ TUIData *data = ui->data;
+ if (id1 == id2) {
+ return false;
+ } else if (id1 < 0 || id2 < 0) {
+ return true;
+ }
+ HlAttrs a1 = kv_A(data->attrs, (size_t)id1);
+ HlAttrs a2 = kv_A(data->attrs, (size_t)id2);
+
if (rgb) {
return a1.rgb_fg_color != a2.rgb_fg_color
|| a1.rgb_bg_color != a2.rgb_bg_color
@@ -515,21 +533,16 @@ static bool attrs_differ(HlAttrs a1, HlAttrs a2, bool rgb)
}
}
-static bool no_bg(UI *ui, HlAttrs attrs)
-{
- return ui->rgb ? attrs.rgb_bg_color == -1
- : attrs.cterm_bg_color == 0;
-}
-
-static void update_attrs(UI *ui, HlAttrs attrs)
+static void update_attrs(UI *ui, int attr_id)
{
TUIData *data = ui->data;
- if (!attrs_differ(attrs, data->print_attrs, ui->rgb)) {
+ if (!attrs_differ(ui, attr_id, data->print_attr_id, ui->rgb)) {
+ data->print_attr_id = attr_id;
return;
}
-
- data->print_attrs = attrs;
+ data->print_attr_id = attr_id;
+ HlAttrs attrs = kv_A(data->attrs, (size_t)attr_id);
int fg = ui->rgb ? attrs.rgb_fg_color : (attrs.cterm_fg_color - 1);
if (fg == -1) {
@@ -634,6 +647,12 @@ static void update_attrs(UI *ui, HlAttrs attrs)
data->default_attr = fg == -1 && bg == -1
&& !bold && !italic && !underline && !undercurl && !reverse && !standout;
+
+ // Non-BCE terminals can't clear with non-default background color. Some BCE
+ // terminals don't support attributes either, so don't rely on it. But assume
+ // italic and bold has no effect if there is no text.
+ data->can_clear_attr = !reverse && !standout && !underline && !undercurl
+ && (data->bce || bg == -1);
}
static void final_column_wrap(UI *ui)
@@ -659,7 +678,7 @@ static void print_cell(UI *ui, UCell *ptr)
// Printing the next character finally advances the cursor.
final_column_wrap(ui);
}
- update_attrs(ui, kv_A(data->attrs, ptr->attr));
+ update_attrs(ui, ptr->attr);
out(ui, ptr->data, strlen(ptr->data));
grid->col++;
if (data->immediate_wrap_after_last_column) {
@@ -675,8 +694,8 @@ static bool cheap_to_print(UI *ui, int row, int col, int next)
UCell *cell = grid->cells[row] + col;
while (next) {
next--;
- if (attrs_differ(kv_A(data->attrs, cell->attr),
- data->print_attrs, ui->rgb)) {
+ if (attrs_differ(ui, cell->attr,
+ data->print_attr_id, ui->rgb)) {
if (data->default_attr) {
return false;
}
@@ -726,7 +745,7 @@ static void cursor_goto(UI *ui, int row, int col)
int n = col - grid->col;
if (n <= (row == grid->row ? 4 : 2)
&& cheap_to_print(ui, grid->row, grid->col, n)) {
- UGRID_FOREACH_CELL(grid, grid->row, grid->row, grid->col, col - 1, {
+ UGRID_FOREACH_CELL(grid, grid->row, grid->col, col, {
print_cell(ui, cell);
});
}
@@ -798,50 +817,45 @@ safe_move:
}
static void clear_region(UI *ui, int top, int bot, int left, int right,
- HlAttrs attrs)
+ int attr_id)
{
TUIData *data = ui->data;
UGrid *grid = &data->grid;
- bool cleared = false;
-
- // non-BCE terminals can't clear with non-default background color
- bool can_clear = data->bce || no_bg(ui, attrs);
-
- if (can_clear && right == ui->width -1) {
- // Background is set to the default color and the right edge matches the
- // screen end, try to use terminal codes for clearing the requested area.
- update_attrs(ui, attrs);
- if (left == 0) {
- if (bot == ui->height - 1) {
- if (top == 0) {
- unibi_out(ui, unibi_clear_screen);
- ugrid_goto(&data->grid, top, left);
- } else {
- cursor_goto(ui, top, 0);
- unibi_out(ui, unibi_clr_eos);
- }
- cleared = true;
- }
+ update_attrs(ui, attr_id);
+
+ // Background is set to the default color and the right edge matches the
+ // screen end, try to use terminal codes for clearing the requested area.
+ if (data->can_clear_attr
+ && left == 0 && right == ui->width && bot == ui->height) {
+ if (top == 0) {
+ unibi_out(ui, unibi_clear_screen);
+ ugrid_goto(&data->grid, top, left);
+ } else {
+ cursor_goto(ui, top, 0);
+ unibi_out(ui, unibi_clr_eos);
}
+ } else {
+ int width = right-left;
- if (!cleared) {
- // iterate through each line and clear with clr_eol
- for (int row = top; row <= bot; row++) {
- cursor_goto(ui, row, left);
+ // iterate through each line and clear
+ for (int row = top; row < bot; row++) {
+ cursor_goto(ui, row, left);
+ if (data->can_clear_attr && right == ui->width) {
unibi_out(ui, unibi_clr_eol);
+ } else if (data->can_erase_chars && data->can_clear_attr && width >= 5) {
+ UNIBI_SET_NUM_VAR(data->params[0], width);
+ unibi_out(ui, unibi_erase_chars);
+ } else {
+ out(ui, data->space_buf, (size_t)width);
+ grid->col += width;
+ if (data->immediate_wrap_after_last_column) {
+ // Printing at the right margin immediately advances the cursor.
+ final_column_wrap(ui);
+ }
}
- cleared = true;
}
}
-
- if (!cleared) {
- // could not clear using faster terminal codes, refresh the whole region
- UGRID_FOREACH_CELL(grid, top, bot, left, right, {
- cursor_goto(ui, row, col);
- print_cell(ui, cell);
- });
- }
}
static void set_scroll_region(UI *ui, int top, int bot, int left, int right)
@@ -902,12 +916,16 @@ static void tui_grid_resize(UI *ui, Integer g, Integer width, Integer height)
UGrid *grid = &data->grid;
ugrid_resize(grid, (int)width, (int)height);
+ xfree(data->space_buf);
+ data->space_buf = xmalloc((size_t)width * sizeof(*data->space_buf));
+ memset(data->space_buf, ' ', (size_t)width);
+
// resize might not always be followed by a clear before flush
// so clip the invalid region
for (size_t i = 0; i < kv_size(data->invalid_regions); i++) {
Rect *r = &kv_A(data->invalid_regions, i);
- r->bot = MIN(r->bot, grid->height-1);
- r->right = MIN(r->right, grid->width-1);
+ r->bot = MIN(r->bot, grid->height);
+ r->right = MIN(r->right, grid->width);
}
if (!got_winch) { // Try to resize the terminal window.
@@ -930,8 +948,7 @@ static void tui_grid_clear(UI *ui, Integer g)
UGrid *grid = &data->grid;
ugrid_clear(grid);
kv_size(data->invalid_regions) = 0;
- clear_region(ui, 0, grid->height-1, 0, grid->width-1,
- data->clear_attrs);
+ clear_region(ui, 0, grid->height, 0, grid->width, 0);
}
static void tui_grid_cursor_goto(UI *ui, Integer grid, Integer row, Integer col)
@@ -1089,9 +1106,7 @@ static void tui_grid_scroll(UI *ui, Integer g, Integer startrow, Integer endrow,
data->scroll_region_is_full_screen = fullwidth
&& top == 0 && bot == ui->height-1;
- int clear_top, clear_bot;
- ugrid_scroll(grid, top, bot, left, right, (int)rows,
- &clear_top, &clear_bot);
+ ugrid_scroll(grid, top, bot, left, right, (int)rows);
bool can_scroll = data->can_scroll
&& (data->scroll_region_is_full_screen
@@ -1106,8 +1121,6 @@ static void tui_grid_scroll(UI *ui, Integer g, Integer startrow, Integer endrow,
set_scroll_region(ui, top, bot, left, right);
}
cursor_goto(ui, top, left);
- // also set default color attributes or some terminals can become funny
- update_attrs(ui, data->clear_attrs);
if (rows > 0) {
if (rows == 1) {
@@ -1129,16 +1142,14 @@ static void tui_grid_scroll(UI *ui, Integer g, Integer startrow, Integer endrow,
if (!data->scroll_region_is_full_screen) {
reset_scroll_region(ui, fullwidth);
}
-
- if (!(data->bce || no_bg(ui, data->clear_attrs))) {
- // Scrolling will leave wrong background in the cleared area on non-BCE
- // terminals. Update the cleared area.
- clear_region(ui, clear_top, clear_bot, left, right,
- data->clear_attrs);
- }
} else {
- // Mark the entire scroll region as invalid for redrawing later
- invalidate(ui, top, bot, left, right);
+ // Mark the moved region as invalid for redrawing later
+ if (rows > 0) {
+ endrow = endrow - rows;
+ } else {
+ startrow = startrow - rows;
+ }
+ invalidate(ui, (int)startrow, (int)endrow, (int)startcol, (int)endcol);
}
}
@@ -1171,8 +1182,8 @@ static void tui_default_colors_set(UI *ui, Integer rgb_fg, Integer rgb_bg,
data->clear_attrs.cterm_fg_color = (int)cterm_fg;
data->clear_attrs.cterm_bg_color = (int)cterm_bg;
- data->print_attrs = HLATTRS_INVALID;
- invalidate(ui, 0, data->grid.height-1, 0, data->grid.width-1);
+ data->print_attr_id = -1;
+ invalidate(ui, 0, data->grid.height, 0, data->grid.width);
}
static void tui_flush(UI *ui)
@@ -1194,11 +1205,27 @@ static void tui_flush(UI *ui)
while (kv_size(data->invalid_regions)) {
Rect r = kv_pop(data->invalid_regions);
- assert(r.bot < grid->height && r.right < grid->width);
- UGRID_FOREACH_CELL(grid, r.top, r.bot, r.left, r.right, {
- cursor_goto(ui, row, col);
- print_cell(ui, cell);
- });
+ assert(r.bot <= grid->height && r.right <= grid->width);
+
+ for (int row = r.top; row < r.bot; row++) {
+ int clear_attr = grid->cells[row][r.right-1].attr;
+ int clear_col;
+ for (clear_col = r.right; clear_col > 0; clear_col--) {
+ UCell *cell = &grid->cells[row][clear_col-1];
+ if (!(cell->data[0] == ' ' && cell->data[1] == NUL
+ && cell->attr == clear_attr)) {
+ break;
+ }
+ }
+
+ UGRID_FOREACH_CELL(grid, row, r.left, clear_col, {
+ cursor_goto(ui, row, col);
+ print_cell(ui, cell);
+ });
+ if (clear_col < r.right) {
+ clear_region(ui, row, row+1, clear_col, r.right, clear_attr);
+ }
+ }
}
cursor_goto(ui, data->row, data->col);
@@ -1283,8 +1310,8 @@ static void tui_option_set(UI *ui, String name, Object value)
if (strequal(name.data, "termguicolors")) {
ui->rgb = value.data.boolean;
- data->print_attrs = HLATTRS_INVALID;
- invalidate(ui, 0, data->grid.height-1, 0, data->grid.width-1);
+ data->print_attr_id = -1;
+ invalidate(ui, 0, data->grid.height, 0, data->grid.width);
}
}
@@ -1300,18 +1327,16 @@ static void tui_raw_line(UI *ui, Integer g, Integer linerow, Integer startcol,
assert((size_t)attrs[c-startcol] < kv_size(data->attrs));
grid->cells[linerow][c].attr = attrs[c-startcol];
}
- UGRID_FOREACH_CELL(grid, (int)linerow, (int)linerow, (int)startcol,
- (int)endcol-1, {
- cursor_goto(ui, row, col);
+ UGRID_FOREACH_CELL(grid, (int)linerow, (int)startcol, (int)endcol, {
+ cursor_goto(ui, (int)linerow, col);
print_cell(ui, cell);
});
if (clearcol > endcol) {
- HlAttrs cl_attrs = kv_A(data->attrs, (size_t)clearattr);
ugrid_clear_chunk(grid, (int)linerow, (int)endcol, (int)clearcol,
(sattr_T)clearattr);
- clear_region(ui, (int)linerow, (int)linerow, (int)endcol, (int)clearcol-1,
- cl_attrs);
+ clear_region(ui, (int)linerow, (int)linerow+1, (int)endcol, (int)clearcol,
+ (int)clearattr);
}
if (wrap && ui->width == grid->width && linerow + 1 < grid->height) {
@@ -1319,9 +1344,10 @@ static void tui_raw_line(UI *ui, Integer g, Integer linerow, Integer startcol,
// width and the line continuation is within the grid.
if (endcol != grid->width) {
- // Print the last cell of the row, if we haven't already done so.
- cursor_goto(ui, (int)linerow, grid->width - 1);
- print_cell(ui, &grid->cells[linerow][grid->width - 1]);
+ // Print the last char of the row, if we haven't already done so.
+ int size = grid->cells[linerow][grid->width - 1].data[0] == NUL ? 2 : 1;
+ cursor_goto(ui, (int)linerow, grid->width - size);
+ print_cell(ui, &grid->cells[linerow][grid->width - size]);
}
// Wrap the cursor over to the next line. The next line will be
@@ -1334,27 +1360,17 @@ static void invalidate(UI *ui, int top, int bot, int left, int right)
{
TUIData *data = ui->data;
Rect *intersects = NULL;
- // Increase dimensions before comparing to ensure adjacent regions are
- // treated as intersecting
- --top;
- ++bot;
- --left;
- ++right;
for (size_t i = 0; i < kv_size(data->invalid_regions); i++) {
Rect *r = &kv_A(data->invalid_regions, i);
- if (!(top > r->bot || bot < r->top
- || left > r->right || right < r->left)) {
+ // adjacent regions are treated as overlapping
+ if (!(top > r->bot || bot < r->top)
+ && !(left > r->right || right < r->left)) {
intersects = r;
break;
}
}
- ++top;
- --bot;
- ++left;
- --right;
-
if (intersects) {
// If top/bot/left/right intersects with a invalid rect, we replace it
// by the union
@@ -1514,16 +1530,19 @@ static int unibi_find_ext_bool(unibi_term *ut, const char *name)
/// and several terminal emulators falsely announce incorrect terminal types.
static void patch_terminfo_bugs(TUIData *data, const char *term,
const char *colorterm, long vte_version,
- bool konsole, bool iterm_env)
+ long konsolev, bool iterm_env)
{
unibi_term *ut = data->ut;
- const char * xterm_version = os_getenv("XTERM_VERSION");
+ const char *xterm_version = os_getenv("XTERM_VERSION");
#if 0 // We don't need to identify this specifically, for now.
bool roxterm = !!os_getenv("ROXTERM_ID");
#endif
- bool xterm = terminfo_is_term_family(term, "xterm");
+ bool xterm = terminfo_is_term_family(term, "xterm")
+ // Treat Terminal.app as generic xterm-like, for now.
+ || terminfo_is_term_family(term, "nsterm");
bool kitty = terminfo_is_term_family(term, "xterm-kitty");
bool linuxvt = terminfo_is_term_family(term, "linux");
+ bool bsdvt = terminfo_is_bsd_console(term);
bool rxvt = terminfo_is_term_family(term, "rxvt");
bool teraterm = terminfo_is_term_family(term, "teraterm");
bool putty = terminfo_is_term_family(term, "putty");
@@ -1539,12 +1558,12 @@ static void patch_terminfo_bugs(TUIData *data, const char *term,
bool alacritty = terminfo_is_term_family(term, "alacritty");
// None of the following work over SSH; see :help TERM .
bool iterm_pretending_xterm = xterm && iterm_env;
- bool konsole_pretending_xterm = xterm && konsole;
+ bool konsole_pretending_xterm = xterm && konsolev;
bool gnome_pretending_xterm = xterm && colorterm
&& strstr(colorterm, "gnome-terminal");
bool mate_pretending_xterm = xterm && colorterm
&& strstr(colorterm, "mate-terminal");
- bool true_xterm = xterm && !!xterm_version;
+ bool true_xterm = xterm && !!xterm_version && !bsdvt;
bool cygwin = terminfo_is_term_family(term, "cygwin");
bool conemu = terminfo_is_term_family(term, "conemu");
@@ -1689,7 +1708,7 @@ static void patch_terminfo_bugs(TUIData *data, const char *term,
unibi_set_num(ut, unibi_max_colors, 256);
unibi_set_str(ut, unibi_set_a_foreground, XTERM_SETAF_256_COLON);
unibi_set_str(ut, unibi_set_a_background, XTERM_SETAB_256_COLON);
- } else if (konsole || xterm || gnome || rxvt || st || putty
+ } else if (konsolev || xterm || gnome || rxvt || st || putty
|| linuxvt // Linux 4.8+ supports 256-colour SGR.
|| mate_pretending_xterm || gnome_pretending_xterm
|| tmux
@@ -1710,7 +1729,8 @@ static void patch_terminfo_bugs(TUIData *data, const char *term,
}
// Blacklist of terminals that cannot be trusted to report DECSCUSR support.
- if (!(st || (vte_version != 0 && vte_version < 3900) || konsole)) {
+ if (!(st || (vte_version != 0 && vte_version < 3900)
+ || (konsolev > 0 && konsolev < 180770))) {
data->unibi_ext.reset_cursor_style = unibi_find_ext_str(ut, "Se");
data->unibi_ext.set_cursor_style = unibi_find_ext_str(ut, "Ss");
}
@@ -1719,15 +1739,15 @@ static void patch_terminfo_bugs(TUIData *data, const char *term,
// adding them to terminal types, that have such control sequences but lack
// the correct terminfo entries, is a fixup, not an augmentation.
if (-1 == data->unibi_ext.set_cursor_style) {
- // DECSCUSR (cursor shape) sequence is widely supported by several terminal
- // types. https://github.com/gnachman/iTerm2/pull/92
- // xterm extension: vertical bar
- if (!konsole
+ // DECSCUSR (cursor shape) is widely supported.
+ // https://github.com/gnachman/iTerm2/pull/92
+ if ((!bsdvt && (!konsolev || konsolev >= 180770))
&& ((xterm && !vte_version) // anything claiming xterm compat
// per MinTTY 0.4.3-1 release notes from 2009
|| putty
// per https://bugzilla.gnome.org/show_bug.cgi?id=720821
|| (vte_version >= 3900)
+ || (konsolev >= 180770) // #9364
|| tmux // per tmux manual page
// https://lists.gnu.org/archive/html/screen-devel/2013-03/msg00000.html
|| screen
@@ -1735,7 +1755,7 @@ static void patch_terminfo_bugs(TUIData *data, const char *term,
|| rxvt // per command.C
// per analysis of VT100Terminal.m
|| iterm || iterm_pretending_xterm
- || teraterm // per TeraTerm "Supported Control Functions" doco
+ || teraterm // per TeraTerm "Supported Control Functions" doco
|| alacritty // https://github.com/jwilm/alacritty/pull/608
|| cygwin
// Some linux-type terminals implement the xterm extension.
@@ -1776,12 +1796,10 @@ static void patch_terminfo_bugs(TUIData *data, const char *term,
"");
}
unibi_set_ext_str(ut, (size_t)data->unibi_ext.reset_cursor_style,
- "\x1b[?c");
- } else if (konsole) {
- // Konsole uses an idiosyncratic escape code to set the cursor shape and
- // does not support DECSCUSR. This makes Konsole set up and apply a
- // nonce profile, which has side-effects on temporary font resizing.
- // In an ideal world, Konsole would just support DECSCUSR.
+ "\x1b[?c");
+ } else if (konsolev > 0 && konsolev < 180770) {
+ // Konsole before version 18.07.70: set up a nonce profile. This has
+ // side-effects on temporary font resizing. #6798
data->unibi_ext.set_cursor_style = (int)unibi_add_ext_str(ut, "Ss",
TMUX_WRAP(tmux, "\x1b]50;CursorShape=%?"
"%p1%{3}%<" "%t%{0}" // block
@@ -1804,10 +1822,14 @@ static void patch_terminfo_bugs(TUIData *data, const char *term,
/// This adds stuff that is not in standard terminfo as extended unibilium
/// capabilities.
static void augment_terminfo(TUIData *data, const char *term,
- const char *colorterm, long vte_version, bool konsole, bool iterm_env)
+ const char *colorterm, long vte_version,
+ long konsolev, bool iterm_env)
{
unibi_term *ut = data->ut;
- bool xterm = terminfo_is_term_family(term, "xterm");
+ bool xterm = terminfo_is_term_family(term, "xterm")
+ // Treat Terminal.app as generic xterm-like, for now.
+ || terminfo_is_term_family(term, "nsterm");
+ bool bsdvt = terminfo_is_bsd_console(term);
bool dtterm = terminfo_is_term_family(term, "dtterm");
bool rxvt = terminfo_is_term_family(term, "rxvt");
bool teraterm = terminfo_is_term_family(term, "teraterm");
@@ -1818,16 +1840,17 @@ static void augment_terminfo(TUIData *data, const char *term,
|| terminfo_is_term_family(term, "iterm2")
|| terminfo_is_term_family(term, "iTerm.app")
|| terminfo_is_term_family(term, "iTerm2.app");
+ bool alacritty = terminfo_is_term_family(term, "alacritty");
// None of the following work over SSH; see :help TERM .
bool iterm_pretending_xterm = xterm && iterm_env;
- const char * xterm_version = os_getenv("XTERM_VERSION");
- bool true_xterm = xterm && !!xterm_version;
+ const char *xterm_version = os_getenv("XTERM_VERSION");
+ bool true_xterm = xterm && !!xterm_version && !bsdvt;
// Only define this capability for terminal types that we know understand it.
if (dtterm // originated this extension
|| xterm // per xterm ctlseqs doco
- || konsole // per commentary in VT102Emulation.cpp
+ || konsolev // per commentary in VT102Emulation.cpp
|| teraterm // per TeraTerm "Supported Control Functions" doco
|| rxvt) { // per command.C
data->unibi_ext.resize_screen = (int)unibi_add_ext_str(ut,
@@ -1885,7 +1908,8 @@ static void augment_terminfo(TUIData *data, const char *term,
// would use a tmux control sequence and an extra if(screen) test.
data->unibi_ext.set_cursor_color = (int)unibi_add_ext_str(
ut, NULL, TMUX_WRAP(tmux, "\033]Pl%p1%06x\033\\"));
- } else if ((xterm || rxvt) && (vte_version == 0 || vte_version >= 3900)) {
+ } else if ((xterm || rxvt || alacritty)
+ && (vte_version == 0 || vte_version >= 3900)) {
// Supported in urxvt, newer VTE.
data->unibi_ext.set_cursor_color = (int)unibi_add_ext_str(
ut, "ext.set_cursor_color", "\033]12;#%p1%06x\007");
@@ -1925,13 +1949,9 @@ static void augment_terminfo(TUIData *data, const char *term,
ut, "ext.enter_undercurl_mode", "\x1b[4:3m");
data->unibi_ext.exit_undercurl_mode = (int)unibi_add_ext_str(
ut, "ext.exit_undercurl_mode", "\x1b[4:0m");
- if (has_colon_rgb) {
- data->unibi_ext.set_underline_color = (int)unibi_add_ext_str(
- ut, "ext.set_underline_color", "\x1b[58:2:%p1%d:%p2%d:%p3%dm");
- } else {
- data->unibi_ext.set_underline_color = (int)unibi_add_ext_str(
- ut, "ext.set_underline_color", "\x1b[58;2;%p1%d;%p2%d;%p3%dm");
- }
+ // Only support colon syntax. #9270
+ data->unibi_ext.set_underline_color = (int)unibi_add_ext_str(
+ ut, "ext.set_underline_color", "\x1b[58:2::%p1%d:%p2%d:%p3%dm");
}
}
diff --git a/src/nvim/ugrid.c b/src/nvim/ugrid.c
index b741a61d8c..f5bd35a48e 100644
--- a/src/nvim/ugrid.c
+++ b/src/nvim/ugrid.c
@@ -52,8 +52,7 @@ void ugrid_goto(UGrid *grid, int row, int col)
grid->col = col;
}
-void ugrid_scroll(UGrid *grid, int top, int bot, int left, int right,
- int count, int *clear_top, int *clear_bot)
+void ugrid_scroll(UGrid *grid, int top, int bot, int left, int right, int count)
{
// Compute start/stop/step for the loop below
int start, stop, step;
@@ -76,26 +75,18 @@ void ugrid_scroll(UGrid *grid, int top, int bot, int left, int right,
memcpy(target_row, source_row,
sizeof(UCell) * (size_t)(right - left + 1));
}
-
- // clear cells in the emptied region,
- if (count > 0) {
- *clear_top = stop;
- *clear_bot = stop + count - 1;
- } else {
- *clear_bot = stop;
- *clear_top = stop + count + 1;
- }
- clear_region(grid, *clear_top, *clear_bot, left, right, 0);
}
static void clear_region(UGrid *grid, int top, int bot, int left, int right,
sattr_T attr)
{
- UGRID_FOREACH_CELL(grid, top, bot, left, right, {
- cell->data[0] = ' ';
- cell->data[1] = 0;
- cell->attr = attr;
- });
+ for (int row = top; row <= bot; row++) {
+ UGRID_FOREACH_CELL(grid, row, left, right+1, {
+ cell->data[0] = ' ';
+ cell->data[1] = 0;
+ cell->attr = attr;
+ });
+ }
}
static void destroy_cells(UGrid *grid)
diff --git a/src/nvim/ugrid.h b/src/nvim/ugrid.h
index af78fe91c5..33a706b8c0 100644
--- a/src/nvim/ugrid.h
+++ b/src/nvim/ugrid.h
@@ -22,15 +22,13 @@ struct ugrid {
// -V:UGRID_FOREACH_CELL:625
-#define UGRID_FOREACH_CELL(grid, top, bot, left, right, code) \
+#define UGRID_FOREACH_CELL(grid, row, startcol, endcol, code) \
do { \
- for (int row = top; row <= bot; row++) { \
- UCell *row_cells = (grid)->cells[row]; \
- for (int col = left; col <= right; col++) { \
- UCell *cell = row_cells + col; \
- (void)(cell); \
- code; \
- } \
+ UCell *row_cells = (grid)->cells[row]; \
+ for (int col = startcol; col < endcol; col++) { \
+ UCell *cell = row_cells + col; \
+ (void)(cell); \
+ code; \
} \
} while (0)
diff --git a/src/nvim/ui_bridge.c b/src/nvim/ui_bridge.c
index ebd4651f4d..bd5d37be73 100644
--- a/src/nvim/ui_bridge.c
+++ b/src/nvim/ui_bridge.c
@@ -104,7 +104,7 @@ static void ui_thread_run(void *data)
static void ui_bridge_stop(UI *b)
{
- // Detach brigde first, so that "stop" is the last event the TUI loop
+ // Detach bridge first, so that "stop" is the last event the TUI loop
// receives from the main thread. #8041
ui_detach_impl(b);
UIBridgeData *bridge = (UIBridgeData *)b;
@@ -117,6 +117,7 @@ static void ui_bridge_stop(UI *b)
if (stopped) { // -V547
break;
}
+ // TODO(justinmk): Remove this. Use a cond-wait above. #9274
loop_poll_events(&main_loop, 10); // Process one event.
}
uv_thread_join(&bridge->ui_thread);
diff --git a/src/nvim/version.c b/src/nvim/version.c
index beb65a8bfd..966ecfd719 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -159,7 +159,7 @@ static const int included_patches[] = {
// 1769,
// 1768,
// 1767,
- // 1766,
+ 1766,
1765,
1764,
// 1763,
@@ -167,7 +167,7 @@ static const int included_patches[] = {
// 1761,
1760,
// 1759,
- // 1758,
+ 1758,
1757,
// 1756,
1755,
@@ -194,7 +194,7 @@ static const int included_patches[] = {
// 1734,
// 1733,
// 1732,
- // 1731,
+ 1731,
1730,
// 1729,
// 1728,
@@ -305,7 +305,7 @@ static const int included_patches[] = {
// 1623,
1622,
// 1621,
- // 1620,
+ 1620,
// 1619,
1618,
// 1617,
@@ -372,7 +372,7 @@ static const int included_patches[] = {
1556,
1555,
// 1554,
- // 1553,
+ 1553,
// 1552,
// 1551,
// 1550,
@@ -460,15 +460,15 @@ static const int included_patches[] = {
1468,
1467,
1466,
- // 1465,
+ 1465,
1464,
// 1463,
// 1462,
// 1461,
// 1460,
// 1459,
- // 1458,
- // 1457,
+ 1458,
+ 1457,
1456,
// 1455,
// 1454,
@@ -487,7 +487,7 @@ static const int included_patches[] = {
1441,
// 1440,
1439,
- // 1438,
+ 1438,
1437,
// 1436,
1435,
@@ -498,7 +498,7 @@ static const int included_patches[] = {
// 1430,
// 1429,
1428,
- // 1427,
+ 1427,
1426,
// 1425,
1424,
@@ -573,7 +573,7 @@ static const int included_patches[] = {
// 1355,
// 1354,
// 1353,
- // 1352,
+ 1352,
1351,
// 1350,
// 1349,
@@ -646,7 +646,7 @@ static const int included_patches[] = {
1282,
1281,
// 1280,
- // 1279,
+ 1279,
// 1278,
// 1277,
// 1276,
@@ -676,7 +676,7 @@ static const int included_patches[] = {
1252,
1251,
1250,
- // 1249,
+ 1249,
1248,
1247,
// 1246,
@@ -754,15 +754,15 @@ static const int included_patches[] = {
// 1174,
// 1173,
1172,
- // 1171,
+ 1171,
// 1170,
1169,
1168,
// 1167,
1166,
- // 1165,
+ 1165,
// 1164,
- // 1163,
+ 1163,
// 1162,
1161,
1160,
@@ -1188,7 +1188,7 @@ static const int included_patches[] = {
// 740,
// 739,
// 738,
- // 737,
+ 737,
736,
735,
734,
@@ -2173,7 +2173,7 @@ void intro_message(int colon)
N_(NVIM_VERSION_LONG),
"",
N_("Nvim is open source and freely distributable"),
- N_("https://neovim.io/community"),
+ N_("https://neovim.io/#chat"),
"",
N_("type :help nvim<Enter> if you are new! "),
N_("type :checkhealth<Enter> to optimize Nvim"),
diff --git a/src/nvim/xdiff/COPYING b/src/nvim/xdiff/COPYING
new file mode 100644
index 0000000000..f3f1b3b65e
--- /dev/null
+++ b/src/nvim/xdiff/COPYING
@@ -0,0 +1,504 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/src/nvim/xdiff/README.txt b/src/nvim/xdiff/README.txt
new file mode 100644
index 0000000000..1afe74095b
--- /dev/null
+++ b/src/nvim/xdiff/README.txt
@@ -0,0 +1,16 @@
+The files in this directory come from the xdiff implementation in git.
+You can find it here: https://github.com/git/git/tree/master/xdiff
+The files were last updated 2018 September 10.
+
+This is originally based on libxdiff, which can be found here:
+http://www.xmailserver.org/xdiff-lib.html
+
+The git version was used because it has been maintained and improved.
+And since it's part of git it is expected to be reliable.
+
+The code is distributed under the GNU LGPL license. It is included in the
+COPYING file.
+
+Changes in these files were made to avoid compiler warnings.
+
+The first work for including xdiff in Vim was done by Christian Brabandt.
diff --git a/src/nvim/xdiff/xdiff.h b/src/nvim/xdiff/xdiff.h
new file mode 100644
index 0000000000..bc26fb64fd
--- /dev/null
+++ b/src/nvim/xdiff/xdiff.h
@@ -0,0 +1,143 @@
+/*
+ * LibXDiff by Davide Libenzi ( File Differential Library )
+ * Copyright (C) 2003 Davide Libenzi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+#if !defined(XDIFF_H)
+#define XDIFF_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* #ifdef __cplusplus */
+
+/* xpparm_t.flags */
+#define XDF_NEED_MINIMAL (1 << 0)
+
+#define XDF_IGNORE_WHITESPACE (1 << 1)
+#define XDF_IGNORE_WHITESPACE_CHANGE (1 << 2)
+#define XDF_IGNORE_WHITESPACE_AT_EOL (1 << 3)
+#define XDF_IGNORE_CR_AT_EOL (1 << 4)
+#define XDF_WHITESPACE_FLAGS (XDF_IGNORE_WHITESPACE | \
+ XDF_IGNORE_WHITESPACE_CHANGE | \
+ XDF_IGNORE_WHITESPACE_AT_EOL | \
+ XDF_IGNORE_CR_AT_EOL)
+
+#define XDF_IGNORE_BLANK_LINES (1 << 7)
+
+#define XDF_PATIENCE_DIFF (1 << 14)
+#define XDF_HISTOGRAM_DIFF (1 << 15)
+#define XDF_DIFF_ALGORITHM_MASK (XDF_PATIENCE_DIFF | XDF_HISTOGRAM_DIFF)
+#define XDF_DIFF_ALG(x) ((x) & XDF_DIFF_ALGORITHM_MASK)
+
+#define XDF_INDENT_HEURISTIC (1 << 23)
+
+/* xdemitconf_t.flags */
+#define XDL_EMIT_FUNCNAMES (1 << 0)
+#define XDL_EMIT_FUNCCONTEXT (1 << 2)
+
+/* merge simplification levels */
+#define XDL_MERGE_MINIMAL 0
+#define XDL_MERGE_EAGER 1
+#define XDL_MERGE_ZEALOUS 2
+#define XDL_MERGE_ZEALOUS_ALNUM 3
+
+/* merge favor modes */
+#define XDL_MERGE_FAVOR_OURS 1
+#define XDL_MERGE_FAVOR_THEIRS 2
+#define XDL_MERGE_FAVOR_UNION 3
+
+/* merge output styles */
+#define XDL_MERGE_DIFF3 1
+
+typedef struct s_mmfile {
+ char *ptr;
+ long size;
+} mmfile_t;
+
+typedef struct s_mmbuffer {
+ char *ptr;
+ long size;
+} mmbuffer_t;
+
+typedef struct s_xpparam {
+ unsigned long flags;
+
+ /* See Documentation/diff-options.txt. */
+ char **anchors;
+ size_t anchors_nr;
+} xpparam_t;
+
+typedef struct s_xdemitcb {
+ void *priv;
+ int (*outf)(void *, mmbuffer_t *, int);
+} xdemitcb_t;
+
+typedef long (*find_func_t)(const char *line, long line_len, char *buffer, long buffer_size, void *priv);
+
+typedef int (*xdl_emit_hunk_consume_func_t)(long start_a, long count_a,
+ long start_b, long count_b,
+ void *cb_data);
+
+typedef struct s_xdemitconf {
+ long ctxlen;
+ long interhunkctxlen;
+ unsigned long flags;
+ find_func_t find_func;
+ void *find_func_priv;
+ xdl_emit_hunk_consume_func_t hunk_func;
+} xdemitconf_t;
+
+typedef struct s_bdiffparam {
+ long bsize;
+} bdiffparam_t;
+
+#include "../memory.h"
+
+#define xdl_malloc(x) xmalloc((x))
+#define xdl_free(ptr) xfree(ptr)
+#define xdl_realloc(ptr,x) xrealloc((ptr),(x))
+
+void *xdl_mmfile_first(mmfile_t *mmf, long *size);
+long xdl_mmfile_size(mmfile_t *mmf);
+
+int xdl_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
+ xdemitconf_t const *xecfg, xdemitcb_t *ecb);
+
+typedef struct s_xmparam {
+ xpparam_t xpp;
+ int marker_size;
+ int level;
+ int favor;
+ int style;
+ const char *ancestor; /* label for orig */
+ const char *file1; /* label for mf1 */
+ const char *file2; /* label for mf2 */
+} xmparam_t;
+
+#define DEFAULT_CONFLICT_MARKER_SIZE 7
+
+int xdl_merge(mmfile_t *orig, mmfile_t *mf1, mmfile_t *mf2,
+ xmparam_t const *xmp, mmbuffer_t *result);
+
+#ifdef __cplusplus
+}
+#endif /* #ifdef __cplusplus */
+
+#endif /* #if !defined(XDIFF_H) */
diff --git a/src/nvim/xdiff/xdiffi.c b/src/nvim/xdiff/xdiffi.c
new file mode 100644
index 0000000000..96d5277027
--- /dev/null
+++ b/src/nvim/xdiff/xdiffi.c
@@ -0,0 +1,1043 @@
+/*
+ * LibXDiff by Davide Libenzi ( File Differential Library )
+ * Copyright (C) 2003 Davide Libenzi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+#include "xinclude.h"
+
+#define XDL_MAX_COST_MIN 256
+#define XDL_HEUR_MIN_COST 256
+#define XDL_LINE_MAX (long)((1UL << (CHAR_BIT * sizeof(long) - 1)) - 1)
+#define XDL_SNAKE_CNT 20
+#define XDL_K_HEUR 4
+
+typedef struct s_xdpsplit {
+ long i1, i2;
+ int min_lo, min_hi;
+} xdpsplit_t;
+
+/*
+ * See "An O(ND) Difference Algorithm and its Variations", by Eugene Myers.
+ * Basically considers a "box" (off1, off2, lim1, lim2) and scan from both
+ * the forward diagonal starting from (off1, off2) and the backward diagonal
+ * starting from (lim1, lim2). If the K values on the same diagonal crosses
+ * returns the furthest point of reach. We might end up having to expensive
+ * cases using this algorithm is full, so a little bit of heuristic is needed
+ * to cut the search and to return a suboptimal point.
+ */
+static long xdl_split(unsigned long const *ha1, long off1, long lim1,
+ unsigned long const *ha2, long off2, long lim2,
+ long *kvdf, long *kvdb, int need_min, xdpsplit_t *spl,
+ xdalgoenv_t *xenv) {
+ long dmin = off1 - lim2, dmax = lim1 - off2;
+ long fmid = off1 - off2, bmid = lim1 - lim2;
+ long odd = (fmid - bmid) & 1;
+ long fmin = fmid, fmax = fmid;
+ long bmin = bmid, bmax = bmid;
+ long ec, d, i1, i2, prev1, best, dd, v, k;
+
+ /*
+ * Set initial diagonal values for both forward and backward path.
+ */
+ kvdf[fmid] = off1;
+ kvdb[bmid] = lim1;
+
+ for (ec = 1;; ec++) {
+ int got_snake = 0;
+
+ /*
+ * We need to extent the diagonal "domain" by one. If the next
+ * values exits the box boundaries we need to change it in the
+ * opposite direction because (max - min) must be a power of two.
+ * Also we initialize the external K value to -1 so that we can
+ * avoid extra conditions check inside the core loop.
+ */
+ if (fmin > dmin)
+ kvdf[--fmin - 1] = -1;
+ else
+ ++fmin;
+ if (fmax < dmax)
+ kvdf[++fmax + 1] = -1;
+ else
+ --fmax;
+
+ for (d = fmax; d >= fmin; d -= 2) {
+ if (kvdf[d - 1] >= kvdf[d + 1])
+ i1 = kvdf[d - 1] + 1;
+ else
+ i1 = kvdf[d + 1];
+ prev1 = i1;
+ i2 = i1 - d;
+ for (; i1 < lim1 && i2 < lim2 && ha1[i1] == ha2[i2]; i1++, i2++);
+ if (i1 - prev1 > xenv->snake_cnt)
+ got_snake = 1;
+ kvdf[d] = i1;
+ if (odd && bmin <= d && d <= bmax && kvdb[d] <= i1) {
+ spl->i1 = i1;
+ spl->i2 = i2;
+ spl->min_lo = spl->min_hi = 1;
+ return ec;
+ }
+ }
+
+ /*
+ * We need to extent the diagonal "domain" by one. If the next
+ * values exits the box boundaries we need to change it in the
+ * opposite direction because (max - min) must be a power of two.
+ * Also we initialize the external K value to -1 so that we can
+ * avoid extra conditions check inside the core loop.
+ */
+ if (bmin > dmin)
+ kvdb[--bmin - 1] = XDL_LINE_MAX;
+ else
+ ++bmin;
+ if (bmax < dmax)
+ kvdb[++bmax + 1] = XDL_LINE_MAX;
+ else
+ --bmax;
+
+ for (d = bmax; d >= bmin; d -= 2) {
+ if (kvdb[d - 1] < kvdb[d + 1])
+ i1 = kvdb[d - 1];
+ else
+ i1 = kvdb[d + 1] - 1;
+ prev1 = i1;
+ i2 = i1 - d;
+ for (; i1 > off1 && i2 > off2 && ha1[i1 - 1] == ha2[i2 - 1]; i1--, i2--);
+ if (prev1 - i1 > xenv->snake_cnt)
+ got_snake = 1;
+ kvdb[d] = i1;
+ if (!odd && fmin <= d && d <= fmax && i1 <= kvdf[d]) {
+ spl->i1 = i1;
+ spl->i2 = i2;
+ spl->min_lo = spl->min_hi = 1;
+ return ec;
+ }
+ }
+
+ if (need_min)
+ continue;
+
+ /*
+ * If the edit cost is above the heuristic trigger and if
+ * we got a good snake, we sample current diagonals to see
+ * if some of the, have reached an "interesting" path. Our
+ * measure is a function of the distance from the diagonal
+ * corner (i1 + i2) penalized with the distance from the
+ * mid diagonal itself. If this value is above the current
+ * edit cost times a magic factor (XDL_K_HEUR) we consider
+ * it interesting.
+ */
+ if (got_snake && ec > xenv->heur_min) {
+ for (best = 0, d = fmax; d >= fmin; d -= 2) {
+ dd = d > fmid ? d - fmid: fmid - d;
+ i1 = kvdf[d];
+ i2 = i1 - d;
+ v = (i1 - off1) + (i2 - off2) - dd;
+
+ if (v > XDL_K_HEUR * ec && v > best &&
+ off1 + xenv->snake_cnt <= i1 && i1 < lim1 &&
+ off2 + xenv->snake_cnt <= i2 && i2 < lim2) {
+ for (k = 1; ha1[i1 - k] == ha2[i2 - k]; k++)
+ if (k == xenv->snake_cnt) {
+ best = v;
+ spl->i1 = i1;
+ spl->i2 = i2;
+ break;
+ }
+ }
+ }
+ if (best > 0) {
+ spl->min_lo = 1;
+ spl->min_hi = 0;
+ return ec;
+ }
+
+ for (best = 0, d = bmax; d >= bmin; d -= 2) {
+ dd = d > bmid ? d - bmid: bmid - d;
+ i1 = kvdb[d];
+ i2 = i1 - d;
+ v = (lim1 - i1) + (lim2 - i2) - dd;
+
+ if (v > XDL_K_HEUR * ec && v > best &&
+ off1 < i1 && i1 <= lim1 - xenv->snake_cnt &&
+ off2 < i2 && i2 <= lim2 - xenv->snake_cnt) {
+ for (k = 0; ha1[i1 + k] == ha2[i2 + k]; k++)
+ if (k == xenv->snake_cnt - 1) {
+ best = v;
+ spl->i1 = i1;
+ spl->i2 = i2;
+ break;
+ }
+ }
+ }
+ if (best > 0) {
+ spl->min_lo = 0;
+ spl->min_hi = 1;
+ return ec;
+ }
+ }
+
+ /*
+ * Enough is enough. We spent too much time here and now we collect
+ * the furthest reaching path using the (i1 + i2) measure.
+ */
+ if (ec >= xenv->mxcost) {
+ long fbest, fbest1, bbest, bbest1;
+
+ fbest = fbest1 = -1;
+ for (d = fmax; d >= fmin; d -= 2) {
+ i1 = XDL_MIN(kvdf[d], lim1);
+ i2 = i1 - d;
+ if (lim2 < i2)
+ i1 = lim2 + d, i2 = lim2;
+ if (fbest < i1 + i2) {
+ fbest = i1 + i2;
+ fbest1 = i1;
+ }
+ }
+
+ bbest = bbest1 = XDL_LINE_MAX;
+ for (d = bmax; d >= bmin; d -= 2) {
+ i1 = XDL_MAX(off1, kvdb[d]);
+ i2 = i1 - d;
+ if (i2 < off2)
+ i1 = off2 + d, i2 = off2;
+ if (i1 + i2 < bbest) {
+ bbest = i1 + i2;
+ bbest1 = i1;
+ }
+ }
+
+ if ((lim1 + lim2) - bbest < fbest - (off1 + off2)) {
+ spl->i1 = fbest1;
+ spl->i2 = fbest - fbest1;
+ spl->min_lo = 1;
+ spl->min_hi = 0;
+ } else {
+ spl->i1 = bbest1;
+ spl->i2 = bbest - bbest1;
+ spl->min_lo = 0;
+ spl->min_hi = 1;
+ }
+ return ec;
+ }
+ }
+}
+
+
+/*
+ * Rule: "Divide et Impera". Recursively split the box in sub-boxes by calling
+ * the box splitting function. Note that the real job (marking changed lines)
+ * is done in the two boundary reaching checks.
+ */
+int xdl_recs_cmp(diffdata_t *dd1, long off1, long lim1,
+ diffdata_t *dd2, long off2, long lim2,
+ long *kvdf, long *kvdb, int need_min, xdalgoenv_t *xenv) {
+ unsigned long const *ha1 = dd1->ha, *ha2 = dd2->ha;
+
+ /*
+ * Shrink the box by walking through each diagonal snake (SW and NE).
+ */
+ for (; off1 < lim1 && off2 < lim2 && ha1[off1] == ha2[off2]; off1++, off2++);
+ for (; off1 < lim1 && off2 < lim2 && ha1[lim1 - 1] == ha2[lim2 - 1]; lim1--, lim2--);
+
+ /*
+ * If one dimension is empty, then all records on the other one must
+ * be obviously changed.
+ */
+ if (off1 == lim1) {
+ char *rchg2 = dd2->rchg;
+ long *rindex2 = dd2->rindex;
+
+ for (; off2 < lim2; off2++)
+ rchg2[rindex2[off2]] = 1;
+ } else if (off2 == lim2) {
+ char *rchg1 = dd1->rchg;
+ long *rindex1 = dd1->rindex;
+
+ for (; off1 < lim1; off1++)
+ rchg1[rindex1[off1]] = 1;
+ } else {
+ xdpsplit_t spl;
+ spl.i1 = spl.i2 = 0;
+
+ /*
+ * Divide ...
+ */
+ if (xdl_split(ha1, off1, lim1, ha2, off2, lim2, kvdf, kvdb,
+ need_min, &spl, xenv) < 0) {
+
+ return -1;
+ }
+
+ /*
+ * ... et Impera.
+ */
+ if (xdl_recs_cmp(dd1, off1, spl.i1, dd2, off2, spl.i2,
+ kvdf, kvdb, spl.min_lo, xenv) < 0 ||
+ xdl_recs_cmp(dd1, spl.i1, lim1, dd2, spl.i2, lim2,
+ kvdf, kvdb, spl.min_hi, xenv) < 0) {
+
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+int xdl_do_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
+ xdfenv_t *xe) {
+ long ndiags;
+ long *kvd, *kvdf, *kvdb;
+ xdalgoenv_t xenv;
+ diffdata_t dd1, dd2;
+
+ if (XDF_DIFF_ALG(xpp->flags) == XDF_PATIENCE_DIFF)
+ return xdl_do_patience_diff(mf1, mf2, xpp, xe);
+
+ if (XDF_DIFF_ALG(xpp->flags) == XDF_HISTOGRAM_DIFF)
+ return xdl_do_histogram_diff(mf1, mf2, xpp, xe);
+
+ if (xdl_prepare_env(mf1, mf2, xpp, xe) < 0) {
+
+ return -1;
+ }
+
+ /*
+ * Allocate and setup K vectors to be used by the differential algorithm.
+ * One is to store the forward path and one to store the backward path.
+ */
+ ndiags = xe->xdf1.nreff + xe->xdf2.nreff + 3;
+ if (!(kvd = (long *) xdl_malloc((2 * ndiags + 2) * sizeof(long)))) {
+
+ xdl_free_env(xe);
+ return -1;
+ }
+ kvdf = kvd;
+ kvdb = kvdf + ndiags;
+ kvdf += xe->xdf2.nreff + 1;
+ kvdb += xe->xdf2.nreff + 1;
+
+ xenv.mxcost = xdl_bogosqrt(ndiags);
+ if (xenv.mxcost < XDL_MAX_COST_MIN)
+ xenv.mxcost = XDL_MAX_COST_MIN;
+ xenv.snake_cnt = XDL_SNAKE_CNT;
+ xenv.heur_min = XDL_HEUR_MIN_COST;
+
+ dd1.nrec = xe->xdf1.nreff;
+ dd1.ha = xe->xdf1.ha;
+ dd1.rchg = xe->xdf1.rchg;
+ dd1.rindex = xe->xdf1.rindex;
+ dd2.nrec = xe->xdf2.nreff;
+ dd2.ha = xe->xdf2.ha;
+ dd2.rchg = xe->xdf2.rchg;
+ dd2.rindex = xe->xdf2.rindex;
+
+ if (xdl_recs_cmp(&dd1, 0, dd1.nrec, &dd2, 0, dd2.nrec,
+ kvdf, kvdb, (xpp->flags & XDF_NEED_MINIMAL) != 0, &xenv) < 0) {
+
+ xdl_free(kvd);
+ xdl_free_env(xe);
+ return -1;
+ }
+
+ xdl_free(kvd);
+
+ return 0;
+}
+
+
+static xdchange_t *xdl_add_change(xdchange_t *xscr, long i1, long i2, long chg1, long chg2) {
+ xdchange_t *xch;
+
+ if (!(xch = (xdchange_t *) xdl_malloc(sizeof(xdchange_t))))
+ return NULL;
+
+ xch->next = xscr;
+ xch->i1 = i1;
+ xch->i2 = i2;
+ xch->chg1 = chg1;
+ xch->chg2 = chg2;
+ xch->ignore = 0;
+
+ return xch;
+}
+
+
+static int recs_match(xrecord_t *rec1, xrecord_t *rec2, long flags)
+{
+ return (rec1->ha == rec2->ha &&
+ xdl_recmatch(rec1->ptr, rec1->size,
+ rec2->ptr, rec2->size,
+ flags));
+}
+
+/*
+ * If a line is indented more than this, xget_indent() just returns this value.
+ * This avoids having to do absurd amounts of work for data that are not
+ * human-readable text, and also ensures that the output of xget_indent fits within
+ * an int.
+ */
+#define MAX_INDENT 200
+
+/*
+ * Return the amount of indentation of the specified line, treating TAB as 8
+ * columns. Return -1 if line is empty or contains only whitespace. Clamp the
+ * output value at MAX_INDENT.
+ */
+static int xget_indent(xrecord_t *rec)
+{
+ long i;
+ int ret = 0;
+
+ for (i = 0; i < rec->size; i++) {
+ char c = rec->ptr[i];
+
+ if (!XDL_ISSPACE(c))
+ return ret;
+ else if (c == ' ')
+ ret += 1;
+ else if (c == '\t')
+ ret += 8 - ret % 8;
+ /* ignore other whitespace characters */
+
+ if (ret >= MAX_INDENT)
+ return MAX_INDENT;
+ }
+
+ /* The line contains only whitespace. */
+ return -1;
+}
+
+/*
+ * If more than this number of consecutive blank rows are found, just return this
+ * value. This avoids requiring O(N^2) work for pathological cases, and also
+ * ensures that the output of score_split fits in an int.
+ */
+#define MAX_BLANKS 20
+
+/* Characteristics measured about a hypothetical split position. */
+struct split_measurement {
+ /*
+ * Is the split at the end of the file (aside from any blank lines)?
+ */
+ int end_of_file;
+
+ /*
+ * How much is the line immediately following the split indented (or -1 if
+ * the line is blank):
+ */
+ int indent;
+
+ /*
+ * How many consecutive lines above the split are blank?
+ */
+ int pre_blank;
+
+ /*
+ * How much is the nearest non-blank line above the split indented (or -1
+ * if there is no such line)?
+ */
+ int pre_indent;
+
+ /*
+ * How many lines after the line following the split are blank?
+ */
+ int post_blank;
+
+ /*
+ * How much is the nearest non-blank line after the line following the
+ * split indented (or -1 if there is no such line)?
+ */
+ int post_indent;
+};
+
+struct split_score {
+ /* The effective indent of this split (smaller is preferred). */
+ int effective_indent;
+
+ /* Penalty for this split (smaller is preferred). */
+ int penalty;
+};
+
+/*
+ * Fill m with information about a hypothetical split of xdf above line split.
+ */
+static void measure_split(const xdfile_t *xdf, long split,
+ struct split_measurement *m)
+{
+ long i;
+
+ if (split >= xdf->nrec) {
+ m->end_of_file = 1;
+ m->indent = -1;
+ } else {
+ m->end_of_file = 0;
+ m->indent = xget_indent(xdf->recs[split]);
+ }
+
+ m->pre_blank = 0;
+ m->pre_indent = -1;
+ for (i = split - 1; i >= 0; i--) {
+ m->pre_indent = xget_indent(xdf->recs[i]);
+ if (m->pre_indent != -1)
+ break;
+ m->pre_blank += 1;
+ if (m->pre_blank == MAX_BLANKS) {
+ m->pre_indent = 0;
+ break;
+ }
+ }
+
+ m->post_blank = 0;
+ m->post_indent = -1;
+ for (i = split + 1; i < xdf->nrec; i++) {
+ m->post_indent = xget_indent(xdf->recs[i]);
+ if (m->post_indent != -1)
+ break;
+ m->post_blank += 1;
+ if (m->post_blank == MAX_BLANKS) {
+ m->post_indent = 0;
+ break;
+ }
+ }
+}
+
+/*
+ * The empirically-determined weight factors used by score_split() below.
+ * Larger values means that the position is a less favorable place to split.
+ *
+ * Note that scores are only ever compared against each other, so multiplying
+ * all of these weight/penalty values by the same factor wouldn't change the
+ * heuristic's behavior. Still, we need to set that arbitrary scale *somehow*.
+ * In practice, these numbers are chosen to be large enough that they can be
+ * adjusted relative to each other with sufficient precision despite using
+ * integer math.
+ */
+
+/* Penalty if there are no non-blank lines before the split */
+#define START_OF_FILE_PENALTY 1
+
+/* Penalty if there are no non-blank lines after the split */
+#define END_OF_FILE_PENALTY 21
+
+/* Multiplier for the number of blank lines around the split */
+#define TOTAL_BLANK_WEIGHT (-30)
+
+/* Multiplier for the number of blank lines after the split */
+#define POST_BLANK_WEIGHT 6
+
+/*
+ * Penalties applied if the line is indented more than its predecessor
+ */
+#define RELATIVE_INDENT_PENALTY (-4)
+#define RELATIVE_INDENT_WITH_BLANK_PENALTY 10
+
+/*
+ * Penalties applied if the line is indented less than both its predecessor and
+ * its successor
+ */
+#define RELATIVE_OUTDENT_PENALTY 24
+#define RELATIVE_OUTDENT_WITH_BLANK_PENALTY 17
+
+/*
+ * Penalties applied if the line is indented less than its predecessor but not
+ * less than its successor
+ */
+#define RELATIVE_DEDENT_PENALTY 23
+#define RELATIVE_DEDENT_WITH_BLANK_PENALTY 17
+
+/*
+ * We only consider whether the sum of the effective indents for splits are
+ * less than (-1), equal to (0), or greater than (+1) each other. The resulting
+ * value is multiplied by the following weight and combined with the penalty to
+ * determine the better of two scores.
+ */
+#define INDENT_WEIGHT 60
+
+/*
+ * How far do we slide a hunk at most?
+ */
+#define INDENT_HEURISTIC_MAX_SLIDING 100
+
+/*
+ * Compute a badness score for the hypothetical split whose measurements are
+ * stored in m. The weight factors were determined empirically using the tools and
+ * corpus described in
+ *
+ * https://github.com/mhagger/diff-slider-tools
+ *
+ * Also see that project if you want to improve the weights based on, for example,
+ * a larger or more diverse corpus.
+ */
+static void score_add_split(const struct split_measurement *m, struct split_score *s)
+{
+ /*
+ * A place to accumulate penalty factors (positive makes this index more
+ * favored):
+ */
+ int post_blank, total_blank, indent, any_blanks;
+
+ if (m->pre_indent == -1 && m->pre_blank == 0)
+ s->penalty += START_OF_FILE_PENALTY;
+
+ if (m->end_of_file)
+ s->penalty += END_OF_FILE_PENALTY;
+
+ /*
+ * Set post_blank to the number of blank lines following the split,
+ * including the line immediately after the split:
+ */
+ post_blank = (m->indent == -1) ? 1 + m->post_blank : 0;
+ total_blank = m->pre_blank + post_blank;
+
+ /* Penalties based on nearby blank lines: */
+ s->penalty += TOTAL_BLANK_WEIGHT * total_blank;
+ s->penalty += POST_BLANK_WEIGHT * post_blank;
+
+ if (m->indent != -1)
+ indent = m->indent;
+ else
+ indent = m->post_indent;
+
+ any_blanks = (total_blank != 0);
+
+ /* Note that the effective indent is -1 at the end of the file: */
+ s->effective_indent += indent;
+
+ if (indent == -1) {
+ /* No additional adjustments needed. */
+ } else if (m->pre_indent == -1) {
+ /* No additional adjustments needed. */
+ } else if (indent > m->pre_indent) {
+ /*
+ * The line is indented more than its predecessor.
+ */
+ s->penalty += any_blanks ?
+ RELATIVE_INDENT_WITH_BLANK_PENALTY :
+ RELATIVE_INDENT_PENALTY;
+ } else if (indent == m->pre_indent) {
+ /*
+ * The line has the same indentation level as its predecessor.
+ * No additional adjustments needed.
+ */
+ } else {
+ /*
+ * The line is indented less than its predecessor. It could be
+ * the block terminator of the previous block, but it could
+ * also be the start of a new block (e.g., an "else" block, or
+ * maybe the previous block didn't have a block terminator).
+ * Try to distinguish those cases based on what comes next:
+ */
+ if (m->post_indent != -1 && m->post_indent > indent) {
+ /*
+ * The following line is indented more. So it is likely
+ * that this line is the start of a block.
+ */
+ s->penalty += any_blanks ?
+ RELATIVE_OUTDENT_WITH_BLANK_PENALTY :
+ RELATIVE_OUTDENT_PENALTY;
+ } else {
+ /*
+ * That was probably the end of a block.
+ */
+ s->penalty += any_blanks ?
+ RELATIVE_DEDENT_WITH_BLANK_PENALTY :
+ RELATIVE_DEDENT_PENALTY;
+ }
+ }
+}
+
+static int score_cmp(struct split_score *s1, struct split_score *s2)
+{
+ /* -1 if s1.effective_indent < s2->effective_indent, etc. */
+ int cmp_indents = ((s1->effective_indent > s2->effective_indent) -
+ (s1->effective_indent < s2->effective_indent));
+
+ return INDENT_WEIGHT * cmp_indents + (s1->penalty - s2->penalty);
+}
+
+/*
+ * Represent a group of changed lines in an xdfile_t (i.e., a contiguous group
+ * of lines that was inserted or deleted from the corresponding version of the
+ * file). We consider there to be such a group at the beginning of the file, at
+ * the end of the file, and between any two unchanged lines, though most such
+ * groups will usually be empty.
+ *
+ * If the first line in a group is equal to the line following the group, then
+ * the group can be slid down. Similarly, if the last line in a group is equal
+ * to the line preceding the group, then the group can be slid up. See
+ * group_slide_down() and group_slide_up().
+ *
+ * Note that loops that are testing for changed lines in xdf->rchg do not need
+ * index bounding since the array is prepared with a zero at position -1 and N.
+ */
+struct xdlgroup {
+ /*
+ * The index of the first changed line in the group, or the index of
+ * the unchanged line above which the (empty) group is located.
+ */
+ long start;
+
+ /*
+ * The index of the first unchanged line after the group. For an empty
+ * group, end is equal to start.
+ */
+ long end;
+};
+
+/*
+ * Initialize g to point at the first group in xdf.
+ */
+static void group_init(xdfile_t *xdf, struct xdlgroup *g)
+{
+ g->start = g->end = 0;
+ while (xdf->rchg[g->end])
+ g->end++;
+}
+
+/*
+ * Move g to describe the next (possibly empty) group in xdf and return 0. If g
+ * is already at the end of the file, do nothing and return -1.
+ */
+static inline int group_next(xdfile_t *xdf, struct xdlgroup *g)
+{
+ if (g->end == xdf->nrec)
+ return -1;
+
+ g->start = g->end + 1;
+ for (g->end = g->start; xdf->rchg[g->end]; g->end++)
+ ;
+
+ return 0;
+}
+
+/*
+ * Move g to describe the previous (possibly empty) group in xdf and return 0.
+ * If g is already at the beginning of the file, do nothing and return -1.
+ */
+static inline int group_previous(xdfile_t *xdf, struct xdlgroup *g)
+{
+ if (g->start == 0)
+ return -1;
+
+ g->end = g->start - 1;
+ for (g->start = g->end; xdf->rchg[g->start - 1]; g->start--)
+ ;
+
+ return 0;
+}
+
+/*
+ * If g can be slid toward the end of the file, do so, and if it bumps into a
+ * following group, expand this group to include it. Return 0 on success or -1
+ * if g cannot be slid down.
+ */
+static int group_slide_down(xdfile_t *xdf, struct xdlgroup *g, long flags)
+{
+ if (g->end < xdf->nrec &&
+ recs_match(xdf->recs[g->start], xdf->recs[g->end], flags)) {
+ xdf->rchg[g->start++] = 0;
+ xdf->rchg[g->end++] = 1;
+
+ while (xdf->rchg[g->end])
+ g->end++;
+
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+/*
+ * If g can be slid toward the beginning of the file, do so, and if it bumps
+ * into a previous group, expand this group to include it. Return 0 on success
+ * or -1 if g cannot be slid up.
+ */
+static int group_slide_up(xdfile_t *xdf, struct xdlgroup *g, long flags)
+{
+ if (g->start > 0 &&
+ recs_match(xdf->recs[g->start - 1], xdf->recs[g->end - 1], flags)) {
+ xdf->rchg[--g->start] = 1;
+ xdf->rchg[--g->end] = 0;
+
+ while (xdf->rchg[g->start - 1])
+ g->start--;
+
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+static void xdl_bug(const char *msg)
+{
+ fprintf(stderr, "BUG: %s\n", msg);
+ exit(1);
+}
+
+/*
+ * Move back and forward change groups for a consistent and pretty diff output.
+ * This also helps in finding joinable change groups and reducing the diff
+ * size.
+ */
+int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) {
+ struct xdlgroup g, go;
+ long earliest_end, end_matching_other;
+ long groupsize;
+
+ group_init(xdf, &g);
+ group_init(xdfo, &go);
+
+ while (1) {
+ /* If the group is empty in the to-be-compacted file, skip it: */
+ if (g.end == g.start)
+ goto next;
+
+ /*
+ * Now shift the change up and then down as far as possible in
+ * each direction. If it bumps into any other changes, merge them.
+ */
+ do {
+ groupsize = g.end - g.start;
+
+ /*
+ * Keep track of the last "end" index that causes this
+ * group to align with a group of changed lines in the
+ * other file. -1 indicates that we haven't found such
+ * a match yet:
+ */
+ end_matching_other = -1;
+
+ /* Shift the group backward as much as possible: */
+ while (!group_slide_up(xdf, &g, flags))
+ if (group_previous(xdfo, &go))
+ xdl_bug("group sync broken sliding up");
+
+ /*
+ * This is this highest that this group can be shifted.
+ * Record its end index:
+ */
+ earliest_end = g.end;
+
+ if (go.end > go.start)
+ end_matching_other = g.end;
+
+ /* Now shift the group forward as far as possible: */
+ while (1) {
+ if (group_slide_down(xdf, &g, flags))
+ break;
+ if (group_next(xdfo, &go))
+ xdl_bug("group sync broken sliding down");
+
+ if (go.end > go.start)
+ end_matching_other = g.end;
+ }
+ } while (groupsize != g.end - g.start);
+
+ /*
+ * If the group can be shifted, then we can possibly use this
+ * freedom to produce a more intuitive diff.
+ *
+ * The group is currently shifted as far down as possible, so the
+ * heuristics below only have to handle upwards shifts.
+ */
+
+ if (g.end == earliest_end) {
+ /* no shifting was possible */
+ } else if (end_matching_other != -1) {
+ /*
+ * Move the possibly merged group of changes back to line
+ * up with the last group of changes from the other file
+ * that it can align with.
+ */
+ while (go.end == go.start) {
+ if (group_slide_up(xdf, &g, flags))
+ xdl_bug("match disappeared");
+ if (group_previous(xdfo, &go))
+ xdl_bug("group sync broken sliding to match");
+ }
+ } else if (flags & XDF_INDENT_HEURISTIC) {
+ /*
+ * Indent heuristic: a group of pure add/delete lines
+ * implies two splits, one between the end of the "before"
+ * context and the start of the group, and another between
+ * the end of the group and the beginning of the "after"
+ * context. Some splits are aesthetically better and some
+ * are worse. We compute a badness "score" for each split,
+ * and add the scores for the two splits to define a
+ * "score" for each position that the group can be shifted
+ * to. Then we pick the shift with the lowest score.
+ */
+ long shift, best_shift = -1;
+ struct split_score best_score;
+
+ shift = earliest_end;
+ if (g.end - groupsize - 1 > shift)
+ shift = g.end - groupsize - 1;
+ if (g.end - INDENT_HEURISTIC_MAX_SLIDING > shift)
+ shift = g.end - INDENT_HEURISTIC_MAX_SLIDING;
+ for (; shift <= g.end; shift++) {
+ struct split_measurement m;
+ struct split_score score = {0, 0};
+
+ measure_split(xdf, shift, &m);
+ score_add_split(&m, &score);
+ measure_split(xdf, shift - groupsize, &m);
+ score_add_split(&m, &score);
+ if (best_shift == -1 ||
+ score_cmp(&score, &best_score) <= 0) {
+ best_score.effective_indent = score.effective_indent;
+ best_score.penalty = score.penalty;
+ best_shift = shift;
+ }
+ }
+
+ while (g.end > best_shift) {
+ if (group_slide_up(xdf, &g, flags))
+ xdl_bug("best shift unreached");
+ if (group_previous(xdfo, &go))
+ xdl_bug("group sync broken sliding to blank line");
+ }
+ }
+
+ next:
+ /* Move past the just-processed group: */
+ if (group_next(xdf, &g))
+ break;
+ if (group_next(xdfo, &go))
+ xdl_bug("group sync broken moving to next group");
+ }
+
+ if (!group_next(xdfo, &go))
+ xdl_bug("group sync broken at end of file");
+
+ return 0;
+}
+
+
+int xdl_build_script(xdfenv_t *xe, xdchange_t **xscr) {
+ xdchange_t *cscr = NULL, *xch;
+ char *rchg1 = xe->xdf1.rchg, *rchg2 = xe->xdf2.rchg;
+ long i1, i2, l1, l2;
+
+ /*
+ * Trivial. Collects "groups" of changes and creates an edit script.
+ */
+ for (i1 = xe->xdf1.nrec, i2 = xe->xdf2.nrec; i1 >= 0 || i2 >= 0; i1--, i2--)
+ if (rchg1[i1 - 1] || rchg2[i2 - 1]) {
+ for (l1 = i1; rchg1[i1 - 1]; i1--);
+ for (l2 = i2; rchg2[i2 - 1]; i2--);
+
+ if (!(xch = xdl_add_change(cscr, i1, i2, l1 - i1, l2 - i2))) {
+ xdl_free_script(cscr);
+ return -1;
+ }
+ cscr = xch;
+ }
+
+ *xscr = cscr;
+
+ return 0;
+}
+
+
+void xdl_free_script(xdchange_t *xscr) {
+ xdchange_t *xch;
+
+ while ((xch = xscr) != NULL) {
+ xscr = xscr->next;
+ xdl_free(xch);
+ }
+}
+
+static int xdl_call_hunk_func(xdfenv_t *xe UNUSED, xdchange_t *xscr, xdemitcb_t *ecb,
+ xdemitconf_t const *xecfg)
+{
+ xdchange_t *xch, *xche;
+
+ for (xch = xscr; xch; xch = xche->next) {
+ xche = xdl_get_hunk(&xch, xecfg);
+ if (!xch)
+ break;
+ if (xecfg->hunk_func(xch->i1, xche->i1 + xche->chg1 - xch->i1,
+ xch->i2, xche->i2 + xche->chg2 - xch->i2,
+ ecb->priv) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+static void xdl_mark_ignorable(xdchange_t *xscr, xdfenv_t *xe, long flags)
+{
+ xdchange_t *xch;
+
+ for (xch = xscr; xch; xch = xch->next) {
+ int ignore = 1;
+ xrecord_t **rec;
+ long i;
+
+ rec = &xe->xdf1.recs[xch->i1];
+ for (i = 0; i < xch->chg1 && ignore; i++)
+ ignore = xdl_blankline(rec[i]->ptr, rec[i]->size, flags);
+
+ rec = &xe->xdf2.recs[xch->i2];
+ for (i = 0; i < xch->chg2 && ignore; i++)
+ ignore = xdl_blankline(rec[i]->ptr, rec[i]->size, flags);
+
+ xch->ignore = ignore;
+ }
+}
+
+int xdl_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
+ xdemitconf_t const *xecfg, xdemitcb_t *ecb) {
+ xdchange_t *xscr;
+ xdfenv_t xe;
+ emit_func_t ef = xecfg->hunk_func ? xdl_call_hunk_func : xdl_emit_diff;
+
+ if (xdl_do_diff(mf1, mf2, xpp, &xe) < 0) {
+
+ return -1;
+ }
+ if (xdl_change_compact(&xe.xdf1, &xe.xdf2, xpp->flags) < 0 ||
+ xdl_change_compact(&xe.xdf2, &xe.xdf1, xpp->flags) < 0 ||
+ xdl_build_script(&xe, &xscr) < 0) {
+
+ xdl_free_env(&xe);
+ return -1;
+ }
+ if (xscr) {
+ if (xpp->flags & XDF_IGNORE_BLANK_LINES)
+ xdl_mark_ignorable(xscr, &xe, xpp->flags);
+
+ if (ef(&xe, xscr, ecb, xecfg) < 0) {
+
+ xdl_free_script(xscr);
+ xdl_free_env(&xe);
+ return -1;
+ }
+ xdl_free_script(xscr);
+ }
+ xdl_free_env(&xe);
+
+ return 0;
+}
diff --git a/src/nvim/xdiff/xdiffi.h b/src/nvim/xdiff/xdiffi.h
new file mode 100644
index 0000000000..8f1c7c8b04
--- /dev/null
+++ b/src/nvim/xdiff/xdiffi.h
@@ -0,0 +1,64 @@
+/*
+ * LibXDiff by Davide Libenzi ( File Differential Library )
+ * Copyright (C) 2003 Davide Libenzi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+#if !defined(XDIFFI_H)
+#define XDIFFI_H
+
+
+typedef struct s_diffdata {
+ long nrec;
+ unsigned long const *ha;
+ long *rindex;
+ char *rchg;
+} diffdata_t;
+
+typedef struct s_xdalgoenv {
+ long mxcost;
+ long snake_cnt;
+ long heur_min;
+} xdalgoenv_t;
+
+typedef struct s_xdchange {
+ struct s_xdchange *next;
+ long i1, i2;
+ long chg1, chg2;
+ int ignore;
+} xdchange_t;
+
+
+
+int xdl_recs_cmp(diffdata_t *dd1, long off1, long lim1,
+ diffdata_t *dd2, long off2, long lim2,
+ long *kvdf, long *kvdb, int need_min, xdalgoenv_t *xenv);
+int xdl_do_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
+ xdfenv_t *xe);
+int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags);
+int xdl_build_script(xdfenv_t *xe, xdchange_t **xscr);
+void xdl_free_script(xdchange_t *xscr);
+int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
+ xdemitconf_t const *xecfg);
+int xdl_do_patience_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
+ xdfenv_t *env);
+int xdl_do_histogram_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
+ xdfenv_t *env);
+
+#endif /* #if !defined(XDIFFI_H) */
diff --git a/src/nvim/xdiff/xemit.c b/src/nvim/xdiff/xemit.c
new file mode 100644
index 0000000000..d8a6f1ed38
--- /dev/null
+++ b/src/nvim/xdiff/xemit.c
@@ -0,0 +1,332 @@
+/*
+ * LibXDiff by Davide Libenzi ( File Differential Library )
+ * Copyright (C) 2003 Davide Libenzi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+#include "xinclude.h"
+
+static long xdl_get_rec(xdfile_t *xdf, long ri, char const **rec) {
+
+ *rec = xdf->recs[ri]->ptr;
+
+ return xdf->recs[ri]->size;
+}
+
+
+static int xdl_emit_record(xdfile_t *xdf, long ri, char const *pre, xdemitcb_t *ecb) {
+ long size, psize = (long)strlen(pre);
+ char const *rec;
+
+ size = xdl_get_rec(xdf, ri, &rec);
+ if (xdl_emit_diffrec(rec, size, pre, psize, ecb) < 0) {
+
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Starting at the passed change atom, find the latest change atom to be included
+ * inside the differential hunk according to the specified configuration.
+ * Also advance xscr if the first changes must be discarded.
+ */
+xdchange_t *xdl_get_hunk(xdchange_t **xscr, xdemitconf_t const *xecfg)
+{
+ xdchange_t *xch, *xchp, *lxch;
+ long max_common = 2 * xecfg->ctxlen + xecfg->interhunkctxlen;
+ long max_ignorable = xecfg->ctxlen;
+ unsigned long ignored = 0; /* number of ignored blank lines */
+
+ /* remove ignorable changes that are too far before other changes */
+ for (xchp = *xscr; xchp && xchp->ignore; xchp = xchp->next) {
+ xch = xchp->next;
+
+ if (xch == NULL ||
+ xch->i1 - (xchp->i1 + xchp->chg1) >= max_ignorable)
+ *xscr = xch;
+ }
+
+ if (*xscr == NULL)
+ return NULL;
+
+ lxch = *xscr;
+
+ for (xchp = *xscr, xch = xchp->next; xch; xchp = xch, xch = xch->next) {
+ long distance = xch->i1 - (xchp->i1 + xchp->chg1);
+ if (distance > max_common)
+ break;
+
+ if (distance < max_ignorable && (!xch->ignore || lxch == xchp)) {
+ lxch = xch;
+ ignored = 0;
+ } else if (distance < max_ignorable && xch->ignore) {
+ ignored += xch->chg2;
+ } else if (lxch != xchp &&
+ xch->i1 + (long)ignored - (lxch->i1 + lxch->chg1) > max_common) {
+ break;
+ } else if (!xch->ignore) {
+ lxch = xch;
+ ignored = 0;
+ } else {
+ ignored += xch->chg2;
+ }
+ }
+
+ return lxch;
+}
+
+
+#if 0
+static long def_ff(const char *rec, long len, char *buf, long sz, void *priv UNUSED)
+{
+ if (len > 0 &&
+ (isalpha((unsigned char)*rec) || /* identifier? */
+ *rec == '_' || /* also identifier? */
+ *rec == '$')) { /* identifiers from VMS and other esoterico */
+ if (len > sz)
+ len = sz;
+ while (0 < len && isspace((unsigned char)rec[len - 1]))
+ len--;
+ memcpy(buf, rec, len);
+ return len;
+ }
+ return -1;
+}
+#endif
+
+#if 0
+static long match_func_rec(xdfile_t *xdf, xdemitconf_t const *xecfg, long ri,
+ char *buf, long sz)
+{
+ const char *rec;
+ long len = xdl_get_rec(xdf, ri, &rec);
+ if (!xecfg->find_func)
+ return def_ff(rec, len, buf, sz, xecfg->find_func_priv);
+ return xecfg->find_func(rec, len, buf, sz, xecfg->find_func_priv);
+}
+#endif
+
+#if 0
+static int is_func_rec(xdfile_t *xdf, xdemitconf_t const *xecfg, long ri)
+{
+ char dummy[1];
+ return match_func_rec(xdf, xecfg, ri, dummy, sizeof(dummy)) >= 0;
+}
+#endif
+
+struct func_line {
+ long len;
+ char buf[80];
+};
+
+#if 0
+static long get_func_line(xdfenv_t *xe, xdemitconf_t const *xecfg,
+ struct func_line *func_line, long start, long limit)
+{
+ long l, size, step = (start > limit) ? -1 : 1;
+ char *buf, dummy[1];
+
+ buf = func_line ? func_line->buf : dummy;
+ size = func_line ? sizeof(func_line->buf) : sizeof(dummy);
+
+ for (l = start; l != limit && 0 <= l && l < xe->xdf1.nrec; l += step) {
+ long len = match_func_rec(&xe->xdf1, xecfg, l, buf, size);
+ if (len >= 0) {
+ if (func_line)
+ func_line->len = len;
+ return l;
+ }
+ }
+ return -1;
+}
+#endif
+
+#if 0
+static int is_empty_rec(xdfile_t *xdf, long ri)
+{
+ const char *rec;
+ long len = xdl_get_rec(xdf, ri, &rec);
+
+ while (len > 0 && XDL_ISSPACE(*rec)) {
+ rec++;
+ len--;
+ }
+ return !len;
+}
+#endif
+
+int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
+ xdemitconf_t const *xecfg) {
+ long s1, s2, e1, e2, lctx;
+ xdchange_t *xch, *xche;
+#if 0
+ long funclineprev = -1;
+#endif
+ struct func_line func_line;
+
+ func_line.len = 0;
+
+ for (xch = xscr; xch; xch = xche->next) {
+ xche = xdl_get_hunk(&xch, xecfg);
+ if (!xch)
+ break;
+
+ s1 = XDL_MAX(xch->i1 - xecfg->ctxlen, 0);
+ s2 = XDL_MAX(xch->i2 - xecfg->ctxlen, 0);
+
+#if 0
+ if (xecfg->flags & XDL_EMIT_FUNCCONTEXT) {
+ long fs1, i1 = xch->i1;
+
+ /* Appended chunk? */
+ if (i1 >= xe->xdf1.nrec) {
+ long i2 = xch->i2;
+
+ /*
+ * We don't need additional context if
+ * a whole function was added.
+ */
+ while (i2 < xe->xdf2.nrec) {
+ if (is_func_rec(&xe->xdf2, xecfg, i2))
+ goto post_context_calculation;
+ i2++;
+ }
+
+ /*
+ * Otherwise get more context from the
+ * pre-image.
+ */
+ i1 = xe->xdf1.nrec - 1;
+ }
+
+ fs1 = get_func_line(xe, xecfg, NULL, i1, -1);
+ while (fs1 > 0 && !is_empty_rec(&xe->xdf1, fs1 - 1) &&
+ !is_func_rec(&xe->xdf1, xecfg, fs1 - 1))
+ fs1--;
+ if (fs1 < 0)
+ fs1 = 0;
+ if (fs1 < s1) {
+ s2 -= s1 - fs1;
+ s1 = fs1;
+ }
+ }
+
+ post_context_calculation:
+#endif
+ lctx = xecfg->ctxlen;
+ lctx = XDL_MIN(lctx, xe->xdf1.nrec - (xche->i1 + xche->chg1));
+ lctx = XDL_MIN(lctx, xe->xdf2.nrec - (xche->i2 + xche->chg2));
+
+ e1 = xche->i1 + xche->chg1 + lctx;
+ e2 = xche->i2 + xche->chg2 + lctx;
+
+#if 0
+ if (xecfg->flags & XDL_EMIT_FUNCCONTEXT) {
+ long fe1 = get_func_line(xe, xecfg, NULL,
+ xche->i1 + xche->chg1,
+ xe->xdf1.nrec);
+ while (fe1 > 0 && is_empty_rec(&xe->xdf1, fe1 - 1))
+ fe1--;
+ if (fe1 < 0)
+ fe1 = xe->xdf1.nrec;
+ if (fe1 > e1) {
+ e2 += fe1 - e1;
+ e1 = fe1;
+ }
+
+ /*
+ * Overlap with next change? Then include it
+ * in the current hunk and start over to find
+ * its new end.
+ */
+ if (xche->next) {
+ long l = XDL_MIN(xche->next->i1,
+ xe->xdf1.nrec - 1);
+ if (l - xecfg->ctxlen <= e1 ||
+ get_func_line(xe, xecfg, NULL, l, e1) < 0) {
+ xche = xche->next;
+ goto post_context_calculation;
+ }
+ }
+ }
+#endif
+
+ /*
+ * Emit current hunk header.
+ */
+
+#if 0
+ if (xecfg->flags & XDL_EMIT_FUNCNAMES) {
+ get_func_line(xe, xecfg, &func_line,
+ s1 - 1, funclineprev);
+ funclineprev = s1 - 1;
+ }
+#endif
+ if (xdl_emit_hunk_hdr(s1 + 1, e1 - s1, s2 + 1, e2 - s2,
+ func_line.buf, func_line.len, ecb) < 0)
+ return -1;
+
+ /*
+ * Emit pre-context.
+ */
+ for (; s2 < xch->i2; s2++)
+ if (xdl_emit_record(&xe->xdf2, s2, " ", ecb) < 0)
+ return -1;
+
+ for (s1 = xch->i1, s2 = xch->i2;; xch = xch->next) {
+ /*
+ * Merge previous with current change atom.
+ */
+ for (; s1 < xch->i1 && s2 < xch->i2; s1++, s2++)
+ if (xdl_emit_record(&xe->xdf2, s2, " ", ecb) < 0)
+ return -1;
+
+ /*
+ * Removes lines from the first file.
+ */
+ for (s1 = xch->i1; s1 < xch->i1 + xch->chg1; s1++)
+ if (xdl_emit_record(&xe->xdf1, s1, "-", ecb) < 0)
+ return -1;
+
+ /*
+ * Adds lines from the second file.
+ */
+ for (s2 = xch->i2; s2 < xch->i2 + xch->chg2; s2++)
+ if (xdl_emit_record(&xe->xdf2, s2, "+", ecb) < 0)
+ return -1;
+
+ if (xch == xche)
+ break;
+ s1 = xch->i1 + xch->chg1;
+ s2 = xch->i2 + xch->chg2;
+ }
+
+ /*
+ * Emit post-context.
+ */
+ for (s2 = xche->i2 + xche->chg2; s2 < e2; s2++)
+ if (xdl_emit_record(&xe->xdf2, s2, " ", ecb) < 0)
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/nvim/xdiff/xemit.h b/src/nvim/xdiff/xemit.h
new file mode 100644
index 0000000000..1b9887e670
--- /dev/null
+++ b/src/nvim/xdiff/xemit.h
@@ -0,0 +1,36 @@
+/*
+ * LibXDiff by Davide Libenzi ( File Differential Library )
+ * Copyright (C) 2003 Davide Libenzi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+#if !defined(XEMIT_H)
+#define XEMIT_H
+
+
+typedef int (*emit_func_t)(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
+ xdemitconf_t const *xecfg);
+
+xdchange_t *xdl_get_hunk(xdchange_t **xscr, xdemitconf_t const *xecfg);
+int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
+ xdemitconf_t const *xecfg);
+
+
+
+#endif /* #if !defined(XEMIT_H) */
diff --git a/src/nvim/xdiff/xhistogram.c b/src/nvim/xdiff/xhistogram.c
new file mode 100644
index 0000000000..3fb8974dd4
--- /dev/null
+++ b/src/nvim/xdiff/xhistogram.c
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2010, Google Inc.
+ * and other copyright owners as documented in JGit's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "xinclude.h"
+#include "xtypes.h"
+#include "xdiff.h"
+
+#define MAX_PTR INT_MAX
+#define MAX_CNT INT_MAX
+
+#define LINE_END(n) (line##n + count##n - 1)
+#define LINE_END_PTR(n) (*line##n + *count##n - 1)
+
+struct histindex {
+ struct record {
+ unsigned int ptr, cnt;
+ struct record *next;
+ } **records, /* an occurrence */
+ **line_map; /* map of line to record chain */
+ chastore_t rcha;
+ unsigned int *next_ptrs;
+ unsigned int table_bits,
+ records_size,
+ line_map_size;
+
+ unsigned int max_chain_length,
+ key_shift,
+ ptr_shift;
+
+ unsigned int cnt,
+ has_common;
+
+ xdfenv_t *env;
+ xpparam_t const *xpp;
+};
+
+struct region {
+ unsigned int begin1, end1;
+ unsigned int begin2, end2;
+};
+
+#define LINE_MAP(i, a) (i->line_map[(a) - i->ptr_shift])
+
+#define NEXT_PTR(index, ptr) \
+ (index->next_ptrs[(ptr) - index->ptr_shift])
+
+#define CNT(index, ptr) \
+ ((LINE_MAP(index, ptr))->cnt)
+
+#define REC(env, s, l) \
+ (env->xdf##s.recs[l - 1])
+
+static int cmp_recs(xpparam_t const *xpp,
+ xrecord_t *r1, xrecord_t *r2)
+{
+ return r1->ha == r2->ha &&
+ xdl_recmatch(r1->ptr, r1->size, r2->ptr, r2->size,
+ xpp->flags);
+}
+
+#define CMP_ENV(xpp, env, s1, l1, s2, l2) \
+ (cmp_recs(xpp, REC(env, s1, l1), REC(env, s2, l2)))
+
+#define CMP(i, s1, l1, s2, l2) \
+ (cmp_recs(i->xpp, REC(i->env, s1, l1), REC(i->env, s2, l2)))
+
+#define TABLE_HASH(index, side, line) \
+ XDL_HASHLONG((REC(index->env, side, line))->ha, index->table_bits)
+
+static int scanA(struct histindex *index, int line1, int count1)
+{
+ int ptr, tbl_idx;
+ unsigned int chain_len;
+ struct record **rec_chain, *rec;
+
+ for (ptr = LINE_END(1); line1 <= ptr; ptr--) {
+ tbl_idx = TABLE_HASH(index, 1, ptr);
+ rec_chain = index->records + tbl_idx;
+ rec = *rec_chain;
+
+ chain_len = 0;
+ while (rec) {
+ if (CMP(index, 1, rec->ptr, 1, ptr)) {
+ /*
+ * ptr is identical to another element. Insert
+ * it onto the front of the existing element
+ * chain.
+ */
+ NEXT_PTR(index, ptr) = rec->ptr;
+ rec->ptr = ptr;
+ /* cap rec->cnt at MAX_CNT */
+ rec->cnt = XDL_MIN(MAX_CNT, rec->cnt + 1);
+ LINE_MAP(index, ptr) = rec;
+ goto continue_scan;
+ }
+
+ rec = rec->next;
+ chain_len++;
+ }
+
+ if (chain_len == index->max_chain_length)
+ return -1;
+
+ /*
+ * This is the first time we have ever seen this particular
+ * element in the sequence. Construct a new chain for it.
+ */
+ if (!(rec = xdl_cha_alloc(&index->rcha)))
+ return -1;
+ rec->ptr = ptr;
+ rec->cnt = 1;
+ rec->next = *rec_chain;
+ *rec_chain = rec;
+ LINE_MAP(index, ptr) = rec;
+
+continue_scan:
+ ; /* no op */
+ }
+
+ return 0;
+}
+
+static int try_lcs(struct histindex *index, struct region *lcs, int b_ptr,
+ int line1, int count1, int line2, int count2)
+{
+ unsigned int b_next = b_ptr + 1;
+ struct record *rec = index->records[TABLE_HASH(index, 2, b_ptr)];
+ unsigned int as, ae, bs, be, np, rc;
+ int should_break;
+
+ for (; rec; rec = rec->next) {
+ if (rec->cnt > index->cnt) {
+ if (!index->has_common)
+ index->has_common = CMP(index, 1, rec->ptr, 2, b_ptr);
+ continue;
+ }
+
+ as = rec->ptr;
+ if (!CMP(index, 1, as, 2, b_ptr))
+ continue;
+
+ index->has_common = 1;
+ for (;;) {
+ should_break = 0;
+ np = NEXT_PTR(index, as);
+ bs = b_ptr;
+ ae = as;
+ be = bs;
+ rc = rec->cnt;
+
+ while (line1 < (int)as && line2 < (int)bs
+ && CMP(index, 1, as - 1, 2, bs - 1)) {
+ as--;
+ bs--;
+ if (1 < rc)
+ rc = XDL_MIN(rc, CNT(index, as));
+ }
+ while ((int)ae < LINE_END(1) && (int)be < LINE_END(2)
+ && CMP(index, 1, ae + 1, 2, be + 1)) {
+ ae++;
+ be++;
+ if (1 < rc)
+ rc = XDL_MIN(rc, CNT(index, ae));
+ }
+
+ if (b_next <= be)
+ b_next = be + 1;
+ if (lcs->end1 - lcs->begin1 < ae - as || rc < index->cnt) {
+ lcs->begin1 = as;
+ lcs->begin2 = bs;
+ lcs->end1 = ae;
+ lcs->end2 = be;
+ index->cnt = rc;
+ }
+
+ if (np == 0)
+ break;
+
+ while (np <= ae) {
+ np = NEXT_PTR(index, np);
+ if (np == 0) {
+ should_break = 1;
+ break;
+ }
+ }
+
+ if (should_break)
+ break;
+
+ as = np;
+ }
+ }
+ return b_next;
+}
+
+static int fall_back_to_classic_diff(xpparam_t const *xpp, xdfenv_t *env,
+ int line1, int count1, int line2, int count2)
+{
+ xpparam_t xpparam;
+ xpparam.flags = xpp->flags & ~XDF_DIFF_ALGORITHM_MASK;
+
+ return xdl_fall_back_diff(env, &xpparam,
+ line1, count1, line2, count2);
+}
+
+static inline void free_index(struct histindex *index)
+{
+ xdl_free(index->records);
+ xdl_free(index->line_map);
+ xdl_free(index->next_ptrs);
+ xdl_cha_free(&index->rcha);
+}
+
+static int find_lcs(xpparam_t const *xpp, xdfenv_t *env,
+ struct region *lcs,
+ int line1, int count1, int line2, int count2)
+{
+ int b_ptr;
+ int sz, ret = -1;
+ struct histindex index;
+
+ memset(&index, 0, sizeof(index));
+
+ index.env = env;
+ index.xpp = xpp;
+
+ index.records = NULL;
+ index.line_map = NULL;
+ /* in case of early xdl_cha_free() */
+ index.rcha.head = NULL;
+
+ index.table_bits = xdl_hashbits(count1);
+ sz = index.records_size = 1 << index.table_bits;
+ sz *= sizeof(struct record *);
+ if (!(index.records = (struct record **) xdl_malloc(sz)))
+ goto cleanup;
+ memset(index.records, 0, sz);
+
+ sz = index.line_map_size = count1;
+ sz *= sizeof(struct record *);
+ if (!(index.line_map = (struct record **) xdl_malloc(sz)))
+ goto cleanup;
+ memset(index.line_map, 0, sz);
+
+ sz = index.line_map_size;
+ sz *= sizeof(unsigned int);
+ if (!(index.next_ptrs = (unsigned int *) xdl_malloc(sz)))
+ goto cleanup;
+ memset(index.next_ptrs, 0, sz);
+
+ /* lines / 4 + 1 comes from xprepare.c:xdl_prepare_ctx() */
+ if (xdl_cha_init(&index.rcha, sizeof(struct record), count1 / 4 + 1) < 0)
+ goto cleanup;
+
+ index.ptr_shift = line1;
+ index.max_chain_length = 64;
+
+ if (scanA(&index, line1, count1))
+ goto cleanup;
+
+ index.cnt = index.max_chain_length + 1;
+
+ for (b_ptr = line2; b_ptr <= LINE_END(2); )
+ b_ptr = try_lcs(&index, lcs, b_ptr, line1, count1, line2, count2);
+
+ if (index.has_common && index.max_chain_length < index.cnt)
+ ret = 1;
+ else
+ ret = 0;
+
+cleanup:
+ free_index(&index);
+ return ret;
+}
+
+static int histogram_diff(xpparam_t const *xpp, xdfenv_t *env,
+ int line1, int count1, int line2, int count2)
+{
+ struct region lcs;
+ int lcs_found;
+ int result;
+redo:
+ result = -1;
+
+ if (count1 <= 0 && count2 <= 0)
+ return 0;
+
+ if (LINE_END(1) >= MAX_PTR)
+ return -1;
+
+ if (!count1) {
+ while(count2--)
+ env->xdf2.rchg[line2++ - 1] = 1;
+ return 0;
+ } else if (!count2) {
+ while(count1--)
+ env->xdf1.rchg[line1++ - 1] = 1;
+ return 0;
+ }
+
+ memset(&lcs, 0, sizeof(lcs));
+ lcs_found = find_lcs(xpp, env, &lcs, line1, count1, line2, count2);
+ if (lcs_found < 0)
+ goto out;
+ else if (lcs_found)
+ result = fall_back_to_classic_diff(xpp, env, line1, count1, line2, count2);
+ else {
+ if (lcs.begin1 == 0 && lcs.begin2 == 0) {
+ while (count1--)
+ env->xdf1.rchg[line1++ - 1] = 1;
+ while (count2--)
+ env->xdf2.rchg[line2++ - 1] = 1;
+ result = 0;
+ } else {
+ result = histogram_diff(xpp, env,
+ line1, lcs.begin1 - line1,
+ line2, lcs.begin2 - line2);
+ if (result)
+ goto out;
+ /*
+ * result = histogram_diff(xpp, env,
+ * lcs.end1 + 1, LINE_END(1) - lcs.end1,
+ * lcs.end2 + 1, LINE_END(2) - lcs.end2);
+ * but let's optimize tail recursion ourself:
+ */
+ count1 = LINE_END(1) - lcs.end1;
+ line1 = lcs.end1 + 1;
+ count2 = LINE_END(2) - lcs.end2;
+ line2 = lcs.end2 + 1;
+ goto redo;
+ }
+ }
+out:
+ return result;
+}
+
+int xdl_do_histogram_diff(mmfile_t *file1, mmfile_t *file2,
+ xpparam_t const *xpp, xdfenv_t *env)
+{
+ if (xdl_prepare_env(file1, file2, xpp, env) < 0)
+ return -1;
+
+ return histogram_diff(xpp, env,
+ env->xdf1.dstart + 1, env->xdf1.dend - env->xdf1.dstart + 1,
+ env->xdf2.dstart + 1, env->xdf2.dend - env->xdf2.dstart + 1);
+}
diff --git a/src/nvim/xdiff/xinclude.h b/src/nvim/xdiff/xinclude.h
new file mode 100644
index 0000000000..46b8608314
--- /dev/null
+++ b/src/nvim/xdiff/xinclude.h
@@ -0,0 +1,61 @@
+/*
+ * LibXDiff by Davide Libenzi ( File Differential Library )
+ * Copyright (C) 2003 Davide Libenzi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+/* defines HAVE_ATTRIBUTE_UNUSED */
+#ifdef HAVE_CONFIG_H
+# include "../auto/config.h"
+#endif
+
+/* Mark unused function arguments with UNUSED, so that gcc -Wunused-parameter
+ * can be used to check for mistakes. */
+#ifdef HAVE_ATTRIBUTE_UNUSED
+# define UNUSED __attribute__((unused))
+#else
+# define UNUSED
+#endif
+
+#if defined(_MSC_VER)
+# define inline __inline
+#endif
+
+#if !defined(XINCLUDE_H)
+#define XINCLUDE_H
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#if !defined(_WIN32)
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <limits.h>
+
+#include "xmacros.h"
+#include "xdiff.h"
+#include "xtypes.h"
+#include "xutils.h"
+#include "xprepare.h"
+#include "xdiffi.h"
+#include "xemit.h"
+
+
+#endif /* #if !defined(XINCLUDE_H) */
diff --git a/src/nvim/xdiff/xmacros.h b/src/nvim/xdiff/xmacros.h
new file mode 100644
index 0000000000..2809a28ca9
--- /dev/null
+++ b/src/nvim/xdiff/xmacros.h
@@ -0,0 +1,54 @@
+/*
+ * LibXDiff by Davide Libenzi ( File Differential Library )
+ * Copyright (C) 2003 Davide Libenzi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+#if !defined(XMACROS_H)
+#define XMACROS_H
+
+
+
+
+#define XDL_MIN(a, b) ((a) < (b) ? (a): (b))
+#define XDL_MAX(a, b) ((a) > (b) ? (a): (b))
+#define XDL_ABS(v) ((v) >= 0 ? (v): -(v))
+#define XDL_ISDIGIT(c) ((c) >= '0' && (c) <= '9')
+#define XDL_ISSPACE(c) (isspace((unsigned char)(c)))
+#define XDL_ADDBITS(v,b) ((v) + ((v) >> (b)))
+#define XDL_MASKBITS(b) ((1UL << (b)) - 1)
+#define XDL_HASHLONG(v,b) (XDL_ADDBITS((unsigned long)(v), b) & XDL_MASKBITS(b))
+#define XDL_PTRFREE(p) do { if (p) { xdl_free(p); (p) = NULL; } } while (0)
+#define XDL_LE32_PUT(p, v) \
+do { \
+ unsigned char *__p = (unsigned char *) (p); \
+ *__p++ = (unsigned char) (v); \
+ *__p++ = (unsigned char) ((v) >> 8); \
+ *__p++ = (unsigned char) ((v) >> 16); \
+ *__p = (unsigned char) ((v) >> 24); \
+} while (0)
+#define XDL_LE32_GET(p, v) \
+do { \
+ unsigned char const *__p = (unsigned char const *) (p); \
+ (v) = (unsigned long) __p[0] | ((unsigned long) __p[1]) << 8 | \
+ ((unsigned long) __p[2]) << 16 | ((unsigned long) __p[3]) << 24; \
+} while (0)
+
+
+#endif /* #if !defined(XMACROS_H) */
diff --git a/src/nvim/xdiff/xpatience.c b/src/nvim/xdiff/xpatience.c
new file mode 100644
index 0000000000..2c65aac386
--- /dev/null
+++ b/src/nvim/xdiff/xpatience.c
@@ -0,0 +1,393 @@
+/*
+ * LibXDiff by Davide Libenzi ( File Differential Library )
+ * Copyright (C) 2003-2016 Davide Libenzi, Johannes E. Schindelin
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+#include "xinclude.h"
+#include "xtypes.h"
+#include "xdiff.h"
+
+/*
+ * The basic idea of patience diff is to find lines that are unique in
+ * both files. These are intuitively the ones that we want to see as
+ * common lines.
+ *
+ * The maximal ordered sequence of such line pairs (where ordered means
+ * that the order in the sequence agrees with the order of the lines in
+ * both files) naturally defines an initial set of common lines.
+ *
+ * Now, the algorithm tries to extend the set of common lines by growing
+ * the line ranges where the files have identical lines.
+ *
+ * Between those common lines, the patience diff algorithm is applied
+ * recursively, until no unique line pairs can be found; these line ranges
+ * are handled by the well-known Myers algorithm.
+ */
+
+#define NON_UNIQUE ULONG_MAX
+
+/*
+ * This is a hash mapping from line hash to line numbers in the first and
+ * second file.
+ */
+struct hashmap {
+ int nr, alloc;
+ struct entry {
+ unsigned long hash;
+ /*
+ * 0 = unused entry, 1 = first line, 2 = second, etc.
+ * line2 is NON_UNIQUE if the line is not unique
+ * in either the first or the second file.
+ */
+ unsigned long line1, line2;
+ /*
+ * "next" & "previous" are used for the longest common
+ * sequence;
+ * initially, "next" reflects only the order in file1.
+ */
+ struct entry *next, *previous;
+
+ /*
+ * If 1, this entry can serve as an anchor. See
+ * Documentation/diff-options.txt for more information.
+ */
+ unsigned anchor : 1;
+ } *entries, *first, *last;
+ /* were common records found? */
+ unsigned long has_matches;
+ mmfile_t *file1, *file2;
+ xdfenv_t *env;
+ xpparam_t const *xpp;
+};
+
+static int is_anchor(xpparam_t const *xpp, const char *line)
+{
+ size_t i;
+ for (i = 0; i < xpp->anchors_nr; i++) {
+ if (!strncmp(line, xpp->anchors[i], strlen(xpp->anchors[i])))
+ return 1;
+ }
+ return 0;
+}
+
+/* The argument "pass" is 1 for the first file, 2 for the second. */
+static void insert_record(xpparam_t const *xpp, int line, struct hashmap *map,
+ int pass)
+{
+ xrecord_t **records = pass == 1 ?
+ map->env->xdf1.recs : map->env->xdf2.recs;
+ xrecord_t *record = records[line - 1], *other;
+ /*
+ * After xdl_prepare_env() (or more precisely, due to
+ * xdl_classify_record()), the "ha" member of the records (AKA lines)
+ * is _not_ the hash anymore, but a linearized version of it. In
+ * other words, the "ha" member is guaranteed to start with 0 and
+ * the second record's ha can only be 0 or 1, etc.
+ *
+ * So we multiply ha by 2 in the hope that the hashing was
+ * "unique enough".
+ */
+ int index = (int)((record->ha << 1) % map->alloc);
+
+ while (map->entries[index].line1) {
+ other = map->env->xdf1.recs[map->entries[index].line1 - 1];
+ if (map->entries[index].hash != record->ha ||
+ !xdl_recmatch(record->ptr, record->size,
+ other->ptr, other->size,
+ map->xpp->flags)) {
+ if (++index >= map->alloc)
+ index = 0;
+ continue;
+ }
+ if (pass == 2)
+ map->has_matches = 1;
+ if (pass == 1 || map->entries[index].line2)
+ map->entries[index].line2 = NON_UNIQUE;
+ else
+ map->entries[index].line2 = line;
+ return;
+ }
+ if (pass == 2)
+ return;
+ map->entries[index].line1 = line;
+ map->entries[index].hash = record->ha;
+ map->entries[index].anchor = is_anchor(xpp, map->env->xdf1.recs[line - 1]->ptr);
+ if (!map->first)
+ map->first = map->entries + index;
+ if (map->last) {
+ map->last->next = map->entries + index;
+ map->entries[index].previous = map->last;
+ }
+ map->last = map->entries + index;
+ map->nr++;
+}
+
+/*
+ * This function has to be called for each recursion into the inter-hunk
+ * parts, as previously non-unique lines can become unique when being
+ * restricted to a smaller part of the files.
+ *
+ * It is assumed that env has been prepared using xdl_prepare().
+ */
+static int fill_hashmap(mmfile_t *file1, mmfile_t *file2,
+ xpparam_t const *xpp, xdfenv_t *env,
+ struct hashmap *result,
+ int line1, int count1, int line2, int count2)
+{
+ result->file1 = file1;
+ result->file2 = file2;
+ result->xpp = xpp;
+ result->env = env;
+
+ /* We know exactly how large we want the hash map */
+ result->alloc = count1 * 2;
+ result->entries = (struct entry *)
+ xdl_malloc(result->alloc * sizeof(struct entry));
+ if (!result->entries)
+ return -1;
+ memset(result->entries, 0, result->alloc * sizeof(struct entry));
+
+ /* First, fill with entries from the first file */
+ while (count1--)
+ insert_record(xpp, line1++, result, 1);
+
+ /* Then search for matches in the second file */
+ while (count2--)
+ insert_record(xpp, line2++, result, 2);
+
+ return 0;
+}
+
+/*
+ * Find the longest sequence with a smaller last element (meaning a smaller
+ * line2, as we construct the sequence with entries ordered by line1).
+ */
+static int binary_search(struct entry **sequence, int longest,
+ struct entry *entry)
+{
+ int left = -1, right = longest;
+
+ while (left + 1 < right) {
+ int middle = left + (right - left) / 2;
+ /* by construction, no two entries can be equal */
+ if (sequence[middle]->line2 > entry->line2)
+ right = middle;
+ else
+ left = middle;
+ }
+ /* return the index in "sequence", _not_ the sequence length */
+ return left;
+}
+
+/*
+ * The idea is to start with the list of common unique lines sorted by
+ * the order in file1. For each of these pairs, the longest (partial)
+ * sequence whose last element's line2 is smaller is determined.
+ *
+ * For efficiency, the sequences are kept in a list containing exactly one
+ * item per sequence length: the sequence with the smallest last
+ * element (in terms of line2).
+ */
+static struct entry *find_longest_common_sequence(struct hashmap *map)
+{
+ struct entry **sequence = (struct entry **)xdl_malloc(map->nr * sizeof(struct entry *));
+ int longest = 0, i;
+ struct entry *entry;
+ /*
+ * If not -1, this entry in sequence must never be overridden.
+ * Therefore, overriding entries before this has no effect, so
+ * do not do that either.
+ */
+ int anchor_i = -1;
+
+ /* Added to silence Coverity. */
+ if (sequence == NULL)
+ return map->first;
+
+ for (entry = map->first; entry; entry = entry->next) {
+ if (!entry->line2 || entry->line2 == NON_UNIQUE)
+ continue;
+ i = binary_search(sequence, longest, entry);
+ entry->previous = i < 0 ? NULL : sequence[i];
+ ++i;
+ if (i <= anchor_i)
+ continue;
+ sequence[i] = entry;
+ if (entry->anchor) {
+ anchor_i = i;
+ longest = anchor_i + 1;
+ } else if (i == longest) {
+ longest++;
+ }
+ }
+
+ /* No common unique lines were found */
+ if (!longest) {
+ xdl_free(sequence);
+ return NULL;
+ }
+
+ /* Iterate starting at the last element, adjusting the "next" members */
+ entry = sequence[longest - 1];
+ entry->next = NULL;
+ while (entry->previous) {
+ entry->previous->next = entry;
+ entry = entry->previous;
+ }
+ xdl_free(sequence);
+ return entry;
+}
+
+static int match(struct hashmap *map, int line1, int line2)
+{
+ xrecord_t *record1 = map->env->xdf1.recs[line1 - 1];
+ xrecord_t *record2 = map->env->xdf2.recs[line2 - 1];
+ return xdl_recmatch(record1->ptr, record1->size,
+ record2->ptr, record2->size, map->xpp->flags);
+}
+
+static int patience_diff(mmfile_t *file1, mmfile_t *file2,
+ xpparam_t const *xpp, xdfenv_t *env,
+ int line1, int count1, int line2, int count2);
+
+static int walk_common_sequence(struct hashmap *map, struct entry *first,
+ int line1, int count1, int line2, int count2)
+{
+ int end1 = line1 + count1, end2 = line2 + count2;
+ int next1, next2;
+
+ for (;;) {
+ /* Try to grow the line ranges of common lines */
+ if (first) {
+ next1 = first->line1;
+ next2 = first->line2;
+ while (next1 > line1 && next2 > line2 &&
+ match(map, next1 - 1, next2 - 1)) {
+ next1--;
+ next2--;
+ }
+ } else {
+ next1 = end1;
+ next2 = end2;
+ }
+ while (line1 < next1 && line2 < next2 &&
+ match(map, line1, line2)) {
+ line1++;
+ line2++;
+ }
+
+ /* Recurse */
+ if (next1 > line1 || next2 > line2) {
+ struct hashmap submap;
+
+ memset(&submap, 0, sizeof(submap));
+ if (patience_diff(map->file1, map->file2,
+ map->xpp, map->env,
+ line1, next1 - line1,
+ line2, next2 - line2))
+ return -1;
+ }
+
+ if (!first)
+ return 0;
+
+ while (first->next &&
+ first->next->line1 == first->line1 + 1 &&
+ first->next->line2 == first->line2 + 1)
+ first = first->next;
+
+ line1 = first->line1 + 1;
+ line2 = first->line2 + 1;
+
+ first = first->next;
+ }
+}
+
+static int fall_back_to_classic_diff(struct hashmap *map,
+ int line1, int count1, int line2, int count2)
+{
+ xpparam_t xpp;
+ xpp.flags = map->xpp->flags & ~XDF_DIFF_ALGORITHM_MASK;
+
+ return xdl_fall_back_diff(map->env, &xpp,
+ line1, count1, line2, count2);
+}
+
+/*
+ * Recursively find the longest common sequence of unique lines,
+ * and if none was found, ask xdl_do_diff() to do the job.
+ *
+ * This function assumes that env was prepared with xdl_prepare_env().
+ */
+static int patience_diff(mmfile_t *file1, mmfile_t *file2,
+ xpparam_t const *xpp, xdfenv_t *env,
+ int line1, int count1, int line2, int count2)
+{
+ struct hashmap map;
+ struct entry *first;
+ int result = 0;
+
+ /* trivial case: one side is empty */
+ if (!count1) {
+ while(count2--)
+ env->xdf2.rchg[line2++ - 1] = 1;
+ return 0;
+ } else if (!count2) {
+ while(count1--)
+ env->xdf1.rchg[line1++ - 1] = 1;
+ return 0;
+ }
+
+ memset(&map, 0, sizeof(map));
+ if (fill_hashmap(file1, file2, xpp, env, &map,
+ line1, count1, line2, count2))
+ return -1;
+
+ /* are there any matching lines at all? */
+ if (!map.has_matches) {
+ while(count1--)
+ env->xdf1.rchg[line1++ - 1] = 1;
+ while(count2--)
+ env->xdf2.rchg[line2++ - 1] = 1;
+ xdl_free(map.entries);
+ return 0;
+ }
+
+ first = find_longest_common_sequence(&map);
+ if (first)
+ result = walk_common_sequence(&map, first,
+ line1, count1, line2, count2);
+ else
+ result = fall_back_to_classic_diff(&map,
+ line1, count1, line2, count2);
+
+ xdl_free(map.entries);
+ return result;
+}
+
+int xdl_do_patience_diff(mmfile_t *file1, mmfile_t *file2,
+ xpparam_t const *xpp, xdfenv_t *env)
+{
+ if (xdl_prepare_env(file1, file2, xpp, env) < 0)
+ return -1;
+
+ /* environment is cleaned up in xdl_diff() */
+ return patience_diff(file1, file2, xpp, env,
+ 1, env->xdf1.nrec, 1, env->xdf2.nrec);
+}
diff --git a/src/nvim/xdiff/xprepare.c b/src/nvim/xdiff/xprepare.c
new file mode 100644
index 0000000000..abeb8fb84e
--- /dev/null
+++ b/src/nvim/xdiff/xprepare.c
@@ -0,0 +1,483 @@
+/*
+ * LibXDiff by Davide Libenzi ( File Differential Library )
+ * Copyright (C) 2003 Davide Libenzi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+#include "xinclude.h"
+
+
+#define XDL_KPDIS_RUN 4
+#define XDL_MAX_EQLIMIT 1024
+#define XDL_SIMSCAN_WINDOW 100
+#define XDL_GUESS_NLINES1 256
+#define XDL_GUESS_NLINES2 20
+
+
+typedef struct s_xdlclass {
+ struct s_xdlclass *next;
+ unsigned long ha;
+ char const *line;
+ long size;
+ long idx;
+ long len1, len2;
+} xdlclass_t;
+
+typedef struct s_xdlclassifier {
+ unsigned int hbits;
+ long hsize;
+ xdlclass_t **rchash;
+ chastore_t ncha;
+ xdlclass_t **rcrecs;
+ long alloc;
+ long count;
+ long flags;
+} xdlclassifier_t;
+
+
+
+
+static int xdl_init_classifier(xdlclassifier_t *cf, long size, long flags);
+static void xdl_free_classifier(xdlclassifier_t *cf);
+static int xdl_classify_record(unsigned int pass, xdlclassifier_t *cf, xrecord_t **rhash,
+ unsigned int hbits, xrecord_t *rec);
+static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_t const *xpp,
+ xdlclassifier_t *cf, xdfile_t *xdf);
+static void xdl_free_ctx(xdfile_t *xdf);
+static int xdl_clean_mmatch(char const *dis, long i, long s, long e);
+static int xdl_cleanup_records(xdlclassifier_t *cf, xdfile_t *xdf1, xdfile_t *xdf2);
+static int xdl_trim_ends(xdfile_t *xdf1, xdfile_t *xdf2);
+static int xdl_optimize_ctxs(xdlclassifier_t *cf, xdfile_t *xdf1, xdfile_t *xdf2);
+
+
+
+
+static int xdl_init_classifier(xdlclassifier_t *cf, long size, long flags) {
+ cf->flags = flags;
+
+ cf->hbits = xdl_hashbits((unsigned int) size);
+ cf->hsize = 1 << cf->hbits;
+
+ if (xdl_cha_init(&cf->ncha, sizeof(xdlclass_t), size / 4 + 1) < 0) {
+
+ return -1;
+ }
+ if (!(cf->rchash = (xdlclass_t **) xdl_malloc(cf->hsize * sizeof(xdlclass_t *)))) {
+
+ xdl_cha_free(&cf->ncha);
+ return -1;
+ }
+ memset(cf->rchash, 0, cf->hsize * sizeof(xdlclass_t *));
+
+ cf->alloc = size;
+ if (!(cf->rcrecs = (xdlclass_t **) xdl_malloc(cf->alloc * sizeof(xdlclass_t *)))) {
+
+ xdl_free(cf->rchash);
+ xdl_cha_free(&cf->ncha);
+ return -1;
+ }
+
+ cf->count = 0;
+
+ return 0;
+}
+
+
+static void xdl_free_classifier(xdlclassifier_t *cf) {
+
+ xdl_free(cf->rcrecs);
+ xdl_free(cf->rchash);
+ xdl_cha_free(&cf->ncha);
+}
+
+
+static int xdl_classify_record(unsigned int pass, xdlclassifier_t *cf, xrecord_t **rhash,
+ unsigned int hbits, xrecord_t *rec) {
+ long hi;
+ char const *line;
+ xdlclass_t *rcrec;
+ xdlclass_t **rcrecs;
+
+ line = rec->ptr;
+ hi = (long) XDL_HASHLONG(rec->ha, cf->hbits);
+ for (rcrec = cf->rchash[hi]; rcrec; rcrec = rcrec->next)
+ if (rcrec->ha == rec->ha &&
+ xdl_recmatch(rcrec->line, rcrec->size,
+ rec->ptr, rec->size, cf->flags))
+ break;
+
+ if (!rcrec) {
+ if (!(rcrec = xdl_cha_alloc(&cf->ncha))) {
+
+ return -1;
+ }
+ rcrec->idx = cf->count++;
+ if (cf->count > cf->alloc) {
+ cf->alloc *= 2;
+ if (!(rcrecs = (xdlclass_t **) xdl_realloc(cf->rcrecs, cf->alloc * sizeof(xdlclass_t *)))) {
+
+ return -1;
+ }
+ cf->rcrecs = rcrecs;
+ }
+ cf->rcrecs[rcrec->idx] = rcrec;
+ rcrec->line = line;
+ rcrec->size = rec->size;
+ rcrec->ha = rec->ha;
+ rcrec->len1 = rcrec->len2 = 0;
+ rcrec->next = cf->rchash[hi];
+ cf->rchash[hi] = rcrec;
+ }
+
+ (pass == 1) ? rcrec->len1++ : rcrec->len2++;
+
+ rec->ha = (unsigned long) rcrec->idx;
+
+ hi = (long) XDL_HASHLONG(rec->ha, hbits);
+ rec->next = rhash[hi];
+ rhash[hi] = rec;
+
+ return 0;
+}
+
+
+static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_t const *xpp,
+ xdlclassifier_t *cf, xdfile_t *xdf) {
+ unsigned int hbits;
+ long nrec, hsize, bsize;
+ unsigned long hav;
+ char const *blk, *cur, *top, *prev;
+ xrecord_t *crec;
+ xrecord_t **recs, **rrecs;
+ xrecord_t **rhash;
+ unsigned long *ha;
+ char *rchg;
+ long *rindex;
+
+ ha = NULL;
+ rindex = NULL;
+ rchg = NULL;
+ rhash = NULL;
+ recs = NULL;
+
+ if (xdl_cha_init(&xdf->rcha, sizeof(xrecord_t), narec / 4 + 1) < 0)
+ goto abort;
+ if (!(recs = (xrecord_t **) xdl_malloc(narec * sizeof(xrecord_t *))))
+ goto abort;
+
+ if (XDF_DIFF_ALG(xpp->flags) == XDF_HISTOGRAM_DIFF)
+ hbits = hsize = 0;
+ else {
+ hbits = xdl_hashbits((unsigned int) narec);
+ hsize = 1 << hbits;
+ if (!(rhash = (xrecord_t **) xdl_malloc(hsize * sizeof(xrecord_t *))))
+ goto abort;
+ memset(rhash, 0, hsize * sizeof(xrecord_t *));
+ }
+
+ nrec = 0;
+ if ((cur = blk = xdl_mmfile_first(mf, &bsize)) != NULL) {
+ for (top = blk + bsize; cur < top; ) {
+ prev = cur;
+ hav = xdl_hash_record(&cur, top, xpp->flags);
+ if (nrec >= narec) {
+ narec *= 2;
+ if (!(rrecs = (xrecord_t **) xdl_realloc(recs, narec * sizeof(xrecord_t *))))
+ goto abort;
+ recs = rrecs;
+ }
+ if (!(crec = xdl_cha_alloc(&xdf->rcha)))
+ goto abort;
+ crec->ptr = prev;
+ crec->size = (long) (cur - prev);
+ crec->ha = hav;
+ recs[nrec++] = crec;
+
+ if ((XDF_DIFF_ALG(xpp->flags) != XDF_HISTOGRAM_DIFF) &&
+ xdl_classify_record(pass, cf, rhash, hbits, crec) < 0)
+ goto abort;
+ }
+ }
+
+ if (!(rchg = (char *) xdl_malloc((nrec + 2) * sizeof(char))))
+ goto abort;
+ memset(rchg, 0, (nrec + 2) * sizeof(char));
+
+ if (!(rindex = (long *) xdl_malloc((nrec + 1) * sizeof(long))))
+ goto abort;
+ if (!(ha = (unsigned long *) xdl_malloc((nrec + 1) * sizeof(unsigned long))))
+ goto abort;
+
+ xdf->nrec = nrec;
+ xdf->recs = recs;
+ xdf->hbits = hbits;
+ xdf->rhash = rhash;
+ xdf->rchg = rchg + 1;
+ xdf->rindex = rindex;
+ xdf->nreff = 0;
+ xdf->ha = ha;
+ xdf->dstart = 0;
+ xdf->dend = nrec - 1;
+
+ return 0;
+
+abort:
+ xdl_free(ha);
+ xdl_free(rindex);
+ xdl_free(rchg);
+ xdl_free(rhash);
+ xdl_free(recs);
+ xdl_cha_free(&xdf->rcha);
+ return -1;
+}
+
+
+static void xdl_free_ctx(xdfile_t *xdf) {
+
+ xdl_free(xdf->rhash);
+ xdl_free(xdf->rindex);
+ xdl_free(xdf->rchg - 1);
+ xdl_free(xdf->ha);
+ xdl_free(xdf->recs);
+ xdl_cha_free(&xdf->rcha);
+}
+
+
+int xdl_prepare_env(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
+ xdfenv_t *xe) {
+ long enl1, enl2, sample;
+ xdlclassifier_t cf;
+
+ memset(&cf, 0, sizeof(cf));
+
+ /*
+ * For histogram diff, we can afford a smaller sample size and
+ * thus a poorer estimate of the number of lines, as the hash
+ * table (rhash) won't be filled up/grown. The number of lines
+ * (nrecs) will be updated correctly anyway by
+ * xdl_prepare_ctx().
+ */
+ sample = (XDF_DIFF_ALG(xpp->flags) == XDF_HISTOGRAM_DIFF
+ ? XDL_GUESS_NLINES2 : XDL_GUESS_NLINES1);
+
+ enl1 = xdl_guess_lines(mf1, sample) + 1;
+ enl2 = xdl_guess_lines(mf2, sample) + 1;
+
+ if (XDF_DIFF_ALG(xpp->flags) != XDF_HISTOGRAM_DIFF &&
+ xdl_init_classifier(&cf, enl1 + enl2 + 1, xpp->flags) < 0)
+ return -1;
+
+ if (xdl_prepare_ctx(1, mf1, enl1, xpp, &cf, &xe->xdf1) < 0) {
+
+ xdl_free_classifier(&cf);
+ return -1;
+ }
+ if (xdl_prepare_ctx(2, mf2, enl2, xpp, &cf, &xe->xdf2) < 0) {
+
+ xdl_free_ctx(&xe->xdf1);
+ xdl_free_classifier(&cf);
+ return -1;
+ }
+
+ if ((XDF_DIFF_ALG(xpp->flags) != XDF_PATIENCE_DIFF) &&
+ (XDF_DIFF_ALG(xpp->flags) != XDF_HISTOGRAM_DIFF) &&
+ xdl_optimize_ctxs(&cf, &xe->xdf1, &xe->xdf2) < 0) {
+
+ xdl_free_ctx(&xe->xdf2);
+ xdl_free_ctx(&xe->xdf1);
+ xdl_free_classifier(&cf);
+ return -1;
+ }
+
+ if (XDF_DIFF_ALG(xpp->flags) != XDF_HISTOGRAM_DIFF)
+ xdl_free_classifier(&cf);
+
+ return 0;
+}
+
+
+void xdl_free_env(xdfenv_t *xe) {
+
+ xdl_free_ctx(&xe->xdf2);
+ xdl_free_ctx(&xe->xdf1);
+}
+
+
+static int xdl_clean_mmatch(char const *dis, long i, long s, long e) {
+ long r, rdis0, rpdis0, rdis1, rpdis1;
+
+ /*
+ * Limits the window the is examined during the similar-lines
+ * scan. The loops below stops when dis[i - r] == 1 (line that
+ * has no match), but there are corner cases where the loop
+ * proceed all the way to the extremities by causing huge
+ * performance penalties in case of big files.
+ */
+ if (i - s > XDL_SIMSCAN_WINDOW)
+ s = i - XDL_SIMSCAN_WINDOW;
+ if (e - i > XDL_SIMSCAN_WINDOW)
+ e = i + XDL_SIMSCAN_WINDOW;
+
+ /*
+ * Scans the lines before 'i' to find a run of lines that either
+ * have no match (dis[j] == 0) or have multiple matches (dis[j] > 1).
+ * Note that we always call this function with dis[i] > 1, so the
+ * current line (i) is already a multimatch line.
+ */
+ for (r = 1, rdis0 = 0, rpdis0 = 1; (i - r) >= s; r++) {
+ if (!dis[i - r])
+ rdis0++;
+ else if (dis[i - r] == 2)
+ rpdis0++;
+ else
+ break;
+ }
+ /*
+ * If the run before the line 'i' found only multimatch lines, we
+ * return 0 and hence we don't make the current line (i) discarded.
+ * We want to discard multimatch lines only when they appear in the
+ * middle of runs with nomatch lines (dis[j] == 0).
+ */
+ if (rdis0 == 0)
+ return 0;
+ for (r = 1, rdis1 = 0, rpdis1 = 1; (i + r) <= e; r++) {
+ if (!dis[i + r])
+ rdis1++;
+ else if (dis[i + r] == 2)
+ rpdis1++;
+ else
+ break;
+ }
+ /*
+ * If the run after the line 'i' found only multimatch lines, we
+ * return 0 and hence we don't make the current line (i) discarded.
+ */
+ if (rdis1 == 0)
+ return 0;
+ rdis1 += rdis0;
+ rpdis1 += rpdis0;
+
+ return rpdis1 * XDL_KPDIS_RUN < (rpdis1 + rdis1);
+}
+
+
+/*
+ * Try to reduce the problem complexity, discard records that have no
+ * matches on the other file. Also, lines that have multiple matches
+ * might be potentially discarded if they happear in a run of discardable.
+ */
+static int xdl_cleanup_records(xdlclassifier_t *cf, xdfile_t *xdf1, xdfile_t *xdf2) {
+ long i, nm, nreff, mlim;
+ xrecord_t **recs;
+ xdlclass_t *rcrec;
+ char *dis, *dis1, *dis2;
+
+ if (!(dis = (char *) xdl_malloc(xdf1->nrec + xdf2->nrec + 2))) {
+
+ return -1;
+ }
+ memset(dis, 0, xdf1->nrec + xdf2->nrec + 2);
+ dis1 = dis;
+ dis2 = dis1 + xdf1->nrec + 1;
+
+ if ((mlim = xdl_bogosqrt(xdf1->nrec)) > XDL_MAX_EQLIMIT)
+ mlim = XDL_MAX_EQLIMIT;
+ for (i = xdf1->dstart, recs = &xdf1->recs[xdf1->dstart]; i <= xdf1->dend; i++, recs++) {
+ rcrec = cf->rcrecs[(*recs)->ha];
+ nm = rcrec ? rcrec->len2 : 0;
+ dis1[i] = (nm == 0) ? 0: (nm >= mlim) ? 2: 1;
+ }
+
+ if ((mlim = xdl_bogosqrt(xdf2->nrec)) > XDL_MAX_EQLIMIT)
+ mlim = XDL_MAX_EQLIMIT;
+ for (i = xdf2->dstart, recs = &xdf2->recs[xdf2->dstart]; i <= xdf2->dend; i++, recs++) {
+ rcrec = cf->rcrecs[(*recs)->ha];
+ nm = rcrec ? rcrec->len1 : 0;
+ dis2[i] = (nm == 0) ? 0: (nm >= mlim) ? 2: 1;
+ }
+
+ for (nreff = 0, i = xdf1->dstart, recs = &xdf1->recs[xdf1->dstart];
+ i <= xdf1->dend; i++, recs++) {
+ if (dis1[i] == 1 ||
+ (dis1[i] == 2 && !xdl_clean_mmatch(dis1, i, xdf1->dstart, xdf1->dend))) {
+ xdf1->rindex[nreff] = i;
+ xdf1->ha[nreff] = (*recs)->ha;
+ nreff++;
+ } else
+ xdf1->rchg[i] = 1;
+ }
+ xdf1->nreff = nreff;
+
+ for (nreff = 0, i = xdf2->dstart, recs = &xdf2->recs[xdf2->dstart];
+ i <= xdf2->dend; i++, recs++) {
+ if (dis2[i] == 1 ||
+ (dis2[i] == 2 && !xdl_clean_mmatch(dis2, i, xdf2->dstart, xdf2->dend))) {
+ xdf2->rindex[nreff] = i;
+ xdf2->ha[nreff] = (*recs)->ha;
+ nreff++;
+ } else
+ xdf2->rchg[i] = 1;
+ }
+ xdf2->nreff = nreff;
+
+ xdl_free(dis);
+
+ return 0;
+}
+
+
+/*
+ * Early trim initial and terminal matching records.
+ */
+static int xdl_trim_ends(xdfile_t *xdf1, xdfile_t *xdf2) {
+ long i, lim;
+ xrecord_t **recs1, **recs2;
+
+ recs1 = xdf1->recs;
+ recs2 = xdf2->recs;
+ for (i = 0, lim = XDL_MIN(xdf1->nrec, xdf2->nrec); i < lim;
+ i++, recs1++, recs2++)
+ if ((*recs1)->ha != (*recs2)->ha)
+ break;
+
+ xdf1->dstart = xdf2->dstart = i;
+
+ recs1 = xdf1->recs + xdf1->nrec - 1;
+ recs2 = xdf2->recs + xdf2->nrec - 1;
+ for (lim -= i, i = 0; i < lim; i++, recs1--, recs2--)
+ if ((*recs1)->ha != (*recs2)->ha)
+ break;
+
+ xdf1->dend = xdf1->nrec - i - 1;
+ xdf2->dend = xdf2->nrec - i - 1;
+
+ return 0;
+}
+
+
+static int xdl_optimize_ctxs(xdlclassifier_t *cf, xdfile_t *xdf1, xdfile_t *xdf2) {
+
+ if (xdl_trim_ends(xdf1, xdf2) < 0 ||
+ xdl_cleanup_records(cf, xdf1, xdf2) < 0) {
+
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/nvim/xdiff/xprepare.h b/src/nvim/xdiff/xprepare.h
new file mode 100644
index 0000000000..947d9fc1bb
--- /dev/null
+++ b/src/nvim/xdiff/xprepare.h
@@ -0,0 +1,34 @@
+/*
+ * LibXDiff by Davide Libenzi ( File Differential Library )
+ * Copyright (C) 2003 Davide Libenzi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+#if !defined(XPREPARE_H)
+#define XPREPARE_H
+
+
+
+int xdl_prepare_env(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
+ xdfenv_t *xe);
+void xdl_free_env(xdfenv_t *xe);
+
+
+
+#endif /* #if !defined(XPREPARE_H) */
diff --git a/src/nvim/xdiff/xtypes.h b/src/nvim/xdiff/xtypes.h
new file mode 100644
index 0000000000..8442bd436e
--- /dev/null
+++ b/src/nvim/xdiff/xtypes.h
@@ -0,0 +1,67 @@
+/*
+ * LibXDiff by Davide Libenzi ( File Differential Library )
+ * Copyright (C) 2003 Davide Libenzi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+#if !defined(XTYPES_H)
+#define XTYPES_H
+
+
+
+typedef struct s_chanode {
+ struct s_chanode *next;
+ long icurr;
+} chanode_t;
+
+typedef struct s_chastore {
+ chanode_t *head, *tail;
+ long isize, nsize;
+ chanode_t *ancur;
+ chanode_t *sncur;
+ long scurr;
+} chastore_t;
+
+typedef struct s_xrecord {
+ struct s_xrecord *next;
+ char const *ptr;
+ long size;
+ unsigned long ha;
+} xrecord_t;
+
+typedef struct s_xdfile {
+ chastore_t rcha;
+ long nrec;
+ unsigned int hbits;
+ xrecord_t **rhash;
+ long dstart, dend;
+ xrecord_t **recs;
+ char *rchg;
+ long *rindex;
+ long nreff;
+ unsigned long *ha;
+} xdfile_t;
+
+typedef struct s_xdfenv {
+ xdfile_t xdf1, xdf2;
+} xdfenv_t;
+
+
+
+#endif /* #if !defined(XTYPES_H) */
diff --git a/src/nvim/xdiff/xutils.c b/src/nvim/xdiff/xutils.c
new file mode 100644
index 0000000000..25a090fb73
--- /dev/null
+++ b/src/nvim/xdiff/xutils.c
@@ -0,0 +1,425 @@
+/*
+ * LibXDiff by Davide Libenzi ( File Differential Library )
+ * Copyright (C) 2003 Davide Libenzi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+#include <limits.h>
+#include <assert.h>
+#include "xinclude.h"
+
+
+
+
+long xdl_bogosqrt(long n) {
+ long i;
+
+ /*
+ * Classical integer square root approximation using shifts.
+ */
+ for (i = 1; n > 0; n >>= 2)
+ i <<= 1;
+
+ return i;
+}
+
+
+int xdl_emit_diffrec(char const *rec, long size, char const *pre, long psize,
+ xdemitcb_t *ecb) {
+ int i = 2;
+ mmbuffer_t mb[3];
+
+ mb[0].ptr = (char *) pre;
+ mb[0].size = psize;
+ mb[1].ptr = (char *) rec;
+ mb[1].size = size;
+ if (size > 0 && rec[size - 1] != '\n') {
+ mb[2].ptr = (char *) "\n\\ No newline at end of file\n";
+ mb[2].size = (long)strlen(mb[2].ptr);
+ i++;
+ }
+ if (ecb->outf(ecb->priv, mb, i) < 0) {
+
+ return -1;
+ }
+
+ return 0;
+}
+
+void *xdl_mmfile_first(mmfile_t *mmf, long *size)
+{
+ *size = mmf->size;
+ return mmf->ptr;
+}
+
+
+long xdl_mmfile_size(mmfile_t *mmf)
+{
+ return mmf->size;
+}
+
+
+int xdl_cha_init(chastore_t *cha, long isize, long icount) {
+
+ cha->head = cha->tail = NULL;
+ cha->isize = isize;
+ cha->nsize = icount * isize;
+ cha->ancur = cha->sncur = NULL;
+ cha->scurr = 0;
+
+ return 0;
+}
+
+
+void xdl_cha_free(chastore_t *cha) {
+ chanode_t *cur, *tmp;
+
+ for (cur = cha->head; (tmp = cur) != NULL;) {
+ cur = cur->next;
+ xdl_free(tmp);
+ }
+}
+
+
+void *xdl_cha_alloc(chastore_t *cha) {
+ chanode_t *ancur;
+ void *data;
+
+ if (!(ancur = cha->ancur) || ancur->icurr == cha->nsize) {
+ if (!(ancur = (chanode_t *) xdl_malloc(sizeof(chanode_t) + cha->nsize))) {
+
+ return NULL;
+ }
+ ancur->icurr = 0;
+ ancur->next = NULL;
+ if (cha->tail)
+ cha->tail->next = ancur;
+ if (!cha->head)
+ cha->head = ancur;
+ cha->tail = ancur;
+ cha->ancur = ancur;
+ }
+
+ data = (char *) ancur + sizeof(chanode_t) + ancur->icurr;
+ ancur->icurr += cha->isize;
+
+ return data;
+}
+
+long xdl_guess_lines(mmfile_t *mf, long sample) {
+ long nl = 0, size, tsize = 0;
+ char const *data, *cur, *top;
+
+ if ((cur = data = xdl_mmfile_first(mf, &size)) != NULL) {
+ for (top = data + size; nl < sample && cur < top; ) {
+ nl++;
+ if (!(cur = memchr(cur, '\n', top - cur)))
+ cur = top;
+ else
+ cur++;
+ }
+ tsize += (long) (cur - data);
+ }
+
+ if (nl && tsize)
+ nl = xdl_mmfile_size(mf) / (tsize / nl);
+
+ return nl + 1;
+}
+
+int xdl_blankline(const char *line, long size, long flags)
+{
+ long i;
+
+ if (!(flags & XDF_WHITESPACE_FLAGS))
+ return (size <= 1);
+
+ for (i = 0; i < size && XDL_ISSPACE(line[i]); i++)
+ ;
+
+ return (i == size);
+}
+
+/*
+ * Have we eaten everything on the line, except for an optional
+ * CR at the very end?
+ */
+static int ends_with_optional_cr(const char *l, long s, long i)
+{
+ int complete = s && l[s-1] == '\n';
+
+ if (complete)
+ s--;
+ if (s == i)
+ return 1;
+ /* do not ignore CR at the end of an incomplete line */
+ if (complete && s == i + 1 && l[i] == '\r')
+ return 1;
+ return 0;
+}
+
+int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags)
+{
+ int i1, i2;
+
+ if (s1 == s2 && !memcmp(l1, l2, s1))
+ return 1;
+ if (!(flags & XDF_WHITESPACE_FLAGS))
+ return 0;
+
+ i1 = 0;
+ i2 = 0;
+
+ /*
+ * -w matches everything that matches with -b, and -b in turn
+ * matches everything that matches with --ignore-space-at-eol,
+ * which in turn matches everything that matches with --ignore-cr-at-eol.
+ *
+ * Each flavor of ignoring needs different logic to skip whitespaces
+ * while we have both sides to compare.
+ */
+ if (flags & XDF_IGNORE_WHITESPACE) {
+ goto skip_ws;
+ while (i1 < s1 && i2 < s2) {
+ if (l1[i1++] != l2[i2++])
+ return 0;
+ skip_ws:
+ while (i1 < s1 && XDL_ISSPACE(l1[i1]))
+ i1++;
+ while (i2 < s2 && XDL_ISSPACE(l2[i2]))
+ i2++;
+ }
+ } else if (flags & XDF_IGNORE_WHITESPACE_CHANGE) {
+ while (i1 < s1 && i2 < s2) {
+ if (XDL_ISSPACE(l1[i1]) && XDL_ISSPACE(l2[i2])) {
+ /* Skip matching spaces and try again */
+ while (i1 < s1 && XDL_ISSPACE(l1[i1]))
+ i1++;
+ while (i2 < s2 && XDL_ISSPACE(l2[i2]))
+ i2++;
+ continue;
+ }
+ if (l1[i1++] != l2[i2++])
+ return 0;
+ }
+ } else if (flags & XDF_IGNORE_WHITESPACE_AT_EOL) {
+ while (i1 < s1 && i2 < s2 && l1[i1] == l2[i2]) {
+ i1++;
+ i2++;
+ }
+ } else if (flags & XDF_IGNORE_CR_AT_EOL) {
+ /* Find the first difference and see how the line ends */
+ while (i1 < s1 && i2 < s2 && l1[i1] == l2[i2]) {
+ i1++;
+ i2++;
+ }
+ return (ends_with_optional_cr(l1, s1, i1) &&
+ ends_with_optional_cr(l2, s2, i2));
+ }
+
+ /*
+ * After running out of one side, the remaining side must have
+ * nothing but whitespace for the lines to match. Note that
+ * ignore-whitespace-at-eol case may break out of the loop
+ * while there still are characters remaining on both lines.
+ */
+ if (i1 < s1) {
+ while (i1 < s1 && XDL_ISSPACE(l1[i1]))
+ i1++;
+ if (s1 != i1)
+ return 0;
+ }
+ if (i2 < s2) {
+ while (i2 < s2 && XDL_ISSPACE(l2[i2]))
+ i2++;
+ return (s2 == i2);
+ }
+ return 1;
+}
+
+static unsigned long xdl_hash_record_with_whitespace(char const **data,
+ char const *top, long flags) {
+ unsigned long ha = 5381;
+ char const *ptr = *data;
+ int cr_at_eol_only = (flags & XDF_WHITESPACE_FLAGS) == XDF_IGNORE_CR_AT_EOL;
+
+ for (; ptr < top && *ptr != '\n'; ptr++) {
+ if (cr_at_eol_only) {
+ /* do not ignore CR at the end of an incomplete line */
+ if (*ptr == '\r' &&
+ (ptr + 1 < top && ptr[1] == '\n'))
+ continue;
+ }
+ else if (XDL_ISSPACE(*ptr)) {
+ const char *ptr2 = ptr;
+ int at_eol;
+ while (ptr + 1 < top && XDL_ISSPACE(ptr[1])
+ && ptr[1] != '\n')
+ ptr++;
+ at_eol = (top <= ptr + 1 || ptr[1] == '\n');
+ if (flags & XDF_IGNORE_WHITESPACE)
+ ; /* already handled */
+ else if (flags & XDF_IGNORE_WHITESPACE_CHANGE
+ && !at_eol) {
+ ha += (ha << 5);
+ ha ^= (unsigned long) ' ';
+ }
+ else if (flags & XDF_IGNORE_WHITESPACE_AT_EOL
+ && !at_eol) {
+ while (ptr2 != ptr + 1) {
+ ha += (ha << 5);
+ ha ^= (unsigned long) *ptr2;
+ ptr2++;
+ }
+ }
+ continue;
+ }
+ ha += (ha << 5);
+ ha ^= (unsigned long) *ptr;
+ }
+ *data = ptr < top ? ptr + 1: ptr;
+
+ return ha;
+}
+
+unsigned long xdl_hash_record(char const **data, char const *top, long flags) {
+ unsigned long ha = 5381;
+ char const *ptr = *data;
+
+ if (flags & XDF_WHITESPACE_FLAGS)
+ return xdl_hash_record_with_whitespace(data, top, flags);
+
+ for (; ptr < top && *ptr != '\n'; ptr++) {
+ ha += (ha << 5);
+ ha ^= (unsigned long) *ptr;
+ }
+ *data = ptr < top ? ptr + 1: ptr;
+
+ return ha;
+}
+
+unsigned int xdl_hashbits(unsigned int size) {
+ unsigned int val = 1, bits = 0;
+
+ for (; val < size && bits < CHAR_BIT * sizeof(unsigned int); val <<= 1, bits++);
+ return bits ? bits: 1;
+}
+
+
+int xdl_num_out(char *out, long val) {
+ char *ptr, *str = out;
+ char buf[32];
+
+ ptr = buf + sizeof(buf) - 1;
+ *ptr = '\0';
+ if (val < 0) {
+ *--ptr = '-';
+ val = -val;
+ }
+ for (; val && ptr > buf; val /= 10)
+ *--ptr = "0123456789"[val % 10];
+ if (*ptr)
+ for (; *ptr; ptr++, str++)
+ *str = *ptr;
+ else
+ *str++ = '0';
+ *str = '\0';
+
+ return str - out;
+}
+
+int xdl_emit_hunk_hdr(long s1, long c1, long s2, long c2,
+ const char *func, long funclen, xdemitcb_t *ecb) {
+ int nb = 0;
+ mmbuffer_t mb;
+ char buf[128];
+
+ memcpy(buf, "@@ -", 4);
+ nb += 4;
+
+ nb += xdl_num_out(buf + nb, c1 ? s1: s1 - 1);
+
+ if (c1 != 1) {
+ memcpy(buf + nb, ",", 1);
+ nb += 1;
+
+ nb += xdl_num_out(buf + nb, c1);
+ }
+
+ memcpy(buf + nb, " +", 2);
+ nb += 2;
+
+ nb += xdl_num_out(buf + nb, c2 ? s2: s2 - 1);
+
+ if (c2 != 1) {
+ memcpy(buf + nb, ",", 1);
+ nb += 1;
+
+ nb += xdl_num_out(buf + nb, c2);
+ }
+
+ memcpy(buf + nb, " @@", 3);
+ nb += 3;
+ if (func && funclen) {
+ buf[nb++] = ' ';
+ if (funclen > (long)sizeof(buf) - nb - 1)
+ funclen = sizeof(buf) - nb - 1;
+ memcpy(buf + nb, func, funclen);
+ nb += funclen;
+ }
+ buf[nb++] = '\n';
+
+ mb.ptr = buf;
+ mb.size = nb;
+ if (ecb->outf(ecb->priv, &mb, 1) < 0)
+ return -1;
+
+ return 0;
+}
+
+int xdl_fall_back_diff(xdfenv_t *diff_env, xpparam_t const *xpp,
+ int line1, int count1, int line2, int count2)
+{
+ /*
+ * This probably does not work outside Git, since
+ * we have a very simple mmfile structure.
+ *
+ * Note: ideally, we would reuse the prepared environment, but
+ * the libxdiff interface does not (yet) allow for diffing only
+ * ranges of lines instead of the whole files.
+ */
+ mmfile_t subfile1, subfile2;
+ xdfenv_t env;
+
+ subfile1.ptr = (char *)diff_env->xdf1.recs[line1 - 1]->ptr;
+ subfile1.size = diff_env->xdf1.recs[line1 + count1 - 2]->ptr +
+ diff_env->xdf1.recs[line1 + count1 - 2]->size - subfile1.ptr;
+ subfile2.ptr = (char *)diff_env->xdf2.recs[line2 - 1]->ptr;
+ subfile2.size = diff_env->xdf2.recs[line2 + count2 - 2]->ptr +
+ diff_env->xdf2.recs[line2 + count2 - 2]->size - subfile2.ptr;
+ if (xdl_do_diff(&subfile1, &subfile2, xpp, &env) < 0)
+ return -1;
+
+ memcpy(diff_env->xdf1.rchg + line1 - 1, env.xdf1.rchg, count1);
+ memcpy(diff_env->xdf2.rchg + line2 - 1, env.xdf2.rchg, count2);
+
+ xdl_free_env(&env);
+
+ return 0;
+}
diff --git a/src/nvim/xdiff/xutils.h b/src/nvim/xdiff/xutils.h
new file mode 100644
index 0000000000..fba7bae03c
--- /dev/null
+++ b/src/nvim/xdiff/xutils.h
@@ -0,0 +1,47 @@
+/*
+ * LibXDiff by Davide Libenzi ( File Differential Library )
+ * Copyright (C) 2003 Davide Libenzi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+#if !defined(XUTILS_H)
+#define XUTILS_H
+
+
+
+long xdl_bogosqrt(long n);
+int xdl_emit_diffrec(char const *rec, long size, char const *pre, long psize,
+ xdemitcb_t *ecb);
+int xdl_cha_init(chastore_t *cha, long isize, long icount);
+void xdl_cha_free(chastore_t *cha);
+void *xdl_cha_alloc(chastore_t *cha);
+long xdl_guess_lines(mmfile_t *mf, long sample);
+int xdl_blankline(const char *line, long size, long flags);
+int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags);
+unsigned long xdl_hash_record(char const **data, char const *top, long flags);
+unsigned int xdl_hashbits(unsigned int size);
+int xdl_num_out(char *out, long val);
+int xdl_emit_hunk_hdr(long s1, long c1, long s2, long c2,
+ const char *func, long funclen, xdemitcb_t *ecb);
+int xdl_fall_back_diff(xdfenv_t *diff_env, xpparam_t const *xpp,
+ int line1, int count1, int line2, int count2);
+
+
+
+#endif /* #if !defined(XUTILS_H) */