From de13113dc16e3f3a453e783dc7ea692ac4967231 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 4 Nov 2018 13:16:24 +0100 Subject: test/timer_spec: relax lower-bound Test is unreliable on macOS 10.13. The lower-bound isn't central to the purpose of the test, so just relax it. ref https://github.com/neovim/neovim/pull/9095#issuecomment-429603452 > We don't guarantee that a X ms timer is triggered during Y ms sleep > for any X to happen with X=10ms, Y=40ms. related: #6829 --- src/nvim/testdir/test_timers.vim | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/testdir/test_timers.vim b/src/nvim/testdir/test_timers.vim index da61751bf4..8a3e57bb02 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() @@ -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)) -- cgit From 4de70f5b9581bd0e35e7af3b6fb1eb835d538555 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Thu, 1 Nov 2018 05:24:44 +0100 Subject: doc - update standard-plugin-list. closes #8388 --- src/nvim/api/vim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index fed20a272a..7fcccfd988 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1028,7 +1028,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. -- cgit From b96730bc3bc71e03004b9720bcd0ac67a2a7bb85 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Mon, 5 Nov 2018 03:50:22 +0100 Subject: doc: API --- src/nvim/api/buffer.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 39330690e8..487a912882 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) { -- cgit From bd6866f90b6cf7334a9f0d160be6f3b1e5157d51 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Mon, 5 Nov 2018 20:06:26 -0500 Subject: vim-patch:8.1.0510: filter test fails when $LANG is C.UTF-8 Problem: Filter test fails when $LANG is C.UTF-8. Solution: Set 'helplang' to "en" for any C language. (Christian Brabandt, closes vim/vim#3577) https://github.com/vim/vim/commit/dcd71cbaedf75dd8e5c5a45c5c2e3ec7ee552dce --- src/nvim/option.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/nvim/option.c b/src/nvim/option.c index a0fb2d9e36..4fa99424e8 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; -- cgit From e0d6894a54b0ed263d8c93197e50ad5fca641f08 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Mon, 5 Nov 2018 20:40:32 -0500 Subject: vim-patch:8.1.0512: 'helplang' default is inconsistent for C and C.UTF-8 Problem: 'helplang' default is inconsistent for C and C.UTF-8. Solution: Don't accept a value unless it starts with two letters. https://github.com/vim/vim/commit/389ab7122bec99c11ad4ce6d87cc6f38a21e4e40 --- src/nvim/ex_cmds2.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index 90fb7b8bc3..a148f51527 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -3506,7 +3506,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 +3531,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. -- cgit From f08869cff2eae65eede8df41fab274c77dd76c60 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Tue, 6 Nov 2018 07:49:20 -0500 Subject: vim-patch:8.1.0511: ml_get error when calling a function with a range (#9207) Problem: ml_get error when calling a function with a range. Solution: Don't position the cursor after the last line. https://github.com/vim/vim/commit/9e353b5265bd7fa103caf4e5a9b3c99f344f548e --- src/nvim/eval.c | 6 ++++++ src/nvim/testdir/test_functions.vim | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 4e0e3f6f1f..2fb9bd7367 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; 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('') + 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 -- cgit From c4c74c3883aa3122c0c877ca8dd7b26beb5cc4aa Mon Sep 17 00:00:00 2001 From: Tommy Allen Date: Wed, 7 Nov 2018 04:31:25 -0500 Subject: jobstart(): Fix hang on non-executable cwd #9204 * os/fs.c: add os_isdir_executable() * eval.c: fix hang on job start caused by non-executable cwd option * channel.c: assert cwd is an executable directory * test: jobstart() produces error when using non-executable cwd --- src/nvim/channel.c | 2 ++ src/nvim/eval.c | 4 ++-- src/nvim/os/fs.c | 21 ++++++++++++++++++++- 3 files changed, 24 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/nvim/channel.c b/src/nvim/channel.c index 259f1cc600..58a34acb22 100644 --- a/src/nvim/channel.c +++ b/src/nvim/channel.c @@ -284,6 +284,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; diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 2fb9bd7367..9c7af0a87d 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -11724,7 +11724,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; @@ -16769,7 +16769,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; 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. -- cgit From 348adbcc7a6a07b68d1eddab5b675746ee5e4148 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Tue, 6 Nov 2018 19:56:31 +0100 Subject: ui_options: also send when starting or from OptionSet needed after #9024 to receive options from init.vim --- src/nvim/option.c | 60 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/nvim/option.c b/src/nvim/option.c index 4fa99424e8..11f3df7cfa 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -1773,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' @@ -1790,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); @@ -2382,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); @@ -2393,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); @@ -4060,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 */ @@ -4433,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 */ @@ -4465,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))); - } } } -- cgit From 312afd8e2e777707401c9305ad450deb2bc08e1b Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Thu, 8 Nov 2018 13:46:44 +0100 Subject: channel: avoid buffering output when only terminal and no callbacks are active --- src/nvim/channel.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/nvim/channel.c b/src/nvim/channel.c index 58a34acb22..e191f838e0 100644 --- a/src/nvim/channel.c +++ b/src/nvim/channel.c @@ -607,12 +607,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); + } } } -- cgit From 18435a25347eeecb0886281d278c060aa7f82f6c Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Fri, 9 Nov 2018 03:33:28 -0500 Subject: vim-patch:8.1.0337: :file fails in quickfix command (#9215) Problem: :file fails in quickfix command. Solution: Allow :file without argument when curbuf_lock is set. (Jason Franklin) https://github.com/vim/vim/commit/379fb76b080521f7c09265ec3264b9e698923518 --- src/nvim/ex_docmd.c | 19 ++++++++++++++----- src/nvim/testdir/test_quickfix.vim | 29 +++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 6ac7656a2f..6361267d9b 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" diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim index 624e642e7f..bfe5791ec8 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! -- cgit From f8639dc99cb085432b14da086af316176152bc1f Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sat, 10 Nov 2018 11:12:04 +0100 Subject: test: adjust time-sensitive tests (#9220) - window_split_tab_spec.lua: Put cursor at bottom of :terminal buffer so that it follows output. - inccommand_spec.lua: Increase timeout to allow 2nd retry. - Timer tests are less reliable on Travis CI macOS 10.12/10.13. ref #6829 ref e39dade80b02 ref de13113dc16e ref https://github.com/neovim/neovim/pull/9095#issuecomment-429603452 > We don't guarantee that a X ms timer is triggered during Y ms sleep > for any X to happen with X=10ms, Y=40ms. --- src/nvim/testdir/test_lambda.vim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/testdir/test_lambda.vim b/src/nvim/testdir/test_lambda.vim index 311cc6e2cb..2ac84c2213 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() let m = s:n - sleep 200ms + sleep 210ms call timer_stop(s:timer_id) call assert_true(m > 1) call assert_true(s:n > m + 1) -- cgit From 520ec3dbfd208c99f9b184ab0a4baeab9a93b556 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sat, 3 Nov 2018 14:40:22 +0100 Subject: UI/TUI: improvements and cleanups for scrolling and clearing - TUI: _never_ rely on BCE for implicit clearing, only explicit commands. - TUI: use unibi_erase_chars when possible. - TUI: use end-exclusive ranges for invalid and cleared areas - screen: scrolling leaves scrolled in aree undefined. This is a conservative change, a client assuming the old semantics will still behave correctly. - screen: factor out vsep handling from line drawing. This is needed anyway for the multigrid refactor. - screen: simplifications of win_do_lines --- src/nvim/message.c | 4 ++ src/nvim/move.c | 4 +- src/nvim/screen.c | 99 +++++++++++----------------------- src/nvim/tui/tui.c | 153 +++++++++++++++++++++++++++-------------------------- src/nvim/ugrid.c | 25 +++------ src/nvim/ugrid.h | 14 +++-- 6 files changed, 130 insertions(+), 169 deletions(-) (limited to 'src') diff --git a/src/nvim/message.c b/src/nvim/message.c index edce30e6fa..10f4905fb2 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -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 { 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/screen.c b/src/nvim/screen.c index 46aa771a89..d1453b56d2 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -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; @@ -4262,7 +4259,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 +4344,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 +4469,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) { @@ -6071,10 +6052,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 +6079,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 +6121,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 +6202,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 +6213,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 +6248,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 +6260,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/tui/tui.c b/src/nvim/tui/tui.c index fc7d31edb0..4b00fcf57c 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -94,6 +94,7 @@ typedef struct { bool can_change_scroll_region; bool can_set_lr_margin; bool can_set_left_right_margin; + bool can_erase_chars; bool immediate_wrap_after_last_column; bool bce; bool mouse_enabled; @@ -119,6 +120,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; @@ -239,6 +241,7 @@ static void terminfo_start(UI *ui) data->can_set_left_right_margin = !!unibi_get_str(data->ut, unibi_set_left_margin_parm) && !!unibi_get_str(data->ut, unibi_set_right_margin_parm); + data->can_erase_chars = !!unibi_get_str(data->ut, unibi_erase_chars); data->immediate_wrap_after_last_column = terminfo_is_term_family(term, "cygwin") || terminfo_is_term_family(term, "interix"); @@ -401,6 +404,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); } @@ -662,7 +666,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); }); } @@ -734,50 +738,48 @@ 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; + HlAttrs attrs = kv_A(data->attrs, (size_t)attr_id); + update_attrs(ui, attrs); // 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; - } + // 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 (can_clear && 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 (can_clear && right == ui->width) { unibi_out(ui, unibi_clr_eol); + } else if (data->can_erase_chars && can_clear && 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) @@ -838,12 +840,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. @@ -866,8 +872,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) @@ -1025,9 +1030,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->scroll_region_is_full_screen || (data->can_change_scroll_region @@ -1041,8 +1044,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) { @@ -1064,16 +1065,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); } } @@ -1107,7 +1106,7 @@ static void tui_default_colors_set(UI *ui, Integer rgb_fg, Integer rgb_bg, 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); + invalidate(ui, 0, data->grid.height, 0, data->grid.width); } static void tui_flush(UI *ui) @@ -1129,11 +1128,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); @@ -1219,7 +1234,7 @@ static void tui_option_set(UI *ui, String name, Object value) ui->rgb = value.data.boolean; data->print_attrs = HLATTRS_INVALID; - invalidate(ui, 0, data->grid.height-1, 0, data->grid.width-1); + invalidate(ui, 0, data->grid.height, 0, data->grid.width); } } @@ -1235,18 +1250,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) { @@ -1269,27 +1282,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 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) -- cgit From eb3b73d472798c0b9ff2bde8e0313890b6c42a2e Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Fri, 9 Nov 2018 14:07:29 +0100 Subject: TUI: attrs -> attr_id refactor --- src/nvim/highlight_defs.h | 11 ----------- src/nvim/tui/tui.c | 49 +++++++++++++++++++++++++++-------------------- 2 files changed, 28 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/src/nvim/highlight_defs.h b/src/nvim/highlight_defs.h index 09d20c75ea..0790793c94 100644 --- a/src/nvim/highlight_defs.h +++ b/src/nvim/highlight_defs.h @@ -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 { diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 4b00fcf57c..b6986b77e9 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -104,7 +104,8 @@ typedef struct { cursorentry_T cursor_shapes[SHAPE_IDX_COUNT]; HlAttrs clear_attrs; kvec_t(HlAttrs) attrs; - HlAttrs print_attrs; + int print_attr_id; + bool has_bg; bool default_attr; ModeShape showing_mode; struct { @@ -186,6 +187,7 @@ static void terminfo_start(UI *ui) data->scroll_region_is_full_screen = true; data->bufpos = 0; data->default_attr = false; + data->has_bg = false; data->is_invisible = true; data->busy = false; data->cork = false; @@ -305,7 +307,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); @@ -439,8 +441,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 @@ -455,21 +466,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) { @@ -483,6 +489,8 @@ static void update_attrs(UI *ui, HlAttrs attrs) : (data->clear_attrs.cterm_bg_color - 1); } + data->has_bg = bg != -1; + int attr = ui->rgb ? attrs.rgb_ae_attr : attrs.cterm_ae_attr; bool bold = attr & HL_BOLD; bool italic = attr & HL_ITALIC; @@ -599,7 +607,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) { @@ -615,8 +623,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; } @@ -743,11 +751,10 @@ static void clear_region(UI *ui, int top, int bot, int left, int right, TUIData *data = ui->data; UGrid *grid = &data->grid; - HlAttrs attrs = kv_A(data->attrs, (size_t)attr_id); - update_attrs(ui, attrs); + update_attrs(ui, attr_id); // non-BCE terminals can't clear with non-default background color - bool can_clear = data->bce || no_bg(ui, attrs); + bool can_clear = data->bce || !data->has_bg; // 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. @@ -1105,7 +1112,7 @@ 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; + data->print_attr_id = -1; invalidate(ui, 0, data->grid.height, 0, data->grid.width); } @@ -1233,7 +1240,7 @@ 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; + data->print_attr_id = -1; invalidate(ui, 0, data->grid.height, 0, data->grid.width); } } -- cgit From 9f3fb66111d3a7923106df60837f3150b3cf55b9 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sun, 11 Nov 2018 13:13:14 -0500 Subject: vim-patch:8.1.0516: :move command sets 'modified' #9224 Problem: :move command marks buffer modified when nothing changed. Solution: Do not set 'modified'. Add a test. (Jason Franklin) https://github.com/vim/vim/commit/ddd1f9183bed00d096f29c503721ac559174a29f --- src/nvim/ex_cmds.c | 15 ++++++++++++++- src/nvim/testdir/test_alot.vim | 1 + src/nvim/testdir/test_move.vim | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 src/nvim/testdir/test_move.vim (limited to 'src') diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index dc942eb0b3..0a9b6ecc57 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; /* 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_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 -- cgit From 208cdb84a6991bb3652db70b7ac6aea7ab36dcb7 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Mon, 3 Sep 2018 10:40:28 -0400 Subject: vim-patch:8.1.0340: no test for :spellinfo Problem: No test for :spellinfo. Solution: Add a test. (Dominique Pelle, closes vim/vim#3394) https://github.com/vim/vim/commit/9049b686121367941bf534c041975938135c7e20 --- src/nvim/testdir/test_spell.vim | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'src') diff --git a/src/nvim/testdir/test_spell.vim b/src/nvim/testdir/test_spell.vim index a2828b21d2..3dbbce83fc 100644 --- a/src/nvim/testdir/test_spell.vim +++ b/src/nvim/testdir/test_spell.vim @@ -85,6 +85,35 @@ func Test_spellreall() bwipe! endfunc +func Test_spellinfo() + 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", -- cgit From e5046822c96ecfd7c774bf3ab025caf5aebd06d8 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Mon, 3 Sep 2018 13:11:07 -0400 Subject: oldtests: skip Test_spellinfo() nvim supports only `set encoding=utf8`. --- src/nvim/testdir/test_spell.vim | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/nvim/testdir/test_spell.vim b/src/nvim/testdir/test_spell.vim index 3dbbce83fc..b3438cc649 100644 --- a/src/nvim/testdir/test_spell.vim +++ b/src/nvim/testdir/test_spell.vim @@ -86,6 +86,7 @@ func Test_spellreall() endfunc func Test_spellinfo() + throw 'skipped: Nvim does not support enc=latin1' new set enc=latin1 spell spelllang=en -- cgit From 42419e5a735332e075d3db599df5fd1b74a92868 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Wed, 19 Sep 2018 21:21:45 -0400 Subject: vim-patch:8.0.1620: reading spell file has no good EOF detection Problem: Reading spell file has no good EOF detection. Solution: Check for EOF at every character read for a length field. https://github.com/vim/vim/commit/e26e0d2b83c2875b9829b884c2ababf8ca771f7e --- src/nvim/fileio.c | 71 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index d0e30ddbd3..21cb76e220 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -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; } -- cgit From 8fa7b6c8af127b90fa54aa7ac70735ca0149643a Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Mon, 12 Nov 2018 11:05:27 -0500 Subject: vim-patch:8.1.0096: inconsistent use of the word autocommands Problem: Inconsistent use of the word autocommands. Solution: Don't use auto-commands or "auto commands". https://github.com/vim/vim/commit/8c55533c6f109db2a0fff69651887f9474eb09c6 --- src/nvim/fileio.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 21cb76e220..857e69a001 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -5967,19 +5967,19 @@ void au_event_restore(char_u *old_ei) * will be automatically executed for * when editing a file matching , in * the current group. - * :autocmd Show the auto-commands associated with + * :autocmd Show the autocommands associated with * and . - * :autocmd Show the auto-commands associated with + * :autocmd Show the autocommands associated with * . - * :autocmd Show all auto-commands. - * :autocmd! Remove all auto-commands associated with + * :autocmd Show all autocommands. + * :autocmd! Remove all autocommands associated with * and , and add the command * , for the current group. - * :autocmd! Remove all auto-commands associated with + * :autocmd! Remove all autocommands associated with * and for the current group. - * :autocmd! Remove all auto-commands associated with + * :autocmd! Remove all autocommands associated with * 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 @@ -6073,7 +6073,7 @@ void do_autocmd(char_u *arg_in, int forceit) */ if (!forceit && *cmd == NUL) { /* Highlight title */ - MSG_PUTS_TITLE(_("\n--- Auto-Commands ---")); + MSG_PUTS_TITLE(_("\n--- Autocommands ---")); } /* @@ -6942,7 +6942,7 @@ 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. */ + // Don't redraw while doing autocommands. ++RedrawingDisabled; save_sourcing_name = sourcing_name; sourcing_name = NULL; /* don't free this one */ @@ -7154,7 +7154,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); -- cgit From 21824df3c6e0e73bb90482899560648fa04d55e5 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Mon, 12 Nov 2018 11:12:44 -0500 Subject: lint --- src/nvim/fileio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 857e69a001..7e8a7d1a35 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -6072,7 +6072,7 @@ void do_autocmd(char_u *arg_in, int forceit) * Print header when showing autocommands. */ if (!forceit && *cmd == NUL) { - /* Highlight title */ + // Highlight title MSG_PUTS_TITLE(_("\n--- Autocommands ---")); } @@ -6943,7 +6943,7 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io, // Don't redraw while doing autocommands. - ++RedrawingDisabled; + RedrawingDisabled++; save_sourcing_name = sourcing_name; sourcing_name = NULL; /* don't free this one */ save_sourcing_lnum = sourcing_lnum; -- cgit From f6ed446817480a0356294f9abc17c138605816e9 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Wed, 14 Nov 2018 20:10:05 -0500 Subject: vim-patch:8.1.0527: using 'shiftwidth' from wrong buffer for folding (#9234) Problem: Using 'shiftwidth' from wrong buffer for folding. Solution: Use "buf" instead of "curbuf". (Christian Brabandt) https://github.com/vim/vim/commit/0c27cbcacf0f58ad30f0b15d1f442f73f40347c2 --- src/nvim/fold.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') 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); } -- cgit From 3295083d5aefd469a08ff96a0ddab097235c685e Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Wed, 14 Nov 2018 21:20:07 -0500 Subject: vim-patch:8.1.0108: no Danish translations (#9235) Problem: No Danish translations. Solution: Add Danish message translations. (closes vim/vim#3073) Move list of languages to a common makefile. https://github.com/vim/vim/commit/a4a2934e59429e2ff68d478556ad8b2043fb0fda --- src/nvim/po/CMakeLists.txt | 1 + src/nvim/po/da.po | 7088 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 7089 insertions(+) create mode 100644 src/nvim/po/da.po (limited to 'src') 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 "" +msgstr "" + +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 \"\"" +msgstr "E495: intet autokommando-filnavn til erstatning for \"\"" + +msgid "E496: no autocommand buffer number to substitute for \"\"" +msgstr "E496: intet autokommando-buffernummer til erstatning for \"\"" + +msgid "E497: no autocommand match name to substitute for \"\"" +msgstr "E497: intet autokommando-matchnavn til erstatning for \"\"" + +msgid "E498: no :source file name to substitute for \"\"" +msgstr "E498: intet :source-filnavn til erstatning for \"\"" + +msgid "E842: no line number to use for \"\"" +msgstr "E842: intet linjenummer til brug for \"\"" + +#, 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 " +msgstr "auto-removing-autokommando: %s " + +#, 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: : invalid buffer number " +msgstr "E680: : 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 " " +msgstr " " + +#, 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 " +msgstr "E562: Anvendelse: cstag " + +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 \t\tUse for I/O" +msgstr "-dev \t\tBrug 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 \tSet terminal type to " +msgstr "-T \tSæt terminaltype til " + +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 \t\tUse instead of any .vimrc" +msgstr "-u \t\tBrug i stedet for nogen .vimrc" + +msgid "-U \t\tUse instead of any .gvimrc" +msgstr "-U \t\tBrug 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 "+\t\tStart at line " +msgstr "+\t\tBegynd ved linje " + +msgid "--cmd \tExecute before loading any vimrc file" +msgstr "--cmd \tUdfør inden indlæsning af vimrc-filer" + +msgid "-c \t\tExecute after loading the first file" +msgstr "-c \tUdfør efter indlæsning af den første fil" + +msgid "-S \t\tSource file after loading the first file" +msgstr "-S \t\tSource filen efter indlæsning af den første fil" + +msgid "-s \tRead Normal mode commands from file " +msgstr "-s \tLæs normal tilstand-kommandoer fra filen " + +msgid "-w \tAppend all typed commands to file " +msgstr "" +"-w \tTilføj alle indtastede kommandoer til slutningen af filen " +"" + +msgid "-W \tWrite all typed commands to file " +msgstr "-W \tSkriv alle indtastede kommandoer til filen " + +msgid "-x\t\t\tEdit encrypted files" +msgstr "-x\t\t\tRediger krypterede filer" + +msgid "-display \tConnect vim to this particular X-server" +msgstr "-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 \tEdit in a Vim server if possible" +msgstr "--remote \tRediger i en Vim-server, hvis det er muligt" + +msgid "--remote-silent Same, don't complain if there is no server" +msgstr "" +"--remote-silent Samme, men vær tavs hvis der ikke er nogen server" + +msgid "" +"--remote-wait As --remote but wait for files to have been edited" +msgstr "" +"--remote-wait Som --remote men vent på filer som skal redigeres" + +msgid "" +"--remote-wait-silent Same, don't complain if there is no server" +msgstr "" +"--remote-wait-silent Samme, men vær tavs hvis der ikke er nogen " +"server" + +msgid "" +"--remote-tab[-wait][-silent] As --remote but use tab page per file" +msgstr "" +"--remote-tab[-wait][-silent] Som --remote men brug fanebladsside " +"pr. fil" + +msgid "--remote-send \tSend to a Vim server and exit" +msgstr "--remote-send \tSend til en Vim-server og afslut" + +msgid "--remote-expr \tEvaluate in a Vim server and print result" +msgstr "" +"--remote-expr \tEvaluér 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 \tSend to/become the Vim server " +msgstr "--servername \tSend til/bliv Vim-serveren " + +msgid "--startuptime \tWrite startup timing messages to " +msgstr "--startuptime \tSkriv meddelelser om opstartstiming til " + +msgid "-i \t\tUse instead of .viminfo" +msgstr "-i \t\tBrug 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 \tRun vim on " +msgstr "-display \tKør vim på " + +msgid "-iconic\t\tStart vim iconified" +msgstr "-iconic\t\tStart vim som ikon" + +msgid "-background \tUse for the background (also: -bg)" +msgstr "-background \tBrug til baggrunden (også: -bg)" + +msgid "-foreground \tUse for normal text (also: -fg)" +msgstr "-foreground \tBrug til normal tekst (også: -fg)" + +msgid "-font \t\tUse for normal text (also: -fn)" +msgstr "-font \tBrug til normal tekst (også: -fn)" + +msgid "-boldfont \tUse for bold text" +msgstr "-boldfont \tBrug til fed tekst" + +msgid "-italicfont \tUse for italic text" +msgstr "-italicfont \tBrug til kursiv tekst" + +msgid "-geometry \tUse for initial geometry (also: -geom)" +msgstr "-geometry \tBrug for indledende geometri (også: -geom)" + +msgid "-borderwidth \tUse a border width of (also: -bw)" +msgstr "-borderwidth \tBrug en kantbredde på (også: -bw)" + +msgid "-scrollbarwidth Use a scrollbar width of (also: -sw)" +msgstr "" +"-scrollbarwidth Brug en rullebjælkebredde på (også: -sw)" + +msgid "-menuheight \tUse a menu bar height of (also: -mh)" +msgstr "-menuheight \tBrug en menulinjehøjde på (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 \tSet the specified resource" +msgstr "-xrm \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 \tRun vim on (also: --display)" +msgstr "-display \tKør vim på (også: --display)" + +msgid "--role \tSet a unique role to identify the main window" +msgstr "--role \tSæt en unik rolle til at identificere hovedvinduet" + +msgid "--socketid \tOpen Vim inside another GTK widget" +msgstr "--socketid \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 \tOpen Vim inside parent application" +msgstr "-P \tÅbn Vim i forælderprogram" + +msgid "--windowid \tOpen Vim inside another win32 widget" +msgstr "--windowid \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 " +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 or click with mouse (empty cancels): " +msgstr "Skriv nummer og eller klik med musen (tom annullerer): " + +msgid "Type number and (empty cancels): " +msgstr "Skriv nummer og (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 to abandon all changes and exit Vim" +msgstr "" +"Skriv :qa! og tryk på 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 not in a script context: %s" +msgstr "E120: Bruger 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 for information " +msgstr "skriv :help iccf for information " + +msgid "type :q to exit " +msgstr "skriv :q for at afslutte " + +msgid "type :help or for on-line help" +msgstr "skriv :help eller for onlinehjælp " + +msgid "type :help version8 for version info" +msgstr "skriv :help version8 for versionsinfo" + +msgid "Running in Vi compatible mode" +msgstr "Kører i Vi-kompatibel-tilstand" + +msgid "type :set nocp for Vim defaults" +msgstr "skriv :set nocp for Vim-standarder" + +msgid "type :help cp-default for info on this" +msgstr "skriv :help cp-default 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 for information " +msgstr "skriv :help sponsor for information " + +msgid "type :help register for information " +msgstr "skriv :help register 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; executes, CTRL-C quits" +msgstr "E11: Ugyldig i kommandolinjevindue; 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 not in a script context" +msgstr "E81: Bruger 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" -- cgit From d81b9d5ec536ff7a9dbb35892adb1d1cd1651026 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Thu, 15 Nov 2018 05:42:18 -0500 Subject: vim-patch:8.1.0146: when $LANG is set the compiler test may fail (#9238) Problem: When $LANG is set the compiler test may fail. Solution: Unset $LANG. https://github.com/vim/vim/commit/f0447e89a52885630947510f2d1b55f665a1a20e --- src/nvim/testdir/test_compiler.vim | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src') 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) -- cgit From 9fe472c91b7f05be3ab5f5e0a459e303fa0eacc7 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sat, 17 Nov 2018 08:18:01 -0500 Subject: vim-patch:8.1.0258: not enough testing for the CompleteDone event Problem: Not enough testing for the CompleteDone event. Solution: Add a test. (closes vim/vim#3297) https://github.com/vim/vim/commit/af559d2c9f44bc88a7d94f9236b3c024563a8e73 --- src/nvim/testdir/test_ins_complete.vim | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'src') 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\\\\", "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 -- cgit From a9ae5bf36b9a742e99e0945df0a0c6e473de1bf3 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sat, 17 Nov 2018 22:20:44 -0500 Subject: vim-patch:8.1.0298: window resize test sometimes fails on Mac Problem: Window resize test sometimes fails on Mac. Solution: Add Test_popup_and_window_resize() to flaky tests. https://github.com/vim/vim/commit/46fad2ef0bd5124f1be22c807214c243fb5611d8 --- src/nvim/testdir/runtest.vim | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/nvim/testdir/runtest.vim b/src/nvim/testdir/runtest.vim index 99b2b940d7..8e9ee0494d 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()', " sometimes fails on Mac \ 'Test_quoteplus()', \ 'Test_quotestar()', \ 'Test_reltime()', -- cgit From 2b7e58cb2c59d6ad6f548b00abd85f396a8a244f Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sat, 17 Nov 2018 22:23:04 -0500 Subject: vim-patch:8.1.0299: misplaced comment Problem: misplaced comment Solution: Remove comment https://github.com/vim/vim/commit/142ae736d984f4575c1c6ec1a4f679ae4ddf9413 --- src/nvim/testdir/runtest.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/testdir/runtest.vim b/src/nvim/testdir/runtest.vim index 8e9ee0494d..4fe7db135b 100644 --- a/src/nvim/testdir/runtest.vim +++ b/src/nvim/testdir/runtest.vim @@ -245,7 +245,7 @@ let s:flaky = [ \ 'Test_oneshot()', \ 'Test_out_cb()', \ 'Test_paused()', - \ 'Test_popup_and_window_resize()', " sometimes fails on Mac + \ 'Test_popup_and_window_resize()', \ 'Test_quoteplus()', \ 'Test_quotestar()', \ 'Test_reltime()', -- cgit From eab181a74e8534974f6cc887bae9b65fddcfe25e Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sat, 17 Nov 2018 22:37:31 -0500 Subject: vim-patch:8.1.0318: the getftype() test may fail for char devices Problem: The getftype() test may fail for char devices if the file disappeared in between the listing and the getftype() call. Solution: Ignore empty result. (Ozaki Kiichi, closes vim/vim#3360) https://github.com/vim/vim/commit/3b3a506f57a397d83db361be35189c591bff10fb --- src/nvim/testdir/test_stat.vim | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/nvim/testdir/test_stat.vim b/src/nvim/testdir/test_stat.vim index c276df0a92..74b76d668e 100644 --- a/src/nvim/testdir/test_stat.vim +++ b/src/nvim/testdir/test_stat.vim @@ -141,17 +141,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? -- cgit From 65a3d53cb92c3b153a69a6fb4827fc0b7790d4cf Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sun, 18 Nov 2018 00:17:50 -0500 Subject: vim-patch:8.1.0376: compiler warning for uninitialized variable Problem: Compiler warning for uninitialized variable. (Tony Mechelynck) Solution: Initialize the variable. https://github.com/vim/vim/commit/c787539747f6bb2510a56aa14dbf6808aff5681a --- src/nvim/screen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/screen.c b/src/nvim/screen.c index d1453b56d2..a1e666386b 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -2172,7 +2172,7 @@ win_line ( 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 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 */ -- cgit From f4b4b7c1326cd599b08c78981b032a75ae1faaa7 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sun, 18 Nov 2018 00:30:16 -0500 Subject: lint --- src/nvim/screen.c | 54 +++++++++++++++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/nvim/screen.c b/src/nvim/screen.c index a1e666386b..1de5e5cc3d 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -2169,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 */ + 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 */ - 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 */ + 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 @@ -3100,8 +3100,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) { @@ -3272,7 +3273,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 @@ -3295,7 +3296,7 @@ win_line ( saved_attr2 = char_attr; // save current attr } mb_c = c; - mb_utf8 = FALSE; + mb_utf8 = false; mb_l = 1; } @@ -3573,7 +3574,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) { @@ -3636,8 +3637,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) { @@ -3726,8 +3728,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; @@ -4053,8 +4056,9 @@ win_line ( mb_utf8 = true; u8cc[0] = 0; c = 0xc0; - } else - mb_utf8 = FALSE; + } else { + mb_utf8 = false; + } } /* advance to the next 'colorcolumn' */ -- cgit From 344dd2757ac24417252ac4d5c73382eb07f81ede Mon Sep 17 00:00:00 2001 From: James McCoy Date: Sun, 18 Nov 2018 12:05:43 -0500 Subject: vim-patch:8.1.0536: file time test fails when using NFS (#9251) Problem: File time test fails when using NFS. Solution: Use three file times instead of localtim(). (James McCoy, closes vim/vim#3618) https://github.com/vim/vim/commit/addc156c38d442367854f71baee31f2eb003c699 --- src/nvim/testdir/test_stat.vim | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/nvim/testdir/test_stat.vim b/src/nvim/testdir/test_stat.vim index 74b76d668e..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 -- cgit From 463d28cc8079c2dd474c462fc84b7f7a67ee9b44 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 18 Nov 2018 19:58:41 +0100 Subject: TUI: support TERM=nsterm (#9244) `:help $TERM` recommends TERM=nsterm for Terminal.app but we did not actually support it. NB: We don't include a builtin term for Terminal.app, presumably because nsterm is commonly available on most systems (`infocmp nsterm`). --- src/nvim/tui/tui.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index b6986b77e9..d2ddd98fd4 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -1466,7 +1466,9 @@ static void patch_terminfo_bugs(TUIData *data, const char *term, #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 rxvt = terminfo_is_term_family(term, "rxvt"); -- cgit From e53ae88e7ecb20f39f9f9c73cd9b39bc12a665ab Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sun, 18 Nov 2018 19:38:51 -0500 Subject: vim-patch:8.1.0398: no test for -o and -O command line arguments (#9253) Problem: No test for -o and -O command line arguments. Solution: Add a test. (Dominique Pelle, closes vim/vim#3438) https://github.com/vim/vim/commit/8f4499b81612568b4964e8445d86e34e6d644b13 --- src/nvim/testdir/test_startup.vim | 77 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) (limited to 'src') 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")', -- cgit From a5637597a6df1465df50584d853dbd8d77cb24da Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Mon, 19 Nov 2018 21:10:52 -0500 Subject: vim-patch:8.0.1427: the :leftabove modifier doesn't work for :copen Problem: The :leftabove modifier doesn't work for :copen. Solution: Respect the split modifier. (Yegappan Lakshmanan, closes vim/vim#2496) https://github.com/vim/vim/commit/de04654ddc865af94ef04b1738b335a924be7923 --- src/nvim/quickfix.c | 16 ++++++++++++---- src/nvim/testdir/test_quickfix.vim | 27 +++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 4 deletions(-) (limited to 'src') 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/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim index bfe5791ec8..cb3e7ca8f6 100644 --- a/src/nvim/testdir/test_quickfix.vim +++ b/src/nvim/testdir/test_quickfix.vim @@ -2637,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 -- cgit From e71f43f8e7beaa0d1ed35b63ea55e43f886a0875 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Mon, 19 Nov 2018 21:52:38 -0500 Subject: vim-patch:8.0.0737: crash when X11 selection is very big Problem: Crash when X11 selection is very big. Solution: Use static items instead of allocating them. Add callbacks. (Ozaki Kiichi) https://github.com/vim/vim/commit/cdb7e1b7f9e18a7b165ff09103a9994f84966123 --- src/nvim/testdir/shared.vim | 7 ++++--- src/nvim/testdir/test_quotestar.vim | 12 ++++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/nvim/testdir/shared.vim b/src/nvim/testdir/shared.vim index b1f1d8fe66..a19929e79b 100644 --- a/src/nvim/testdir/shared.vim +++ b/src/nvim/testdir/shared.vim @@ -136,14 +136,15 @@ 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) + for i in range(timeout / 10) try if eval(a:expr) if has('reltime') @@ -158,7 +159,7 @@ func WaitFor(expr) endif sleep 10m endfor - return 1000 + return timeout endfunc " Wait for up to a given milliseconds. 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 @* = '' -- cgit From fdc2707b41a0c82bb621c2d437f775690bff45ee Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Mon, 19 Nov 2018 22:31:11 -0500 Subject: vim-patch:8.0.1249: no error when WaitFor() gets an invalid wrong expression Problem: No error when WaitFor() gets an invalid wrong expression. Solution: Do not ignore errors in evaluationg the expression. Fix places where the expression was wrong. https://github.com/vim/vim/commit/c20e0d52071a3f6e12321ec3344024faa4695da9 --- src/nvim/testdir/shared.vim | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/nvim/testdir/shared.vim b/src/nvim/testdir/shared.vim index a19929e79b..eb6798f353 100644 --- a/src/nvim/testdir/shared.vim +++ b/src/nvim/testdir/shared.vim @@ -145,15 +145,12 @@ func WaitFor(expr, ...) let slept = 0 endif for i in range(timeout / 10) - try - if eval(a:expr) - if has('reltime') - return float2nr(reltimefloat(reltime(start)) * 1000) - endif - return slept + 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 -- cgit From f1d2297c5ece3463ae098b9cd779e067cbf653fa Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Mon, 19 Nov 2018 23:45:28 -0500 Subject: vim-patch:8.0.1163: popup test is flaky Problem: Popup test is flaky. Solution: Add a WaitFor() and fix another. https://github.com/vim/vim/commit/c79977a437d91306d576fb59e490601409503303 --- src/nvim/testdir/test_popup.vim | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/testdir/test_popup.vim b/src/nvim/testdir/test_popup.vim index 6fd58a1483..9cd591838c 100644 --- a/src/nvim/testdir/test_popup.vim +++ b/src/nvim/testdir/test_popup.vim @@ -681,14 +681,15 @@ func Test_popup_and_window_resize() call term_wait(g:buf, 100) call term_sendkeys(g:buf, "\") call term_wait(g:buf, 100) + 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)') + 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)') + 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)) bwipe! endfunc -- cgit From 3c228e8935ab39f9c63f9e32152cb3d2b4bce543 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Mon, 19 Nov 2018 23:45:59 -0500 Subject: vim-patch:8.0.1165: popup test is still flaky Problem: Popup test is still flaky. Solution: Add a term_wait() call. (Ozaki Kiichi) https://github.com/vim/vim/commit/f52c38315669f85bbcf3bd74c590148bf588f6c6 --- src/nvim/testdir/test_popup.vim | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/nvim/testdir/test_popup.vim b/src/nvim/testdir/test_popup.vim index 9cd591838c..b8f7ac0459 100644 --- a/src/nvim/testdir/test_popup.vim +++ b/src/nvim/testdir/test_popup.vim @@ -677,20 +677,26 @@ func Test_popup_and_window_resize() endif let g:buf = term_start([$NVIM_PRG, '--clean', '-c', 'set noswapfile'], {'term_rows': h / 3}) call term_sendkeys(g:buf, (h / 3 - 1)."o\G") + call term_wait(g:buf, 100) call term_sendkeys(g:buf, "i\") call term_wait(g:buf, 100) call term_sendkeys(g:buf, "\") 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! + " 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 + " 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 -- cgit From 54a586736bab4a657b1457c59d1c0959f009687d Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Mon, 19 Nov 2018 23:46:31 -0500 Subject: vim-patch:8.0.1171: popup test is still a bit flaky Problem: Popup test is still a bit flaky. Solution: Change term_wait() calls. (Ozaki Kiichi) https://github.com/vim/vim/commit/712549e04eddd6687c4b7654ec9af6da6c365603 --- src/nvim/testdir/test_popup.vim | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/testdir/test_popup.vim b/src/nvim/testdir/test_popup.vim index b8f7ac0459..c9cd04018c 100644 --- a/src/nvim/testdir/test_popup.vim +++ b/src/nvim/testdir/test_popup.vim @@ -677,9 +677,8 @@ func Test_popup_and_window_resize() endif let g:buf = term_start([$NVIM_PRG, '--clean', '-c', 'set noswapfile'], {'term_rows': h / 3}) call term_sendkeys(g:buf, (h / 3 - 1)."o\G") - call term_wait(g:buf, 100) call term_sendkeys(g:buf, "i\") - call term_wait(g:buf, 100) + call term_wait(g:buf, 200) call term_sendkeys(g:buf, "\") call term_wait(g:buf, 100) " popup first entry "!" must be at the top -- cgit From deb18a050ef522791c48c7c8c549a2c4b2043be0 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Tue, 20 Nov 2018 10:52:49 +0100 Subject: defaults: background=dark #2894 (#9205) By historical accident, Nvim defaults to background=light. So on a dark background, `:colorscheme default` looks completely wrong. The "smart" logic that Vim uses is confusing for anyone who uses Vim on multiple platforms, so rather than mimic that, pick the (hopefully) most common default. - Since Neovim is dark-powered, we assume most users have dark backgrounds. - Most of the GUIs tend to have a dark background by default. ref #6289 --- src/nvim/options.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/options.lua b/src/nvim/options.lua index bc7f1a2b0a..b0575df7ec 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', -- cgit From bebd1f9f7629c6150e7eadcf0d33e9c90c81add2 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Tue, 20 Nov 2018 20:15:30 -0500 Subject: vim-patch:8.0.1731: characters deleted on completion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: Characters deleted on completion. (Adrià Farrés) Solution: Also check the last item for the ORIGINAL_TEXT flag. (Christian Brabandt, closes vim/vim#1645) https://github.com/vim/vim/commit/e87edf3b85f607632e5431640071fdbc36b685b2 --- src/nvim/edit.c | 10 ++++++++-- src/nvim/testdir/test_popup.vim | 9 +++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/edit.c b/src/nvim/edit.c index d20660bfb9..451d19b8e3 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); } } diff --git a/src/nvim/testdir/test_popup.vim b/src/nvim/testdir/test_popup.vim index c9cd04018c..09dc3ba43f 100644 --- a/src/nvim/testdir/test_popup.vim +++ b/src/nvim/testdir/test_popup.vim @@ -571,6 +571,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\". repeat("\", 3). "rt\", 'tx') + call assert_equal(expected, getline(1,'$')) + bwipe! +endfunc func Test_popup_and_preview_autocommand() " This used to crash Vim -- cgit From 5d22d100f2a848b692c37dc5d413939c8ef7681f Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Tue, 20 Nov 2018 21:13:28 -0500 Subject: vim-patch:8.1.0038: popup test causes Vim to exit Problem: Popup test causes Vim to exit. Solution: Disable the broken part of the test for now. https://github.com/vim/vim/commit/680c99b2efc7e2a9e6b3d611133f43fb7f8c6811 --- src/nvim/testdir/test_popup.vim | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/nvim/testdir/test_popup.vim b/src/nvim/testdir/test_popup.vim index 09dc3ba43f..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 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']) -- cgit From 01dbf0951b25d582451a8e656731dcf3d9295a71 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Fri, 23 Jun 2017 09:56:35 +0200 Subject: api: implement object namespaces Namespaces is a lightweight concept that should be used to group objects for purposes of bulk operations and introspection. This is initially used for highlights and virtual text in buffers, and is planned to also be used for extended marks. There is no plan use them for privileges or isolation, neither to introduce nanespace-level options. --- src/nvim/api/buffer.c | 66 ++++++++++++++++++++++++++++----------------------- src/nvim/api/vim.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++ src/nvim/api/vim.h | 4 ++++ src/nvim/buffer.c | 7 +++--- src/nvim/channel.c | 1 - src/nvim/main.c | 3 +++ src/nvim/map.c | 1 + src/nvim/map.h | 1 + src/nvim/memory.c | 2 ++ 9 files changed, 112 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 487a912882..4559f37191 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -905,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_highlight|. 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, @@ -962,9 +962,9 @@ 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 @@ -973,13 +973,13 @@ Integer nvim_buf_add_highlight(Buffer buffer, /// 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. /// @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 src_id, + Integer ns_id, Integer line_start, Integer line_end, Error *err) @@ -998,7 +998,7 @@ 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); } @@ -1010,12 +1010,18 @@ void nvim_buf_clear_highlight(Buffer buffer, /// 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. /// -/// 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. +/// 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_highlight|. 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_highlight|. If the +/// virtual text never will be cleared by an API call, pass `src_id = -1`. +/// +/// 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 @@ -1023,9 +1029,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, @@ -1075,9 +1081,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 7fcccfd988..54b27477e0 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. @@ -884,6 +902,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) 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 #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/buffer.c b/src/nvim/buffer.c index cd77f48320..634e257d40 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 diff --git a/src/nvim/channel.c b/src/nvim/channel.c index e191f838e0..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. diff --git a/src/nvim/main.c b/src/nvim/main.c index af54e62393..911e51407d 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(); } 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. -- cgit From fc0aeb5f88eccb4c816ba68bfa2902d621067c4e Mon Sep 17 00:00:00 2001 From: Marco Hinz Date: Tue, 20 Nov 2018 12:17:49 +0100 Subject: xenial: fix clang error messages * Remove FUNC_ATTR_NONNULL_ALL from function without pointer arguments. Otherwise the ASAN build would complain: error: 'nonnull' attribute applied to function with no pointer arguments [-Werror,-Wignored-attributes] static void do_autocmd_focusgained(_Bool gained) __attribute__((nonnull)); --- src/nvim/aucmd.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src') 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; -- cgit From 02d68fbcae8b97e41aff4dbb40c64994b37dd65a Mon Sep 17 00:00:00 2001 From: James McCoy Date: Tue, 20 Nov 2018 20:08:41 -0500 Subject: Remove extraneous parens to silence -Wparentheses-equality In file included from ../src/nvim/eval/encode.c:974: ../src/nvim/eval/typval_encode.c.h:390:40: error: equality comparison with extraneous parentheses [-Werror,-Wparentheses-equality] do { if ((tv->vval.v_special == kSpecialVarTrue)) { msgpack_pack_true(packer); } else { msgpack_pack_false(packer); } } while (0); ~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~ --- src/nvim/eval/encode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') 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); \ -- cgit From b1aaa0a881ef36676ddd71e7308ae7461c62896d Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 25 Nov 2018 16:27:10 +0100 Subject: API: Implement nvim_win_set_buf() #9100 closes #9100 --- src/nvim/api/window.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'src') 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 -- cgit From 271c5df41603f5427540082a3f8790bca0fd7595 Mon Sep 17 00:00:00 2001 From: Marvim the Paranoid Android Date: Mon, 26 Nov 2018 00:29:21 +0100 Subject: version.c: update [ci skip] (#9171) vim-patch:8.0.0350: not enough test coverage for Perl vim-patch:8.0.1135: W_WINCOL() is always the same vim-patch:8.0.1280: Python None cannot be converted to a Vim type vim-patch:8.0.1308: the "Reading from stdin" message may be undesired vim-patch:8.0.1338: USE_IM_CONTROL is confusing and incomplete vim-patch:8.0.1343: MS-Windows: does not show colored emojis vim-patch:8.0.1350: cannot build with +eval and -multi_byte vim-patch:8.0.1829: MS-Windows: script for vimdiff can't handle ! chars vim-patch:8.0.1849: compiler warning for unused arguments, missing prototype vim-patch:8.1.0001: the netrw plugin does not work vim-patch:8.1.0006: syn_id2cterm_bg() may be undefined vim-patch:8.1.0012: misplaced #endif vim-patch:8.1.0021: clang warns for undefined behavior vim-patch:8.1.0041: attribute "width" missing from python window attribute list vim-patch:8.1.0051: MS-Windows: missing #endif vim-patch:8.1.0063: Mac: NSStringPboardType is deprecated vim-patch:8.1.0075: no Vim logo in README file vim-patch:8.1.0077: header of README file is not nice vim-patch:8.1.0079: superfluous space in messages vim-patch:8.1.0102: cannot build without syntax highlighting vim-patch:8.1.0104: can't build without the +eval feature vim-patch:8.1.0109: new po makefile missing from distribution vim-patch:8.1.0117: URL in install program still points to SourceForge vim-patch:8.1.0122: translators don't always understand the maintainer message vim-patch:8.1.0123: MS-Windows: colors are wrong after setting 'notgc' vim-patch:8.1.0124: has('vcon') returns true even for non-win32 terminal vim-patch:8.1.0127: build failure when disabling the session feature vim-patch:8.1.0128: building with MinGW does not work out-of-the-box vim-patch:8.1.0129: still some xterm-like terminals get a stray "p" vim-patch:8.1.0137: CI does not run with TCL vim-patch:8.1.0142: xterm and vt320 builtin termcap missing keypad keys vim-patch:8.1.0147: compiler warning when building with Python 3.7 vim-patch:8.1.0148: memory leak when using :tcl expr command vim-patch:8.1.0150: insufficient test coverage for Tcl vim-patch:8.1.0152: cannot easily run individual tests on MS-Windows vim-patch:8.1.0153: build with SHADOWDIR fails vim-patch:8.1.0155: evim.man missing from the distribution vim-patch:8.1.0157: old iTerm2 is not recognized, resulting in stray output vim-patch:8.1.0160: no Danish manual translations vim-patch:8.1.0162: Danish and German man pages are not installed vim-patch:8.1.0163: insufficient testing for Tcl vim-patch:8.1.0173: compiler warning on MS-Windows vim-patch:8.1.0176: overlapping string argument for strcpy() vim-patch:8.1.0178: warning for passing pointer to non-pointer argument vim-patch:8.1.0179: redundant condition for boundary check vim-patch:8.1.0180: static analysis errors in Lua interface vim-patch:8.1.0183: Lua API changed, breaking the build vim-patch:8.1.0185: running tests writes lua.vim even though it is not used vim-patch:8.1.0190: Perl refcounts are wrong vim-patch:8.1.0191: Perl test fails in 24 line terminal vim-patch:8.1.0197: Windows GUI: title for search/replace is wrong vim-patch:8.1.0201: newer Python uses "importlib" instead of "imp" vim-patch:8.1.0202: :version always shows +packages vim-patch:8.1.0203: building with Perl 5.28 fails on Windows vim-patch:8.1.0207: need many menu translation files to cover regions vim-patch:8.1.0209: stderr output from Ruby messes up display vim-patch:8.1.0215: no error if configure --with-x cannot configure X vim-patch:8.1.0217: compiler warning for variable set but not used vim-patch:8.1.0222: errors are reported for "make install" vim-patch:8.1.0232: Ruby error does not include backtrace vim-patch:8.1.0234: incorrect reference counting in Perl interface vim-patch:8.1.0236: Ruby build fails when ruby_intern is missing vim-patch:8.1.0237: Ruby on Cygwin doesn't always work vim-patch:8.1.0239: now Ruby build fails on other systems vim-patch:8.1.0246: build failure without the +eval feature vim-patch:8.1.0247: Python: error message for failing import is incorrect vim-patch:8.1.0249: GTK: when screen DPI changes Vim does not handle it vim-patch:8.1.0250: MS-Windows using VTP: windows size change incorrect vim-patch:8.1.0254: cannot build on MS-Windows; unused macro HAVE_HANDLE_DROP vim-patch:8.1.0260: no LGTM logo in README file vim-patch:8.1.0287: MAX is not defined everywhere vim-patch:8.1.0292: MS-Windows: the text "self-installing" confuses some users vim-patch:8.1.0301: GTK: input method popup displayed on wrong screen. vim-patch:8.1.0305: missing support for Lua 5.4 32 bits on Unix vim-patch:8.1.0319: bzero() function prototype doesn't work for Android vim-patch:8.1.0332: get Gdk-Critical error on first balloon show vim-patch:8.1.0346: building with Aap is outdated and unused vim-patch:8.1.0348: on Travis the slowest build is run last vim-patch:8.1.0357: instructions for tests are outdated vim-patch:8.1.0368: GTK code has too many #ifdefs and GTK 2.10 building fails vim-patch:8.1.0379: build dependencies are incomplete vim-patch:8.1.0380: "make proto" doesn't work well vim-patch:8.1.0383: missing source file rename vim-patch:8.1.0385: Coveralls badge doesn't update vim-patch:8.1.0386: cannot test with non-default option value vim-patch:8.1.0388: Coverity complains about possible NULL pointer use vim-patch:8.1.0390: scrollbars are not tested vim-patch:8.1.0391: building in a shadow directory fails vim-patch:8.1.0403: header file missing from distribution vim-patch:8.1.0405: too many #ifdefs for GTK vim-patch:8.1.0408: MSVC: cannot use the "x64" native compiler option vim-patch:8.1.0411: renamed file missing from distribution vim-patch:8.1.0412: cannot build with GTK 2.4 vim-patch:8.1.0413: test output is duplicated or missing vim-patch:8.1.0415: not actually using 16 colors with vtp vim-patch:8.1.0418: MS-Windows: cannot separate Lua include and library dirs vim-patch:8.1.0419: Cygwin: running cproto fails with -O2 vim-patch:8.1.0420: generating vim.lib when using ActivePerl 5.20.3 or later vim-patch:8.1.0421: MS-Windows: Ruby path is wrong for Ruby 1.9 and later vim-patch:8.1.0422: cannot create map file with MinGW vim-patch:8.1.0427: MS-Windows GUI: using invalid encoded file name vim-patch:8.1.0441: build failure without command line history vim-patch:8.1.0467: cannot build with Mac OS X 10.5 vim-patch:8.1.0472: dosinst command has a few flaws vim-patch:8.1.0474: directory where if_perl.c is written is inconsistent vim-patch:8.1.0477: tiny build fails vim-patch:8.1.0478: cannot build with perl using MinGW vim-patch:8.1.0480: MinGW build file uses different -I flags than MVC vim-patch:8.1.0482: MinGW "make clean" deletes all .exe files vim-patch:8.1.0483: MinGW does not build tee.exe vim-patch:8.1.0490: MS-Windows: doesn't handle missing glibwinpthread-1.dll vim-patch:8.1.0492: "Edit with existing Vim" list can get long vim-patch:8.1.0500: cleaning up in src/tee may not always work vim-patch:8.1.0521: cannot build with +eval but without +quickfix vim-patch:8.1.0534: MS-Windows installer uses different $HOME than Vim vim-patch:8.1.0541: help message in dosinst.c is outdated vim-patch:8.1.0485: term_start() does not check if directory is accessible #9204 --- src/nvim/version.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/nvim/version.c b/src/nvim/version.c index beb65a8bfd..d23a007109 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, -- cgit From a2d03d9b1acc922e6fe1d7a9bae14027271ae7a6 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Mon, 26 Nov 2018 01:26:07 +0100 Subject: refactor: Rename get_term_attr_entry Rename get_term_attr_entry to hl_get_term_attr, similar to hl_get_syn_attr, hl_get_ui_attr. --- src/nvim/highlight.c | 2 +- src/nvim/terminal.c | 2 +- src/nvim/ui_bridge.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c index a104137d9e..ae2b90d8a1 100644 --- a/src/nvim/highlight.c +++ b/src/nvim/highlight.c @@ -178,7 +178,7 @@ void update_window_hl(win_T *wp, bool invalid) } /// 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/terminal.c b/src/nvim/terminal.c index d831979022..07722c68ac 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -603,7 +603,7 @@ 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, diff --git a/src/nvim/ui_bridge.c b/src/nvim/ui_bridge.c index ebd4651f4d..eb592694e6 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; -- cgit From 3283db4ecbe32c6f2bbf1c7ea3032ef4091d5444 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Fri, 21 Sep 2018 21:51:49 +0200 Subject: diff/highlight: do not overlay low-priority CursorLine ref #6380 --- src/nvim/highlight_defs.h | 6 +++--- src/nvim/screen.c | 5 +++-- src/nvim/syntax.c | 1 + 3 files changed, 7 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/nvim/highlight_defs.h b/src/nvim/highlight_defs.h index 0790793c94..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; @@ -83,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/screen.c b/src/nvim/screen.c index 1de5e5cc3d..2a1dae1767 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -2826,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 @@ -3052,7 +3052,8 @@ win_line ( diff_hlf = HLF_CHD; // changed line } line_attr = win_hl_attr(wp, diff_hlf); - if (wp->w_p_cul && lnum == wp->w_cursor.lnum) { + // Overlay CursorLine onto diff highlight, unless it's low-priority. + if (!line_attr_lowprio && wp->w_p_cul && lnum == wp->w_cursor.lnum) { line_attr = hl_combine_attr(line_attr, win_hl_attr(wp, HLF_CUL)); } } diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 22eabc75c1..2cade9f281 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 -- cgit From 60f845ca55a1b8b11a4eb390b1fed93a79e99ad5 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Wed, 31 Oct 2018 20:24:24 +0100 Subject: diff/highlight: Show underline for low-priority CursorLine --- src/nvim/highlight.c | 18 ++++++++++++++++++ src/nvim/screen.c | 10 +++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c index ae2b90d8a1..89a41e73de 100644 --- a/src/nvim/highlight.c +++ b/src/nvim/highlight.c @@ -177,6 +177,24 @@ 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 = 0, + .rgb_bg_color = 0, + }, + .kind = kHlUI, + .id1 = 0, + .id2 = 0, + }); +} + /// Get attribute code for forwarded :terminal highlights. int hl_get_term_attr(HlAttrs *aep) { diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 2a1dae1767..eb24e2af1c 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -3052,9 +3052,13 @@ win_line ( diff_hlf = HLF_CHD; // changed line } line_attr = win_hl_attr(wp, diff_hlf); - // Overlay CursorLine onto diff highlight, unless it's low-priority. - if (!line_attr_lowprio && wp->w_p_cul && lnum == wp->w_cursor.lnum) { - line_attr = hl_combine_attr(line_attr, win_hl_attr(wp, HLF_CUL)); + // Overlay CursorLine onto diff-mode highlight. + if (wp->w_p_cul && lnum == wp->w_cursor.lnum) { + 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)); } } -- cgit From 7fdb45e0f8b2dfc367067c62e413dd8082d770d5 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Mon, 26 Nov 2018 22:14:18 +0100 Subject: preserve_exit: Ignore SIGHUP closes #9274 ref #9028 If stdin closed then read_error_exit calls preserve_exit. Handling SIGHUP during preserve_exit would cause a premature teardown, and conflicts with e.g. ui_bridge_stop which waits for TUI to teardown. Vim ignores SIGHUP in its prepare_to_exit and getout_preserve_modified routines: /* Ignore SIGHUP, because a dropped connection causes a read error, which * makes Vim exit and then handling SIGHUP causes various reentrance * problems. */ signal(SIGHUP, SIG_IGN); --- src/nvim/misc1.c | 3 +++ src/nvim/ui_bridge.c | 1 + 2 files changed, 4 insertions(+) (limited to 'src') diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c index 4032210213..d8730ea08a 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" @@ -2653,6 +2654,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/ui_bridge.c b/src/nvim/ui_bridge.c index eb592694e6..bd5d37be73 100644 --- a/src/nvim/ui_bridge.c +++ b/src/nvim/ui_bridge.c @@ -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); -- cgit From 3ec5351fd1c9cb44acf9a1f3b81537dc9765b211 Mon Sep 17 00:00:00 2001 From: Sha Liu Date: Tue, 27 Nov 2018 10:30:41 +0800 Subject: fix wrong winnr in getwininfo --- src/nvim/eval.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 9c7af0a87d..a115e60c7d 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -10332,10 +10332,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) { -- cgit From cf631aaed04925d37b7dcd7c30668fa32119da8e Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Wed, 28 Nov 2018 03:23:10 +0100 Subject: diff/highlight: Fix GUI highlight for low-priority CursorLine (#9281) ref #9028 ref 0653ed63a508 --- src/nvim/highlight.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c index 89a41e73de..12764e8059 100644 --- a/src/nvim/highlight.c +++ b/src/nvim/highlight.c @@ -186,8 +186,8 @@ int hl_get_underline(void) .cterm_fg_color = 0, .cterm_bg_color = 0, .rgb_ae_attr = (int16_t)HL_UNDERLINE, - .rgb_fg_color = 0, - .rgb_bg_color = 0, + .rgb_fg_color = -1, + .rgb_bg_color = -1, }, .kind = kHlUI, .id1 = 0, -- cgit From 30857030e848e4a727a889e51d4618ab9b30651f Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Fri, 16 Nov 2018 02:00:04 +0100 Subject: doc - develop.txt is for design/guidelines; architecture/concepts should live elsewhere (currently src/nvim/README.md) - move dev-jargon to intro.txt - replace https://neovim.io/community (deprecated) with https://neovim.io/#chat - avoids CmdlineEnter/Leave https://github.com/vim/vim/issues/2889 --- src/nvim/api/vim.c | 3 +++ src/nvim/version.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 54b27477e0..4da61a30ef 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -743,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) diff --git a/src/nvim/version.c b/src/nvim/version.c index d23a007109..966ecfd719 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -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 if you are new! "), N_("type :checkhealth to optimize Nvim"), -- cgit From 67305ffb5de865f872898c03cbacd189c9e9aa53 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Wed, 29 Mar 2017 17:34:50 +0200 Subject: lint: src/.clang-format Move to top level so that clang-format -style=file can find it regardless of current directory. --- src/.clang-format | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 src/.clang-format (limited to 'src') 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 -- cgit From 98eaf60a98d0dfec9b1addb2c4efb3655c095044 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Tue, 27 Nov 2018 12:18:30 +0100 Subject: TUI: set_underline_color: only support colon form #9279 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes https://github.com/neovim/neovim/issues/9270 --- Background info per egmontkob: https://github.com/neovim/neovim/issues/9270#issuecomment-441979176 For undercurl, the newly invented escape sequence is `4:3` strictly with a colon, as with a semicolon it means single underlined and italic. For colored underline, the newly invented escape sequence `58:...` is meant to follow the pattern of `38` and `48`. [ITU T.416](https://www.itu.int/rec/T-REC-T.416-199303-I/en) § 13.1.8 clearly specifies the colon only as the separator (and the well-known ECMA-48 § 8.3.117 just points to this standard). Using semicolon instead was/is a frequent misinterpretation of this standard, and is commonly used in the wild – for 38 and 48. More and more emulators are catching up and beginning to support colon, in addition to semicolon. Semicolon is pretty fragile; in case an emulator doesn't recognize a sequence (let's say doesn't recognize the new extension of `58`), subsequent numbers are interpreted as other attributes. E.g. if 256-color mode is chosen then the next numeric parameter is `5` which turns on blinking. So, luckily, the standard is the technically better solution, the frequent practice of using semicolons is technically the worse. Therefore the direction we should be going is clear. I believe it's a fair requirement for anyone adopting colored underline to support colons too, and it's a reasonable move from applications to slightly push the world forward, force developers to catch up with the recent changes, that is: 1) recognize and at least ignore colon-delimited parameters even if they aren't supported, 2) recognize and support colon wherever they support the nonstandard semicolon instead. Should you come across any terminal emulator that supports 58 with semicolons but not with colons, I think the cleanest you can do is report a bug against them and ignore the problem; they should fix it. It's yet another common misunderstanding that the truecolor syntax is `38`/`48`/`58` followed by `:2:rrr:ggg:bbb`. The wording of T.416 is terrible, but if you read carefully, there's another parameter of color-space-id preceding the three color channels. Assuming you don't care about color-space-id, the syntax is `38`/`48`/`58` followed by `:2::rrr:ggg:bbb` and of course the trailing `m`. This is only for true-color, the 256-color format doesn't have such a parameter, it's `38`/`48`/`58` followed by `:5:index` and the final `m`. --- src/nvim/tui/tui.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index d2ddd98fd4..6e266408c9 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -1866,13 +1866,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"); } } -- cgit From 5a752c97d5294f4a69613db71adf9beb6a8f8790 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Thu, 29 Nov 2018 01:51:26 +0100 Subject: vim-patch:8.1.0098: segfault when pattern with \z() is very slow (#9283) Problem: Segfault when pattern with \z() is very slow. Solution: Check for NULL regprog. Add "nfa_fail" to test_override() to be able to test this. Fix that 'searchhl' resets called_emsg. https://github.com/vim/vim/commit/bcf9442307075bac40d44328c8bf7ea21857b138 closes #8788 --- src/nvim/regexp.c | 27 +++++++++++++++------------ src/nvim/regexp.h | 21 +++++++++++---------- src/nvim/regexp_nfa.c | 24 ++++++++++++++---------- src/nvim/screen.c | 4 ++++ src/nvim/syntax.c | 7 +++++++ src/nvim/testdir/test_syntax.vim | 12 ++++++++++++ 6 files changed, 63 insertions(+), 32 deletions(-) (limited to 'src') 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 eb24e2af1c..e4485b4e2e 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -5603,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: @@ -5695,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; } } diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 2cade9f281..973d09d065 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -2894,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/testdir/test_syntax.vim b/src/nvim/testdir/test_syntax.vim index e35c0f1105..e70d9b7c66 100644 --- a/src/nvim/testdir/test_syntax.vim +++ b/src/nvim/testdir/test_syntax.vim @@ -482,3 +482,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 -- cgit From 32405de7df965174f0aad19692b8d988bae83a44 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Thu, 29 Nov 2018 15:08:40 +0100 Subject: API: rename nvim_buf_clear_highlight to nvim_buf_clear_namespace We want a single function to clear all namespaced buffer objects. This will later include extmarks. --- src/nvim/api/buffer.c | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 4559f37191..29c8ea634a 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -913,7 +913,7 @@ ArrayOf(Integer, 2) nvim_buf_get_mark(Buffer buffer, String name, Error *err) /// 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_highlight|. If the highlight never will be +/// single call to |nvim_buf_clear_namespace|. If the highlight never will be /// deleted by an API call, pass `ns_id = -1`. /// /// As a shorthand, `ns_id = 0` can be used to create a new namespace for the @@ -967,23 +967,23 @@ Integer nvim_buf_add_highlight(Buffer buffer, 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 ns_id Namespace 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, +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) { @@ -1001,6 +1001,26 @@ void nvim_buf_clear_highlight(Buffer buffer, 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); +} + /// Set the virtual text (annotation) for a buffer line. /// @@ -1012,10 +1032,10 @@ void nvim_buf_clear_highlight(Buffer buffer, /// /// 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_highlight|. The same `ns_id` can be used for +/// 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_highlight|. If the -/// virtual text never will be cleared by an API call, pass `src_id = -1`. +/// 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`. /// /// As a shorthand, `ns_id = 0` can be used to create a new namespace for the /// virtual text, the allocated id is then returned. -- cgit From b0ebf61d37ccae3c480834d2ac1b5559e7e3d20d Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Fri, 30 Nov 2018 05:25:20 +0100 Subject: test: adjust time-sensitive tests From test_alot.vim: Found errors in Test_lambda_with_timer(): First run: function RunTheTest[35]..Test_lambda_with_timer line 19: Expected True but got 0 Second run: function RunTheTest[35]..Test_lambda_with_timer line 19: Expected True but got 0 previously: #9220 - Timer tests are less reliable on Travis CI macOS 10.12/10.13. ref #6829 ref e39dade80b02 ref de13113dc16e ref https://github.com/neovim/neovim/pull/9095#issuecomment-429603452 > We don't guarantee that a X ms timer is triggered during Y ms sleep > for any X to happen with X=10ms, Y=40ms. - Call test_garbagecollect_now(), as Vim does. --- src/nvim/testdir/test_lambda.vim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/testdir/test_lambda.vim b/src/nvim/testdir/test_lambda.vim index 2ac84c2213..6e07c874b4 100644 --- a/src/nvim/testdir/test_lambda.vim +++ b/src/nvim/testdir/test_lambda.vim @@ -33,9 +33,9 @@ function! Test_lambda_with_timer() call s:Foo() sleep 210ms " do not collect lambda - call garbagecollect() + call test_garbagecollect_now() let m = s:n - sleep 210ms + sleep 230ms call timer_stop(s:timer_id) call assert_true(m > 1) call assert_true(s:n > m + 1) -- cgit From 32a30d90b460048a43490a16d2e006d0e39b0e38 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Fri, 30 Nov 2018 21:13:01 +0100 Subject: highlight: Fix missing .rgb_sp_color in initializers (#9287) terminal_get_line_attributes() had this bug for a long time, though it likely had no effect visible to users. ref #9028 ref 60f845ca55a1 --- src/nvim/highlight.c | 1 + src/nvim/terminal.c | 1 + 2 files changed, 2 insertions(+) (limited to 'src') diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c index 12764e8059..5a9727f46e 100644 --- a/src/nvim/highlight.c +++ b/src/nvim/highlight.c @@ -188,6 +188,7 @@ int hl_get_underline(void) .rgb_ae_attr = (int16_t)HL_UNDERLINE, .rgb_fg_color = -1, .rgb_bg_color = -1, + .rgb_sp_color = -1, }, .kind = kHlUI, .id1 = 0, diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index 07722c68ac..f715344689 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -610,6 +610,7 @@ void terminal_get_line_attributes(Terminal *term, win_T *wp, int linenr, .rgb_ae_attr = (int16_t)hl_attrs, .rgb_fg_color = vt_fg, .rgb_bg_color = vt_bg, + .rgb_sp_color = -1, }); } -- cgit From 0ce880083d1faeebaecd393fc28e443b19862540 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Fri, 30 Nov 2018 22:21:26 +0100 Subject: test/macOS: adjust time-sensitive tests From test_timers.vim: Found errors in Test_paused(): First run: function RunTheTest[35]..Test_paused line 20: Expected range 0 - 100, but got 123 Second run: function RunTheTest[35]..Test_paused line 20: Expected range 0 - 100, but got 106 previously: #9220 - Timer tests are less reliable on Travis CI macOS 10.12/10.13. ref #6829 ref e39dade80b02 ref de13113dc16e ref https://github.com/neovim/neovim/pull/9095#issuecomment-429603452 > We don't guarantee that a X ms timer is triggered during Y ms sleep > for any X to happen with X=10ms, Y=40ms. --- src/nvim/testdir/test_timers.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/testdir/test_timers.vim b/src/nvim/testdir/test_timers.vim index 8a3e57bb02..cdfdd473b9 100644 --- a/src/nvim/testdir/test_timers.vim +++ b/src/nvim/testdir/test_timers.vim @@ -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 -- cgit From a9e368a7050c86dff36d80dc1cced21de14dd3ac Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Fri, 30 Nov 2018 22:43:08 -0500 Subject: vim-patch:8.1.0553: it is not easy to edit a script that was sourced (#9298) Problem: It is not easy to edit a script that was sourced. Solution: Add a count to ":scriptnames", so that ":script 40" edits the script with script ID 40. https://github.com/vim/vim/commit/07dc18ffa4e7ed202f219fe2fd3d6f58246f71f9 --- src/nvim/ex_cmds.lua | 22 +++++++++++----------- src/nvim/ex_cmds2.c | 11 +++++++++++ src/nvim/testdir/test_scriptnames.vim | 26 ++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 11 deletions(-) create mode 100644 src/nvim/testdir/test_scriptnames.vim (limited to 'src') diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua index df1aa938ed..d9212aa4e3 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 { @@ -2326,8 +2326,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', }, { diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index a148f51527..76c71a00ec 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, 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('\', 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 -- cgit From 5de5507ea6877c7ca6054242caa2cb330969db5d Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Thu, 29 Nov 2018 21:12:24 -0500 Subject: vim-patch:8.1.0550: expression evaluation may repeat an error message Problem: Expression evaluation may repeat an error message. (Jason Franklin) Solution: Increment did_emsg and check for the value when giving an error for the echo command. https://github.com/vim/vim/commit/76a6345433bc2a600689397fb28165a2e5793720 --- src/nvim/eval.c | 3 ++- src/nvim/message.c | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index a115e60c7d..3cb0e65701 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -19538,6 +19538,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; @@ -19552,7 +19553,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; diff --git a/src/nvim/message.c b/src/nvim/message.c index 10f4905fb2..37828f7ad3 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 -- cgit From f59ba0fad0a41951f6ebc427a06b336a5038e5d7 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Thu, 29 Nov 2018 21:19:02 -0500 Subject: vim-patch:8.1.0551: expression evaluation may repeat an error message Problem: Expression evaluation may repeat an error message. (Jason Franklin) Solution: Check for the value of did_emsg when giving an error for the :execute command. https://github.com/vim/vim/commit/8ff5af9544a2abc3d344bba017ef96682e098d9d --- src/nvim/eval.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 3cb0e65701..5d2bdc210b 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -19642,7 +19642,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); @@ -19656,8 +19656,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; } -- cgit From 2271b10a8e890f24d38caa7e8199ba3b83164872 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sat, 1 Dec 2018 10:35:45 +0100 Subject: insert: make mapping work in completion (CTRL-X) mode --- src/nvim/edit.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 451d19b8e3..c04190eaba 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -3195,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; } -- cgit From 0f00f31cbd9b13b41a0d3d976d192bbbeac9cbe8 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sat, 1 Dec 2018 02:41:31 +0100 Subject: VimL/confirm(): Show dialog even if :silent closes #8788 related #9034 --- src/nvim/message.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/message.c b/src/nvim/message.c index 10f4905fb2..26fa8fc7f1 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -2825,7 +2825,6 @@ do_dialog ( Ex command */ ) { - int oldState; int retval = 0; char_u *hotkeys; int c; @@ -2838,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(); @@ -2891,6 +2893,7 @@ do_dialog ( xfree(hotkeys); + msg_silent = save_msg_silent; State = oldState; setmouse(); --no_wait_return; -- cgit From 8b42249cddf6b257e2eee808a41f3d6dd5af6846 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sat, 1 Dec 2018 16:44:36 +0100 Subject: RPC: turn errors from async calls into notifications Previously, nvim sent a response with invalid request id (UINT64_MAX). In functionaltests, catch unexpected error notifications in after_each(). --- src/nvim/msgpack_rpc/channel.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'src') 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, -- cgit From abd32c1bb8c01725291a8de2a691b89ee7050012 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Mon, 3 Dec 2018 22:46:11 -0500 Subject: vim-patch:8.1.0559: command line completion not sufficiently tested Problem: Command line completion not sufficiently tested. Solution: Add more tests. (Dominique Pelle, closes vim/vim#3622) https://github.com/vim/vim/commit/b513d3079bbe3f59a1f1a3d6931939a76cd7e54a --- src/nvim/testdir/test_arglist.vim | 12 ++++++++++++ src/nvim/testdir/test_filetype.vim | 4 ++++ src/nvim/testdir/test_history.vim | 5 +++++ src/nvim/testdir/test_messages.vim | 5 +++++ src/nvim/testdir/test_syntax.vim | 9 +++++++++ 5 files changed, 35 insertions(+) (limited to 'src') 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 \\\"\", 'tx') + call assert_equal('"argdelete bar foo', @:) + + call feedkeys(":argdelete x \\\"\", '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_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\\\"\", 'tx') + call assert_equal('"setfiletype java javacc javascript', @:) +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 \\\"\", 'tx') + call assert_equal('"history / : = > ? @ all cmd debug expr input search', @:) +endfunc 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 \\\"\", 'tx') + call assert_equal('"message clear', @:) +endfunc diff --git a/src/nvim/testdir/test_syntax.vim b/src/nvim/testdir/test_syntax.vim index e70d9b7c66..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 \\\"\", 'tx') + call assert_equal('"syntime clear off on report', @:) +endfunc + func Test_syntax_list() syntax on let a = execute('syntax list') -- cgit From f1ce9b3be2ea1e9e1dc5c6206bc441b310feb28b Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Wed, 5 Dec 2018 10:50:38 +0100 Subject: screen: add missing status redraw when redraw_later(CLEAR) was used --- src/nvim/screen.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/screen.c b/src/nvim/screen.c index e4485b4e2e..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; } -- cgit From 769762834533292e1d6a34b3846213d3896dc386 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Wed, 5 Dec 2018 19:14:19 -0500 Subject: vim-patch:8.0.1425: execute() does not work in completion of user command (#9317) Problem: execute() does not work in completion of user command. (thinca) Solution: Switch off redir_off and restore it. (Ozaki Kiichi, closes vim/vim#2492) https://github.com/vim/vim/commit/2095148277cf1c4e7b3bbaf4e34812b7cfe3011b --- src/nvim/eval.c | 3 +++ src/nvim/testdir/test_usercommands.vim | 12 ++++++++++++ 2 files changed, 15 insertions(+) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 5d2bdc210b..fac56e9206 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -8125,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()) { @@ -8152,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])); @@ -8169,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; 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 \', '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 \\\"\", 'tx') + call assert_equal('"DoExec hi', @:) + delcommand DoExec +endfunc -- cgit From 4c4997e988e506050563805541322ece396a0368 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Thu, 6 Dec 2018 23:20:28 -0500 Subject: vim-patch:8.1.0563: setting v:errors to a string give confusing error Problem: Setting v:errors to a string give confusing error. (Christian Brabandt) Solution: Change internal error into normal error message. https://github.com/vim/vim/commit/74ea88c170f65afa50b2b97e37806d13b4e24cd7 --- src/nvim/eval.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index fac56e9206..a5d79bcd4a 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -19253,7 +19253,7 @@ 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); } } -- cgit From f17700544707160fb9588f37d1f3daef4f7bc483 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Thu, 6 Dec 2018 23:21:56 -0500 Subject: vim-patch:8.1.0564: setting v:errors to wrong type still possible Problem: Setting v:errors to wrong type still possible. Solution: Return after giving an error message. (Christian Brabandt) https://github.com/vim/vim/commit/88b53fd0521d1e62df17a8a1f2181425e9d4854c --- src/nvim/eval.c | 1 + src/nvim/testdir/test_eval_stuff.vim | 10 ++++++++++ 2 files changed, 11 insertions(+) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index a5d79bcd4a..cd29e4ef19 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -19254,6 +19254,7 @@ 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) { EMSG2(_("E963: setting %s to value with wrong type"), name); + return; } } 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 -- cgit From b4a04fd80c4a223a80257ca1670e1907a6a95fdd Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Fri, 7 Dec 2018 17:28:51 +0100 Subject: api: make nvim_buf_set_virtual_text use correct namespace counter --- src/nvim/buffer.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 634e257d40..8b107041b1 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -5396,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); -- cgit From f1eb25f0c45d7612d495f2cbd43a29da294d5325 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sat, 8 Dec 2018 08:21:49 -0500 Subject: vim-patch:8.1.0570: 'commentstring' not used when adding fold marker (#9331) Problem: 'commentstring' not used when adding fold marker. (Maxim Kim) Solution: Only use empty 'comments' middle when leader is empty. (Christian Brabandt, closes vim/vim#3670) https://github.com/vim/vim/commit/539328197c51c1586cbbb6b6be3db3c412249b49 --- src/nvim/misc1.c | 20 ++++++++++++++++++-- src/nvim/testdir/test_fold.vim | 17 +++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c index d8730ea08a..d4a406cdba 100644 --- a/src/nvim/misc1.c +++ b/src/nvim/misc1.c @@ -1099,6 +1099,7 @@ int get_last_leader_offset(char_u *line, char_u **flags) found_one = FALSE; for (list = curbuf->b_p_com; *list; ) { char_u *flags_save = list; + bool is_only_whitespace = false; /* * Get one option part into part_buf[]. Advance list to next one. @@ -1122,8 +1123,12 @@ 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++; + } + if (*string == NUL) { + is_only_whitespace = true; + } } for (j = 0; string[j] != NUL && string[j] == line[i + j]; ++j) /* do nothing */; @@ -1139,6 +1144,17 @@ int get_last_leader_offset(char_u *line, char_u **flags) continue; } + // For a middlepart comment that is only white space, only consider + // it to match if everything before the current position in the + // line is also whitespace. + if (is_only_whitespace && vim_strchr(part_buf, COM_MIDDLE) != NULL) { + for (j = 0; ascii_iswhite(line[j]) && j <= i; j++) { + } + if (j < i) { + continue; + } + } + /* * We have found a match, stop searching. */ diff --git a/src/nvim/testdir/test_fold.vim b/src/nvim/testdir/test_fold.vim index b6a545f959..85f58ada7e 100644 --- a/src/nvim/testdir/test_fold.vim +++ b/src/nvim/testdir/test_fold.vim @@ -674,3 +674,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= + setl comments=s: + 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 -- cgit From 857a7312d015350c9637548310c7a187637d3ca4 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 9 Dec 2018 01:31:34 +0100 Subject: doc (#9288) - misc - doc: `:help config`. closes #9329 - cleanup test/README.md --- src/nvim/api/buffer.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 29c8ea634a..5df0f0bb47 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -1027,8 +1027,7 @@ 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 -- cgit From 67c5bc1ac082236c0a36c785619987b9462aa89a Mon Sep 17 00:00:00 2001 From: Anatolii Sakhnik Date: Tue, 4 Dec 2018 21:17:00 +0200 Subject: Calm down the clinter --- src/nvim/buffer_defs.h | 56 +++++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index e86eaf010f..d9befee296 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; @@ -479,7 +479,7 @@ struct file_buffer { * 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). + * 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 */ @@ -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") */ @@ -916,9 +916,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 +926,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 +1036,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 -- cgit From cf1ffa91667a482c6355f5999b9e97ccc0b4126a Mon Sep 17 00:00:00 2001 From: Anatolii Sakhnik Date: Sun, 2 Dec 2018 22:58:07 +0200 Subject: vim-patch:8.1.0360: using an external diff program is slow and inflexible Problem: Using an external diff program is slow and inflexible. Solution: Include the xdiff library. (Christian Brabandt) Use it by default. https://github.com/vim/vim/commit/e828b7621cf9065a3582be0c4dd1e0e846e335bf vim-patch:8.1.0360 vim-patch:8.1.0364 vim-patch:8.1.0366 vim-patch:8.1.0370 vim-patch:8.1.0377 vim-patch:8.1.0378 vim-patch:8.1.0381 vim-patch:8.1.0396 vim-patch:8.1.0432 --- src/nvim/CMakeLists.txt | 9 +- src/nvim/buffer_defs.h | 2 + src/nvim/diff.c | 831 ++++++++++++++++++++-------- src/nvim/fileio.c | 4 +- src/nvim/globals.h | 3 +- src/nvim/options.lua | 2 +- src/nvim/testdir/test_diffmode.vim | 105 +++- src/nvim/xdiff/COPYING | 504 +++++++++++++++++ src/nvim/xdiff/README.txt | 16 + src/nvim/xdiff/xdiff.h | 143 +++++ src/nvim/xdiff/xdiffi.c | 1043 ++++++++++++++++++++++++++++++++++++ src/nvim/xdiff/xdiffi.h | 64 +++ src/nvim/xdiff/xemit.c | 332 ++++++++++++ src/nvim/xdiff/xemit.h | 36 ++ src/nvim/xdiff/xhistogram.c | 386 +++++++++++++ src/nvim/xdiff/xinclude.h | 61 +++ src/nvim/xdiff/xmacros.h | 54 ++ src/nvim/xdiff/xpatience.c | 393 ++++++++++++++ src/nvim/xdiff/xprepare.c | 483 +++++++++++++++++ src/nvim/xdiff/xprepare.h | 34 ++ src/nvim/xdiff/xtypes.h | 67 +++ src/nvim/xdiff/xutils.c | 425 +++++++++++++++ src/nvim/xdiff/xutils.h | 47 ++ 23 files changed, 4809 insertions(+), 235 deletions(-) create mode 100644 src/nvim/xdiff/COPYING create mode 100644 src/nvim/xdiff/README.txt create mode 100644 src/nvim/xdiff/xdiff.h create mode 100644 src/nvim/xdiff/xdiffi.c create mode 100644 src/nvim/xdiff/xdiffi.h create mode 100644 src/nvim/xdiff/xemit.c create mode 100644 src/nvim/xdiff/xemit.h create mode 100644 src/nvim/xdiff/xhistogram.c create mode 100644 src/nvim/xdiff/xinclude.h create mode 100644 src/nvim/xdiff/xmacros.h create mode 100644 src/nvim/xdiff/xpatience.c create mode 100644 src/nvim/xdiff/xprepare.c create mode 100644 src/nvim/xdiff/xprepare.h create mode 100644 src/nvim/xdiff/xtypes.h create mode 100644 src/nvim/xdiff/xutils.c create mode 100644 src/nvim/xdiff/xutils.h (limited to 'src') diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index 29a4e1e163..e4505f7484 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 @@ -155,6 +157,8 @@ foreach(sfile ${CONV_SOURCES}) endif() endforeach() +list(APPEND CONV_SOURCES ${XDIFF_SOURCES}) + if(NOT MSVC) set_source_files_properties( ${CONV_SOURCES} PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-conversion") @@ -404,7 +408,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 +495,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 +520,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/buffer_defs.h b/src/nvim/buffer_defs.h index d9befee296..238893260e 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -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 }; /* diff --git a/src/nvim/diff.c b/src/nvim/diff.c index 4bfe67c9d3..c3eb2465bd 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 #include #include "nvim/vim.h" +#include "xdiff/xdiff.h" #include "nvim/ascii.h" #include "nvim/diff.h" #include "nvim/buffer.h" @@ -36,16 +42,19 @@ #include "nvim/os/os.h" #include "nvim/os/shell.h" -static int diff_busy = FALSE; // ex_diffgetput() is busy +static int diff_busy = false; // ex_diffgetput() is busy // 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 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 +#define DIFF_INTERNAL 64 // use internal xdiff algorithm +static int diff_flags = DIFF_INTERNAL | DIFF_FILLER; + +static long diff_algorithm = 0; #define LBUFLEN 50 // length of line in diff file @@ -53,6 +62,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 +96,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 +126,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 +155,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 +220,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); } } } @@ -293,14 +321,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 +344,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 +369,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 +389,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 +408,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 +475,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 +547,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 +566,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,30 +640,224 @@ 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); } } } -/// Write buffer "buf" to file "name". +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 += 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 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. +/// +static 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. @@ -647,7 +869,7 @@ void ex_diffupdate(exarg_T *eap) { // 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; @@ -673,46 +895,61 @@ void ex_diffupdate(exarg_T *eap) return; } - // 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); } - // 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. + // force updating cursor position on screen + curwin->w_valid_cursor.lnum = 0; + + diff_redraw(true); +} + +/// +/// 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 +965,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,80 +994,77 @@ void ex_diffupdate(exarg_T *eap) } EMSG(_("E97: Cannot create diffs")); diff_a_works = kNone; - goto theend; + return FAIL; } + return OK; +} - // :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); - } - } - } +/// +/// Invoke the xdiff function. +/// +static int diff_file_internal(diffio_T *diffio) +{ + xpparam_t param; + xdemitconf_t emit_cfg; + xdemitcb_t emit_cb; - // 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; - } + memset(¶m, 0, sizeof(param)); + memset(&emit_cfg, 0, sizeof(emit_cfg)); + memset(&emit_cb, 0, sizeof(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 - } + param.flags = diff_algorithm; - if (diff_write(buf, (char_u *) tmp_new) == FAIL) { - continue; - } - diff_file(tmp_orig, tmp_new, tmp_diff); - - // 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; } - 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, + ¶m, &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", diff_a_works == kFalse ? "" : "-a ", "", (diff_flags & DIFF_IWHITE) ? "-b " : "", @@ -843,6 +1077,7 @@ static void diff_file(const char *const tmp_orig, const char *const tmp_new, NULL); unblock_autocmds(); xfree(cmd); + return OK; } } @@ -876,7 +1111,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 +1142,7 @@ void ex_diffpatch(exarg_T *eap) tempdir = "/tmp"; } os_chdir(tempdir); - shorten_fnames(TRUE); + shorten_fnames(true); } #endif @@ -934,7 +1169,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 +1206,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 +1260,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 +1287,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 +1320,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 +1351,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 +1446,93 @@ 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; + } } - 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 +1544,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 +1631,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 +1641,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 +1745,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 +1785,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; @@ -1815,6 +2057,7 @@ int diffopt_changed(void) int diff_context_new = 6; int diff_flags_new = 0; int diff_foldcolumn_new = 2; + long diff_algorithm_new = 0; char_u *p = p_dip; while (*p != NUL) { @@ -1842,6 +2085,27 @@ 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_algorithm_new |= 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; + } } if ((*p != ',') && (*p != NUL)) { @@ -1859,17 +2123,18 @@ int diffopt_changed(void) } // If "icase" or "iwhite" was added or removed, need to update the diff. - if (diff_flags != diff_flags_new) { + 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 +2175,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,7 +2207,7 @@ 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; @@ -2117,7 +2382,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 +2403,7 @@ void ex_diffgetput(exarg_T *eap) || MODIFIABLE(curtab->tp_diffbuf[idx_other])) { break; } - found_not_ma = TRUE; + found_not_ma = true; } } @@ -2176,7 +2441,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 +2467,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) { @@ -2308,7 +2573,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 +2582,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,12 +2664,12 @@ 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; + diff_busy = false; // Check that the cursor is on a valid character and update it's position. // When there were filler lines the topline has become invalid. @@ -2412,7 +2677,7 @@ void ex_diffgetput(exarg_T *eap) changed_line_abv_curs(); // Also need to redraw the other buffers. - diff_redraw(FALSE); + diff_redraw(false); } /// Update folds for all diff buffers for entry "dp". @@ -2637,3 +2902,143 @@ 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; + int i; + char_u *p; + + for (i = 0; i < nbuf; i++) { + // We are only interested in the header lines, skip text lines. + if (STRNCMP(mb[i].ptr, "@@ ", 3) != 0) { + continue; + } + ga_grow(&dout->dout_ga, 1); + p = vim_strnsave((char_u *)mb[i].ptr, mb[i].size); + if (p == NULL) { + return -1; + } + ((char_u **)dout->dout_ga.ga_data)[dout->dout_ga.ga_len++] = p; + } + return 0; +} diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 7e8a7d1a35..8e5455bc67 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 } 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/options.lua b/src/nvim/options.lua index b0575df7ec..0cc6f58c5f 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -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/testdir/test_diffmode.vim b/src/nvim/testdir/test_diffmode.vim index afe289b262..3e47b02fc8 100644 --- a/src/nvim/testdir/test_diffmode.vim +++ b/src/nvim/testdir/test_diffmode.vim @@ -33,6 +33,18 @@ func Test_diff_fold_sync() 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 @@ -275,10 +287,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 +310,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 +371,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 +385,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 +399,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 +413,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 +436,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 @@ -523,7 +560,7 @@ func Test_diffpatch() 3 + 4 . - saveas Xpatch + saveas! Xpatch bwipe! new call assert_fails('diffpatch Xpatch', 'E816:') @@ -569,6 +606,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 +668,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/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. + + + Copyright (C) + + 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. + + , 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 + * . + * + * Davide Libenzi + * + */ + +#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 + * . + * + * Davide Libenzi + * + */ + +#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 + * . + * + * Davide Libenzi + * + */ + +#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 + * . + * + * Davide Libenzi + * + */ + +#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 + * . + * + * Davide Libenzi + * + */ + +#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 + * . + * + * Davide Libenzi + * + */ + +/* 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 +#include +#include +#if !defined(_WIN32) +#include +#endif +#include +#include + +#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 + * . + * + * Davide Libenzi + * + */ + +#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 + * . + * + * Davide Libenzi + * + */ +#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 + * . + * + * Davide Libenzi + * + */ + +#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 + * . + * + * Davide Libenzi + * + */ + +#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 + * . + * + * Davide Libenzi + * + */ + +#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 + * . + * + * Davide Libenzi + * + */ + +#include +#include +#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 + * . + * + * Davide Libenzi + * + */ + +#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) */ -- cgit From 72c5a9db70f263eaac12aee140da03190e2fa605 Mon Sep 17 00:00:00 2001 From: Anatolii Sakhnik Date: Sun, 9 Dec 2018 13:50:14 +0200 Subject: vim-patch:8.1.0375: cannot use diff mode with Cygwin diff.exe Problem: Cannot use diff mode with Cygwin diff.exe. (Igor Forca) Solution: Skip over unrecognized lines in the diff output. https://github.com/vim/vim/commit/3b8defd0a52fc1276816608e7bb24b628ab14c2e --- src/nvim/diff.c | 4 ++++ src/nvim/testdir/test_diffmode.vim | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/diff.c b/src/nvim/diff.c index c3eb2465bd..2ad9471046 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -1511,6 +1511,10 @@ static void diff_read(int idx_orig, int idx_new, diffout_T *dout) && (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; } } diff --git a/src/nvim/testdir/test_diffmode.vim b/src/nvim/testdir/test_diffmode.vim index 3e47b02fc8..645a87848b 100644 --- a/src/nvim/testdir/test_diffmode.vim +++ b/src/nvim/testdir/test_diffmode.vim @@ -517,7 +517,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 -- cgit From 972ad1119557a0f72f1907c6758d6ed56438e5b3 Mon Sep 17 00:00:00 2001 From: Anatolii Sakhnik Date: Sun, 9 Dec 2018 15:00:19 +0200 Subject: vim-patch:8.1.0393: not all white space difference options available Problem: Not all white space difference options available. Solution: Add "iblank", "iwhiteall" and "iwhiteeol" to 'diffopt'. https://github.com/vim/vim/commit/785fc6567f572b8caefbc89ec29bbd8b801464ae --- src/nvim/diff.c | 75 +++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 57 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/nvim/diff.c b/src/nvim/diff.c index 2ad9471046..6e034485d9 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -45,13 +45,17 @@ static int diff_busy = false; // ex_diffgetput() is busy // 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 -#define DIFF_INTERNAL 64 // use internal xdiff algorithm +#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; @@ -1017,6 +1021,15 @@ static int diff_file_internal(diffio_T *diffio) 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; + } emit_cfg.ctxlen = 0; // don't need any diff_context here emit_cb.priv = &diffio->dio_diff; @@ -1064,10 +1077,13 @@ static int diff_file(diffio_T *dio) // 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", + 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); @@ -1881,20 +1897,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 { @@ -2071,9 +2095,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; @@ -2217,9 +2250,12 @@ bool diff_find_change(win_T *wp, linenr_T lnum, int *startp, int *endp) 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 { @@ -2249,9 +2285,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--; } -- cgit From 7b6c92eac1b7aa702f734120bdd18b5a4f6cfe04 Mon Sep 17 00:00:00 2001 From: Anatolii Sakhnik Date: Sun, 9 Dec 2018 15:31:22 +0200 Subject: vim-patch:8.1.0394: diffs are not always updated correctly Problem: Diffs are not always updated correctly. Solution: When using internal diff update for any changes properly. https://github.com/vim/vim/commit/e3521d9cbb786806eaff106707851d37d2c0ecef --- src/nvim/buffer_defs.h | 1 + src/nvim/diff.c | 17 +++++++++++++---- src/nvim/misc1.c | 12 ++++++++---- src/nvim/normal.c | 8 ++++++++ 4 files changed, 30 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 238893260e..e8975f0622 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -842,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. diff --git a/src/nvim/diff.c b/src/nvim/diff.c index 6e034485d9..a927983374 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -266,6 +266,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 udpate diffs before redrawing. Set _invalid to update the + // diffs themselves, set _update to also update folds properly just + // before redrawing. + tp->tp_diff_invalid = true; + tp->tp_diff_update = true; + return; + } + int inserted; int deleted; if (line2 == MAXLNUM) { @@ -840,7 +849,7 @@ theend: /// Note that if the internal diff failed for one of the buffers, the external /// diff will be used anyway. /// -static int diff_internal(void) +int diff_internal(void) { return (diff_flags & DIFF_INTERNAL) != 0 && *p_dex == NUL; } @@ -864,9 +873,9 @@ static int diff_internal_failed(void) /// 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) diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c index d4a406cdba..d77c196a3a 100644 --- a/src/nvim/misc1.c +++ b/src/nvim/misc1.c @@ -1953,10 +1953,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) { @@ -2025,6 +2025,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); 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) { -- cgit From b7f2c7dd1d2a5753962c9276df3db8bc5d358b3e Mon Sep 17 00:00:00 2001 From: Anatolii Sakhnik Date: Sun, 9 Dec 2018 19:13:48 +0200 Subject: vim-patch:8.1.0395: compiler warning on 64-bit MS-Windows Problem: Compiler warning on 64-bit MS-Windows. Solution: Add type cast. (Mike Williams) https://github.com/vim/vim/commit/6e272acc82af900318017061f923e7f66dc7ee7a --- src/nvim/diff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/diff.c b/src/nvim/diff.c index a927983374..bd66b32213 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -692,7 +692,7 @@ static int diff_write_buffer(buf_T *buf, diffin_T *din) // xdiff requires one big block of memory with all the text. for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++) { - len += STRLEN(ml_get_buf(buf, lnum, false)) + 1; + len += (long)STRLEN(ml_get_buf(buf, lnum, false)) + 1; } ptr = xmalloc(len); if (ptr == NULL) { -- cgit From 2c92a4d0c8a398c8a7dfd1666fdcfd2ab89cc887 Mon Sep 17 00:00:00 2001 From: Anatolii Sakhnik Date: Sun, 9 Dec 2018 19:26:12 +0200 Subject: vim-patch:8.1.0397: no event triggered after updating diffs Problem: No event triggered after updating diffs. Solution: Add the DiffUpdated event. https://github.com/vim/vim/commit/e8fa05b5bc2d6d76bf5af50176a63655d00d1110 --- src/nvim/auevents.lua | 1 + src/nvim/diff.c | 2 ++ src/nvim/testdir/test_diffmode.vim | 6 ++++++ 3 files changed, 9 insertions(+) (limited to 'src') diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua index a6290aaac1..ab92e84799 100644 --- a/src/nvim/auevents.lua +++ b/src/nvim/auevents.lua @@ -33,6 +33,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/diff.c b/src/nvim/diff.c index bd66b32213..0fb8324546 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -924,6 +924,8 @@ void ex_diffupdate(exarg_T *eap) curwin->w_valid_cursor.lnum = 0; diff_redraw(true); + + apply_autocmds(EVENT_DIFFUPDATED, NULL, NULL, false, curbuf); } /// diff --git a/src/nvim/testdir/test_diffmode.vim b/src/nvim/testdir/test_diffmode.vim index 645a87848b..6f25179ab1 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,6 +30,9 @@ 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 -- cgit From 271249a48a4847929410b9055bdb560e52271919 Mon Sep 17 00:00:00 2001 From: Anatolii Sakhnik Date: Sun, 9 Dec 2018 19:34:20 +0200 Subject: vim-patch:8.1.0400: using freed memory with :diffget Problem: Using freed memory with :diffget. Solution: Skip ex_diffupdate() while updating diffs. (closes #3442) https://github.com/vim/vim/commit/d2b58c0a2c665075a8cfef57db6e1b37d4523e02 --- src/nvim/diff.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/diff.c b/src/nvim/diff.c index 0fb8324546..9ac9b6f6db 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -42,7 +42,8 @@ #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 0x001 // display filler lines @@ -880,6 +881,11 @@ static int diff_internal_failed(void) /// @param eap can be NULL void ex_diffupdate(exarg_T *eap) { + if (diff_busy) { + diff_need_update = true; + return; + } + // Delete all diffblocks. diff_clear(curtab); curtab->tp_diff_invalid = false; @@ -2558,7 +2564,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; } } @@ -2723,7 +2729,12 @@ void ex_diffgetput(exarg_T *eap) aucmd_restbuf(&aco); } +theend: diff_busy = false; + if (diff_need_update) { + diff_need_update = false; + 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. -- cgit From fe0114ec414108d544da73c3147fd67079f6cc2e Mon Sep 17 00:00:00 2001 From: Anatolii Sakhnik Date: Sun, 9 Dec 2018 19:44:58 +0200 Subject: vim-patch:8.1.0402: the DiffUpdate event isn't triggered for :diffput Problem: The DiffUpdate event isn't triggered for :diffput. Solution: Also trigger DiffUpdate for :diffget and :diffput. https://github.com/vim/vim/commit/198fa066b2ec011e91012c1a3d85a73df7b93f31 --- src/nvim/diff.c | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/nvim/diff.c b/src/nvim/diff.c index 9ac9b6f6db..b9376c311f 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -268,7 +268,7 @@ 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 udpate diffs before redrawing. Set _invalid to update the + // Will update diffs before redrawing. Set _invalid to update the // diffs themselves, set _update to also update folds properly just // before redrawing. tp->tp_diff_invalid = true; @@ -886,6 +886,8 @@ void ex_diffupdate(exarg_T *eap) return; } + int had_diffs = curtab->tp_first_diff != NULL; + // Delete all diffblocks. diff_clear(curtab); curtab->tp_diff_invalid = false; @@ -899,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. @@ -911,7 +913,7 @@ void ex_diffupdate(exarg_T *eap) } if (idx_new == DB_COUNT) { - return; + goto theend; } // Only use the internal method if it did not fail for one of the buffers. @@ -929,9 +931,13 @@ void ex_diffupdate(exarg_T *eap) // force updating cursor position on screen curwin->w_valid_cursor.lnum = 0; - diff_redraw(true); - - apply_autocmds(EVENT_DIFFUPDATED, NULL, NULL, false, curbuf); +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); + } } /// @@ -2176,7 +2182,8 @@ int diffopt_changed(void) return FAIL; } - // If "icase" or "iwhite" was added or removed, need to update the diff. + // 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; @@ -2734,15 +2741,17 @@ theend: if (diff_need_update) { diff_need_update = false; 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_cursor(); - changed_line_abv_curs(); + } else { + // 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_cursor(); + changed_line_abv_curs(); - // Also need to redraw the other buffers. - diff_redraw(false); + // 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". -- cgit From e104228b1c89022f0b284753ff92deb2e9374c5b Mon Sep 17 00:00:00 2001 From: Anatolii Sakhnik Date: Sun, 9 Dec 2018 19:55:08 +0200 Subject: vim-patch:8.1.0458: ml_get error and crash when using "do" Problem: Ml_get error and crash when using "do". Solution: Adjust cursor position also when diffupdate is not needed. (Hirohito Higashi) https://github.com/vim/vim/commit/df77cef92ec034796723ffa3adb12e8b46daa98e --- src/nvim/diff.c | 18 +++++++++++------- src/nvim/testdir/test_diffmode.vim | 22 ++++++++++++++++++++++ 2 files changed, 33 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/nvim/diff.c b/src/nvim/diff.c index b9376c311f..57bfc8db69 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -2739,15 +2739,19 @@ void ex_diffgetput(exarg_T *eap) theend: diff_busy = false; if (diff_need_update) { - diff_need_update = false; ex_diffupdate(NULL); - } else { - // 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_cursor(); - changed_line_abv_curs(); + } + + // 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_cursor(); + changed_line_abv_curs(); + 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); diff --git a/src/nvim/testdir/test_diffmode.vim b/src/nvim/testdir/test_diffmode.vim index 6f25179ab1..f34c2fd26d 100644 --- a/src/nvim/testdir/test_diffmode.vim +++ b/src/nvim/testdir/test_diffmode.vim @@ -275,6 +275,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']) -- cgit From 8f20c22e10c35075afd97bf6af50fb6d9a2dc710 Mon Sep 17 00:00:00 2001 From: Anatolii Sakhnik Date: Sun, 9 Dec 2018 20:05:53 +0200 Subject: vim-patch:8.1.0497: :%diffput changes order of lines Problem: :%diffput changes order of lines. (Markus Braun) Solution: Do adjust marks when using internal diff. https://github.com/vim/vim/commit/5f57bdcab77bc417ae0357fe8ad6c7259b6d25df --- src/nvim/diff.c | 4 ++-- src/nvim/testdir/test_diffmode.vim | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nvim/diff.c b/src/nvim/diff.c index 57bfc8db69..2bb73f63ba 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -271,9 +271,9 @@ static void diff_mark_adjust_tp(tabpage_T *tp, int idx, linenr_T line1, // 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; - return; } int inserted; @@ -2742,7 +2742,7 @@ theend: ex_diffupdate(NULL); } - // Check that the cursor is on a valid character and update it's + // 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(); diff --git a/src/nvim/testdir/test_diffmode.vim b/src/nvim/testdir/test_diffmode.vim index f34c2fd26d..ad3eec3274 100644 --- a/src/nvim/testdir/test_diffmode.vim +++ b/src/nvim/testdir/test_diffmode.vim @@ -219,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('%') -- cgit From 89eba72792fb9e36ede7e9d58f5673ebfd553178 Mon Sep 17 00:00:00 2001 From: Anatolii Sakhnik Date: Sun, 9 Dec 2018 20:13:34 +0200 Subject: vim-patch:8.1.0502: internal diff fails when diffing a context diff Problem: Internal diff fails when diffing a context diff. (Hirohito Higashi) Solution: Only use callback calls with one line. (closes #3581) https://github.com/vim/vim/commit/f080d70a82f3a4477f346d9efcdfaec1bc1e1d58 --- src/nvim/diff.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/nvim/diff.c b/src/nvim/diff.c index 2bb73f63ba..6dbebd5e29 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -3103,20 +3103,22 @@ static int parse_diff_unified(char_u *line, static int xdiff_out(void *priv, mmbuffer_t *mb, int nbuf) { diffout_T *dout = (diffout_T *)priv; - int i; char_u *p; - for (i = 0; i < nbuf; i++) { - // We are only interested in the header lines, skip text lines. - if (STRNCMP(mb[i].ptr, "@@ ", 3) != 0) { - continue; - } - ga_grow(&dout->dout_ga, 1); - p = vim_strnsave((char_u *)mb[i].ptr, mb[i].size); - if (p == NULL) { - return -1; - } - ((char_u **)dout->dout_ga.ga_data)[dout->dout_ga.ga_len++] = 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; } -- cgit From f273e43cb83c1617969ebd4eaa51aa5bc3f0b855 Mon Sep 17 00:00:00 2001 From: Anatolii Sakhnik Date: Sun, 9 Dec 2018 20:17:04 +0200 Subject: vim-patch:8.1.0513: no error for set diffopt+=algorithm: Problem: No error for set diffopt+=algorithm:. Solution: Check for missing argument. (Hirohito Higashi, closes #3598) https://github.com/vim/vim/commit/d0721058f494143186f66a60151c9634031a8c96 --- src/nvim/diff.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/nvim/diff.c b/src/nvim/diff.c index 6dbebd5e29..19751cb73a 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -2165,6 +2165,8 @@ int diffopt_changed(void) } else if (STRNCMP(p, "histogram", 9) == 0) { p += 9; diff_algorithm_new = XDF_HISTOGRAM_DIFF; + } else { + return FAIL; } } -- cgit From 4e2981081796c8618caa4bed30d12e1e8fc8ae08 Mon Sep 17 00:00:00 2001 From: Anatolii Sakhnik Date: Sun, 9 Dec 2018 20:24:38 +0200 Subject: vim-patch:8.1.0562: parsing of 'diffopt' is slightly wrong Problem: Parsing of 'diffopt' is slightly wrong. Solution: Fix the parsing and add a test. (Jason Franklin, Christian Brabandt) https://github.com/vim/vim/commit/b6fc72851c45a36a370f9516c68508e47b41c4c1 --- src/nvim/diff.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/diff.c b/src/nvim/diff.c index 19751cb73a..2e0b198c13 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -2109,6 +2109,7 @@ int diffopt_changed(void) 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) { @@ -2147,7 +2148,7 @@ int diffopt_changed(void) diff_flags_new |= DIFF_HIDDEN_OFF; } else if (STRNCMP(p, "indent-heuristic", 16) == 0) { p += 16; - diff_algorithm_new |= XDF_INDENT_HEURISTIC; + diff_indent_heuristic = XDF_INDENT_HEURISTIC; } else if (STRNCMP(p, "internal", 8) == 0) { p += 8; diff_flags_new |= DIFF_INTERNAL; @@ -2179,6 +2180,8 @@ 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; -- cgit From 55c5185884d707e6c59d1900a4d921038f360807 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sun, 9 Dec 2018 21:11:56 -0500 Subject: vim-patch:8.1.0574: 'commentstring', fold marker in C (#9339) Problem: 'commentstring' not used when adding fold marker in C. Solution: Require white space before middle comment part. (mostly by Hirohito Higashi) https://github.com/vim/vim/commit/4af7259b2b35e85c590d54908fcd248d2c733be8 --- src/nvim/misc1.c | 14 ++++++-------- src/nvim/testdir/test_fold.vim | 29 +++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c index d77c196a3a..ffe2d11f08 100644 --- a/src/nvim/misc1.c +++ b/src/nvim/misc1.c @@ -1099,7 +1099,6 @@ int get_last_leader_offset(char_u *line, char_u **flags) found_one = FALSE; for (list = curbuf->b_p_com; *list; ) { char_u *flags_save = list; - bool is_only_whitespace = false; /* * Get one option part into part_buf[]. Advance list to next one. @@ -1126,9 +1125,6 @@ int get_last_leader_offset(char_u *line, char_u **flags) while (ascii_iswhite(*string)) { string++; } - if (*string == NUL) { - is_only_whitespace = true; - } } for (j = 0; string[j] != NUL && string[j] == line[i + j]; ++j) /* do nothing */; @@ -1144,10 +1140,12 @@ int get_last_leader_offset(char_u *line, char_u **flags) continue; } - // For a middlepart comment that is only white space, only consider - // it to match if everything before the current position in the - // line is also whitespace. - if (is_only_whitespace && vim_strchr(part_buf, COM_MIDDLE) != NULL) { + 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) { diff --git a/src/nvim/testdir/test_fold.vim b/src/nvim/testdir/test_fold.vim index 85f58ada7e..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! -- cgit From ca1de71a3e2f17b788ed8eb1641858ce6c8227fe Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Tue, 11 Dec 2018 13:19:00 +0100 Subject: TUI: don't use BCE with attributes affecting background --- src/nvim/tui/tui.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 6e266408c9..048498bf7c 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -105,8 +105,8 @@ typedef struct { HlAttrs clear_attrs; kvec_t(HlAttrs) attrs; int print_attr_id; - bool has_bg; bool default_attr; + bool can_clear_attr; ModeShape showing_mode; struct { int enable_mouse, disable_mouse; @@ -187,7 +187,7 @@ static void terminfo_start(UI *ui) data->scroll_region_is_full_screen = true; data->bufpos = 0; data->default_attr = false; - data->has_bg = false; + data->can_clear_attr = false; data->is_invisible = true; data->busy = false; data->cork = false; @@ -489,8 +489,6 @@ static void update_attrs(UI *ui, int attr_id) : (data->clear_attrs.cterm_bg_color - 1); } - data->has_bg = bg != -1; - int attr = ui->rgb ? attrs.rgb_ae_attr : attrs.cterm_ae_attr; bool bold = attr & HL_BOLD; bool italic = attr & HL_ITALIC; @@ -582,6 +580,12 @@ static void update_attrs(UI *ui, int attr_id) 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) @@ -753,12 +757,10 @@ static void clear_region(UI *ui, int top, int bot, int left, int right, update_attrs(ui, attr_id); - // non-BCE terminals can't clear with non-default background color - bool can_clear = data->bce || !data->has_bg; - // 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 (can_clear && left == 0 && right == ui->width && bot == ui->height) { + 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); @@ -772,9 +774,9 @@ static void clear_region(UI *ui, int top, int bot, int left, int right, // iterate through each line and clear for (int row = top; row < bot; row++) { cursor_goto(ui, row, left); - if (can_clear && right == ui->width) { + if (data->can_clear_attr && right == ui->width) { unibi_out(ui, unibi_clr_eol); - } else if (data->can_erase_chars && can_clear && width >= 5) { + } 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 { -- cgit From 57acfceabeb349377ce244de9b67732b21ed1d18 Mon Sep 17 00:00:00 2001 From: Marco Hinz Date: Tue, 11 Dec 2018 21:58:35 +0100 Subject: macOS: infer primary language if $LANG is empty #9345 The macOS preferences have a section called `Language & Region`. There is always at least one language defined, the primary language. CFLocaleCopyPreferredLanguages() returns the languages defined in that section, the first element being the primary language. Use the primary language in case CFLocaleCopyCurrent() returns NULL. In the case that the above fallback does not work either, which is very unlikely, log the error and continue with an empty $LANG. References #9134 --- src/nvim/os/lang.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/nvim/os/lang.c b/src/nvim/os/lang.c index 6b2a54ddbe..900cd1f53a 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 { -- cgit From 3c42d7a10a044b94f4050a2c0ea68d142d5c62eb Mon Sep 17 00:00:00 2001 From: Patrice Peterson Date: Tue, 11 Dec 2018 21:05:04 +0100 Subject: TUI: alacritty supports set_cursor_color #9353 Feature was added in: https://github.com/jwilm/alacritty/pull/757 closes #9353 --- src/nvim/tui/tui.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 048498bf7c..1e0c8e6e25 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -1761,6 +1761,7 @@ 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; @@ -1828,7 +1829,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"); -- cgit From 5fee0be915525fe00519a17cccda2947dfdfbc6a Mon Sep 17 00:00:00 2001 From: Marco Hinz Date: Tue, 11 Dec 2018 23:43:35 +0100 Subject: provider: improve error message (#9344) Executing `:python`, and similar commands that rely on `eval_call_provider()`, while the accompanying provider it not available, leads to this error message: E117: Unknown function: provider#python#Call This doesn't say much to a user. Since we introduced `:checkhealth` for this very reason, we now point to it for further diagnosis. Fixes #3577 --- src/nvim/ex_cmds2.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index 76c71a00ec..d03bfd2488 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -3828,7 +3828,12 @@ 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("No \"%s\" provider found. Run \":checkhealth provider\"", name); + } else { + (void)eval_call_provider(name, "execute", args); + } } } -- cgit From 2b01c3a8a87a8d8ba26bc95b95441835634a2948 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Tue, 11 Dec 2018 23:51:29 +0100 Subject: ex_cmds: Remove various "not implemented" commands Commands related to Netbeans, Sun Workshop, and GUI shims, were intentionally removed and will not be implemented. --- src/nvim/ex_cmds.lua | 36 ------------------------------------ 1 file changed, 36 deletions(-) (limited to 'src') diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua index d9212aa4e3..79ca5363e0 100644 --- a/src/nvim/ex_cmds.lua +++ b/src/nvim/ex_cmds.lua @@ -1706,24 +1706,6 @@ return { addr_type=ADDR_LINES, 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), @@ -1958,18 +1940,6 @@ return { addr_type=ADDR_LINES, 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), @@ -3116,12 +3086,6 @@ return { addr_type=ADDR_LINES, 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), -- cgit From 61d0dfee32ce9a9fb2497b02558df02eabb61d1b Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Wed, 12 Dec 2018 00:17:27 +0100 Subject: provider: repurpose E319 In Vim (and some vestigial parts of Nvim) E319 was a placeholder for ex_ni commands, i.e. commands that are only available in certain builds of Vim. That is obviously counter to Nvim's goals: all Nvim commands are available on all platforms and build types (the remaining ex_ni commands are actually just missing providers). We need an error id for "missing provider", so it makes sense to use E319 for that purpose. ref #9344 ref #3577 --- src/nvim/ex_cmds2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index d03bfd2488..c9b6d19aaa 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -3830,7 +3830,8 @@ static void script_host_execute(char *name, exarg_T *eap) tv_list_append_number(args, (int)eap->line2); if (!eval_has_provider(name)) { - emsgf("No \"%s\" provider found. Run \":checkhealth provider\"", name); + emsgf("E319: No \"%s\" provider found. Run \":checkhealth provider\"", + name); } else { (void)eval_call_provider(name, "execute", args); } -- cgit From 6c602be33a5176fd1101e8cff45dd2a85b0e512e Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Wed, 31 Jan 2018 16:17:05 +0100 Subject: vim-patch:8.0.1445: cannot act on edits in the command line Problem: Cannot act on edits in the command line. Solution: Add the CmdlineChanged autocommand event. (xtal8, closes vim/vim#2603, closes vim/vim#2524) https://github.com/vim/vim/commit/153b704e20f9c269450a7d3ea8cafcf942579ab7 --- src/nvim/auevents.lua | 1 + src/nvim/ex_getln.c | 7 +++++++ src/nvim/testdir/test_autocmd.vim | 12 ++++++++++++ 3 files changed, 20 insertions(+) (limited to 'src') diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua index ab92e84799..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 diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 19a52c913a..447123e45d 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -1804,6 +1804,13 @@ static int empty_pattern(char_u *p) static int command_line_changed(CommandLineState *s) { + // Trigger CmdlineChanged autocommands. + char firstcbuf[2]; + firstcbuf[0] = s->firstc > 0 ? s->firstc : '-'; + firstcbuf[1] = 0; + apply_autocmds(EVENT_CMDLINECHANGED, (char_u *)firstcbuf, (char_u *)firstcbuf, + false, curbuf); + // 'incsearch' highlighting. if (p_is && !cmd_silent && (s->firstc == '/' || s->firstc == '?')) { pos_T end_pos; diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim index 9e8d2081c8..5deb789f48 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'\", 'xt') + call assert_equal("echom 'hello'", g:text) + au! CmdlineChanged + + au! CmdlineChanged : let g:entered = expand('') + let g:entered = 0 + call feedkeys(":echom 'hello'\", 'xt') + call assert_equal(':', g:entered) + au! CmdlineChanged + au! CmdlineEnter : let g:entered = expand('') au! CmdlineLeave : let g:left = expand('') let g:entered = 0 -- cgit From 5f82889be78856ee189c254110bf087dba918b23 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Wed, 12 Dec 2018 11:01:46 +0100 Subject: cmdline: support v:event in CmdlineChanged --- src/nvim/ex_getln.c | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 447123e45d..bfc32887ca 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -1805,11 +1805,35 @@ static int empty_pattern(char_u *p) static int command_line_changed(CommandLineState *s) { // Trigger CmdlineChanged autocommands. - char firstcbuf[2]; - firstcbuf[0] = s->firstc > 0 ? s->firstc : '-'; - firstcbuf[1] = 0; - apply_autocmds(EVENT_CMDLINECHANGED, (char_u *)firstcbuf, (char_u *)firstcbuf, - false, curbuf); + 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 == '?')) { -- cgit From 5062d8e0dd47aa36c568bf8763d6f9054cbcec97 Mon Sep 17 00:00:00 2001 From: Marco Hinz Date: Wed, 12 Dec 2018 03:22:45 +0100 Subject: provider: make :ruby provider check use same code path as :python Prior to this change, the provider check for ruby was special-cased and now it returns E319, like :python etc. References #9354 --- src/nvim/eval.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index cd29e4ef19..d67818aa81 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -10802,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; } @@ -22770,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; } -- cgit From 0930435fc30d1e7e6be05ed1cd1d072e3616b6f4 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Mon, 10 Dec 2018 22:41:37 -0500 Subject: vim-patch:8.0.1748: CmdlineEnter command uses backslash instead of slash Problem: CmdlineEnter command uses backslash instead of slash. Solution: Don't treat the character as a file name. (closes vim/vim#2837) https://github.com/vim/vim/commit/a4baf5b32519855bb176a7aa0e9397c137ca890a --- src/nvim/fileio.c | 8 +++++++- src/nvim/testdir/test_autocmd.vim | 3 +++ 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 8e5455bc67..fe12a69801 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -6903,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 diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim index 5deb789f48..253d6750ed 100644 --- a/src/nvim/testdir/test_autocmd.vim +++ b/src/nvim/testdir/test_autocmd.vim @@ -840,6 +840,8 @@ func Test_Cmdline() au! CmdlineEnter au! CmdlineLeave + let save_shellslash = &shellslash + set noshellslash au! CmdlineEnter / let g:entered = expand('') au! CmdlineLeave / let g:left = expand('') let g:entered = 0 @@ -852,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. -- cgit From 4157f4c72db7eab71b9670d517a8cbd3ed8909ba Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Tue, 11 Dec 2018 20:46:13 -0500 Subject: ex_docmd: '/' is not a path for Cmdline* events Code from https://github.com/neovim/neovim/pull/9348#issuecomment-446416118 autocmd_fname_full was removed in https://github.com/neovim/neovim/commit/82cd0be2eaf71c0476e15c66ba3e83c76896d407 but Vim uses this hack for on CmdlineEnter and related events in vim-patch:8.0.1748. Port the hack by not treating "/" as a path for on these events. --- src/nvim/ex_docmd.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 6361267d9b..4ef332186e 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -8654,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, 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 is not used. result = (char_u *)FullName_save((char *)autocmd_fname, false); -- cgit From 7ba52c0b2b53a6013b8e31794a1991d641a6b0ab Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Thu, 13 Dec 2018 12:02:20 +0100 Subject: os/lang: use the correct LC_NUMERIC also for OS X --- src/nvim/os/lang.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src') diff --git a/src/nvim/os/lang.c b/src/nvim/os/lang.c index 900cd1f53a..108a9c6c39 100644 --- a/src/nvim/os/lang.c +++ b/src/nvim/os/lang.c @@ -54,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 -- cgit From c16529afa5c8eb0314b8c2a35eb033141f0246f9 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Fri, 14 Dec 2018 22:54:39 +0100 Subject: TUI: Konsole 18.07.70 supports DECSCUSR (#9364) ref https://github.com/KDE/konsole/commit/b0d3d83eca4f523a9e4acd3989da6be96033536a KONSOLE_VERSION is exported as a numeric string (after removing the dots from the version string). ref #8300 closes #6778 closes #6798 --- src/nvim/tui/tui.c | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 1e0c8e6e25..dfee73b85e 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -228,14 +228,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 = @@ -1461,7 +1464,7 @@ 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"); @@ -1488,7 +1491,7 @@ 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 @@ -1633,7 +1636,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 @@ -1654,7 +1657,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"); } @@ -1663,15 +1667,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 ((!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 @@ -1719,12 +1723,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 @@ -1747,7 +1749,8 @@ 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"); @@ -1771,7 +1774,7 @@ static void augment_terminfo(TUIData *data, const char *term, // 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, -- cgit From bcc9b9335ceddf1f3ff11ae7bb2821c4f55c301b Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Fri, 14 Dec 2018 22:41:42 -0500 Subject: vim-patch:8.1.0585: undo test may fail on MS-Windows Problem: Undo test may fail on MS-Windows. Solution: Also handle lower case drive letters. https://github.com/vim/vim/commit/56242f2b08737677812513c447955579a19aa620 --- src/nvim/testdir/test_undo.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') 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') -- cgit From 845973c9fed0da7a0d471f5b57ab361961a3de93 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Fri, 14 Dec 2018 22:46:22 -0500 Subject: vim-patch:8.1.0588: cannot define a sign with space in the text Problem: Cannot define a sign with space in the text. Solution: Allow for escaping characters. (Ben Jackson, closes vim/vim#2967) https://github.com/vim/vim/commit/06b056e110005ce0dd97b8c6333405afd06c36fc --- src/nvim/ex_cmds.c | 8 ++++++++ src/nvim/testdir/test_signs.vim | 27 +++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) (limited to 'src') diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 0a9b6ecc57..36c4e333cf 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -5685,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/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 -- cgit From 8fb1fce694d1bba1992ec954f7381fd058b69fda Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sat, 15 Dec 2018 09:54:25 +0100 Subject: TUI: handle wrap of doublewidth chars correctly --- src/nvim/tui/tui.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 1e0c8e6e25..5e6cf88fca 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -1276,9 +1276,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 -- cgit From ab7da4c53138768f5b502b880a607048c2183632 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Tue, 11 Dec 2018 02:04:29 +0100 Subject: TUI: detect BSD vt console FreeBSD console sets TERM=xterm, but it does not support xterm features like cursor-shaping. GUI terminals typically set TERM=xterm-256color, so on FreeBSD we can guess that TERM=xterm is the degraded vt. OpenBSD console sets TERM=vt220 https://github.com/openbsd/src/blob/master/etc/etc.amd64/ttys NetBSD console sets TERM=vt100 https://github.com/NetBSD/src/blob/trunk/etc/etc.amd64/ttys closes #8644 --- src/nvim/os/pty_process_unix.c | 2 +- src/nvim/tui/terminfo.c | 19 +++++++++++++++++++ src/nvim/tui/tui.c | 14 ++++++++------ 3 files changed, 28 insertions(+), 7 deletions(-) (limited to 'src') 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 // forkpty is not in POSIX, so headers are platform-specific -#if defined(__FreeBSD__) || defined (__DragonFly__) +#if defined(__FreeBSD__) || defined(__DragonFly__) # include #elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) # include diff --git a/src/nvim/tui/terminfo.c b/src/nvim/tui/terminfo.c index ad86dd928b..ad57f0af7f 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 26896a141d..405d853148 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -1468,7 +1468,7 @@ static void patch_terminfo_bugs(TUIData *data, const char *term, 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 @@ -1477,6 +1477,7 @@ static void patch_terminfo_bugs(TUIData *data, const char *term, || 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"); @@ -1497,7 +1498,7 @@ static void patch_terminfo_bugs(TUIData *data, const char *term, && 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; char *fix_normal = (char *)unibi_get_str(ut, unibi_cursor_normal); if (fix_normal) { @@ -1670,7 +1671,7 @@ static void patch_terminfo_bugs(TUIData *data, const char *term, if (-1 == data->unibi_ext.set_cursor_style) { // DECSCUSR (cursor shape) is widely supported. // https://github.com/gnachman/iTerm2/pull/92 - if ((!konsolev || konsolev >= 180770) + if ((!bsdvt && (!konsolev || konsolev >= 180770)) && ((xterm && !vte_version) // anything claiming xterm compat // per MinTTY 0.4.3-1 release notes from 2009 || putty @@ -1684,7 +1685,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 // Some linux-type terminals implement the xterm extension. // Example: console-terminal-emulator from the nosh toolset. @@ -1755,6 +1756,7 @@ static void augment_terminfo(TUIData *data, const char *term, { unibi_term *ut = data->ut; bool xterm = terminfo_is_term_family(term, "xterm"); + 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"); @@ -1769,8 +1771,8 @@ static void augment_terminfo(TUIData *data, const char *term, // 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 -- cgit From 3f55010cda120d0ccb35f9e24d93cee33f3aa17b Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Tue, 11 Dec 2018 03:06:35 +0100 Subject: TUI: TERM=nsterm Treat TERM=nsterm the same way in augment_terminfo() and patch_terminfo_bugs(). ref #9244 463d28cc8079 --- src/nvim/tui/tui.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 405d853148..4aff2d264b 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -1755,7 +1755,9 @@ static void augment_terminfo(TUIData *data, const char *term, 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"); -- cgit From 314f6ea3678c09f9824242a10abbe4a2fb2ccff3 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Sat, 15 Dec 2018 23:40:41 -0500 Subject: startup: Use $XDG_CONFIG_DIRS/nvim/sysinit.vim if it exists Closes #8994 --- src/nvim/main.c | 47 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/nvim/main.c b/src/nvim/main.c index 911e51407d..8a40577e8f 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -1722,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: @@ -1804,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 -- cgit From ae6848cd1296a3a86f0cc6e7623dc0a79521886d Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sat, 15 Dec 2018 14:06:12 -0500 Subject: vim-patch:8.1.0596: not all parts of printf() are tested Problem: Not all parts of printf() are tested. Solution: Add a few more test cases. (Dominique Pelle, closes vim/vim#3691) https://github.com/vim/vim/commit/21e551cce26ea6ff389b6c90f1945facf1a8a066 --- src/nvim/testdir/test_expr.vim | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'src') 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)) -- cgit From 4680ca29f1933fd7bc17fc2638b8bfb2e20d5415 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sun, 16 Dec 2018 03:23:00 -0500 Subject: strings: use (u)int16_t for %h printf format --- src/nvim/strings.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/nvim/strings.c b/src/nvim/strings.c index 3b0a950ff2..87593f577b 100644 --- a/src/nvim/strings.c +++ b/src/nvim/strings.c @@ -1001,8 +1001,8 @@ int vim_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap, switch (length_modifier) { case '\0': 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': { @@ -1033,9 +1033,9 @@ int vim_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap, switch (length_modifier) { case '\0': 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)); break; } case 'l': { -- cgit From 1ff7b83d3c38dd3c0347728f0619ca1cf90b92d8 Mon Sep 17 00:00:00 2001 From: Anatolii Sakhnik Date: Wed, 19 Dec 2018 07:02:31 +0200 Subject: l10n: Update Ukrainian translation #9377 --- src/nvim/po/uk.po | 352 +++++++++++++++++++++--------------------------------- 1 file changed, 133 insertions(+), 219 deletions(-) (limited to 'src') 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: Анатолій Сахнік \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 % (add ! to override)" msgstr "E89: Буфер % має зміни (! щоб не зважати)" -#. wrap around (may cause duplicates) msgid "W14: Warning: List of file names overflow" msgstr "W14: Обережно: Список назв файлів переповнено" @@ -152,7 +150,6 @@ msgstr "рядок % з % --%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 % buffers" msgstr "E96: Не можна порівнювати понад % буфери(ів)" +#, 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" @@ -780,6 +781,10 @@ msgstr "E482: Не вдалося відкрити файл %s для запис 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»" @@ -817,6 +822,10 @@ msgstr "E932: Функція замикання не може бути на ве 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: не вдалося коректно злити змінну з контейнером, який сам на себе " @@ -1243,10 +1250,22 @@ msgstr "не вдалося знайти вузол чи порт" 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 % lines" msgstr " в % рядках" -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 %" msgstr "%s, рядок %" -#. 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 " 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 %" msgstr "" -"E5210: ключ словника '%s' вже встановлено для буферизованого потоку у каналі %" +"E5210: ключ словника '%s' вже встановлено для буферизованого потоку у каналі " +"%" #, 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 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 Execute before any config\n" -msgstr " --cmd <команда> Виконати <команду> перед будь-якою конфігурацією\n" +msgstr "" +" --cmd <команда> Виконати <команду> перед будь-якою конфігурацією\n" msgid " +, -c Execute 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 Use this config file\n" msgstr " -u Вжити цей файл конфігурації\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 to abandon all changes and exit Nvim" -msgstr "Введіть :qa! і натисність щоб відкинути всі зміни і вийти Nvim" +msgstr "" +"Введіть :qa! і натисність щоб відкинути всі зміни і вийти Nvim" #, c-format msgid "1 line %sed 1 time" @@ -3951,25 +3915,30 @@ msgstr "Один рядок змінено" msgid "% lines changed" msgstr "Змінено рядків: %" -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 % lines yanked" -msgstr "Запам'ятав блок із % рядків" +msgid "block of % lines yanked%s" +msgstr "Запам'ятав блок із % рядків%s" #, c-format -msgid "% lines yanked" -msgstr "Запам'ятав рядків: %" +msgid "% lines yanked%s" +msgstr "Запам'ятав рядків: %%s" #, c-format msgid "E353: Nothing in register %s" msgstr "E353: У регістрі %s нічого немає" -#. Highlight title msgid "" "\n" "--- Registers ---" @@ -4023,7 +3992,6 @@ msgstr "" msgid "(+% for BOM)" msgstr "(+% для 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 % that " "is stated to be too long" -msgstr "" -"Помилка читання файлу ShaDa: є задовгий елемент у позиції %" +msgstr "Помилка читання файлу ShaDa: є задовгий елемент у позиції %" -#. 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 % that " @@ -4703,24 +4658,6 @@ msgstr "" "Помилка при читанні файлу ShaDa: список буферів у позиції % містить " "поле, яке не має назву файлу" -#. 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 % suggestions" msgstr "Пробачте, тільки % пропозицій" -#. 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 "Перед байтом %" 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 if you are new! " msgstr ":help nvim якщо ви вперше! " @@ -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" -- cgit From d2352b7b51c9ec039426493ad02840cc9c8e2c2e Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sat, 22 Dec 2018 13:23:01 +0100 Subject: vim-patch:8.1.0615: get_tv function names are not consistent (#9386) Problem: Get_tv function names are not consistent. Solution: Rename to tv_get. https://github.com/vim/vim/commit/d155d7a8519987361169459b8d464ae1caef5e9c Only a change in comments appears to be necessary. --- src/nvim/eval/typval.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') 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. /// -- cgit From e9685d9f70f26daa6a252baf8f5a2d411cf4b38f Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sun, 23 Dec 2018 07:12:59 -0500 Subject: vim-patch:8.1.0627: Python cannot handle function name of script-local function (#9392) Problem: Python cannot handle function name of script-local function. Solution: Use instead of the special byte code. (Ozaki Kiichi, closes vim/vim#3681) https://github.com/vim/vim/commit/9123c0b31a283f460ed2b6af95080120cf528118 --- src/nvim/testdir/test_python2.vim | 27 +++++++++++++++++++++++++++ src/nvim/testdir/test_python3.vim | 27 +++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) (limited to 'src') 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(''), '\zs\d\+_foo$') + endfunc + let name = '' . 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(''), '\zs\d\+_foo$') + endfunc + let name = '' . 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 -- cgit From 357e59982d014cccf14ccc092470250c011b8e44 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Mon, 24 Dec 2018 09:39:21 +0100 Subject: strings: make vim_snprintf handle %d correctly again This was broken in #9369 (4680ca2) --- src/nvim/strings.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/nvim/strings.c b/src/nvim/strings.c index 87593f577b..4921824316 100644 --- a/src/nvim/strings.c +++ b/src/nvim/strings.c @@ -999,7 +999,10 @@ 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 int16_t arg = (int16_t)(tvs ? tv_nr(tvs, &arg_idx) : va_arg(ap, int)); @@ -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 = (uint16_t)(tvs ? tv_nr(tvs, &arg_idx) - : va_arg(ap, unsigned)); + : va_arg(ap, unsigned int)); break; } case 'l': { -- cgit