aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/labeler.yml38
-rw-r--r--.github/workflows/reviews.yml99
-rw-r--r--ci/common/build.sh7
-rw-r--r--ci/common/suite.sh18
-rw-r--r--ci/common/test.sh9
-rwxr-xr-xci/run_tests.sh24
-rw-r--r--runtime/doc/change.txt7
-rw-r--r--runtime/doc/index.txt4
-rw-r--r--runtime/doc/quickfix.txt5
-rw-r--r--runtime/doc/various.txt2
-rw-r--r--runtime/doc/visual.txt1
-rw-r--r--src/nvim/api/vim.c6
-rw-r--r--src/nvim/buffer.c2
-rw-r--r--src/nvim/eval.c2
-rw-r--r--src/nvim/ex_cmds2.c9
-rw-r--r--src/nvim/fileio.c2
-rw-r--r--src/nvim/mbyte.c41
-rw-r--r--src/nvim/normal.c12
-rw-r--r--src/nvim/ops.c117
-rw-r--r--src/nvim/quickfix.c74
-rw-r--r--src/nvim/screen.c46
-rw-r--r--src/nvim/testdir/test_cursor_func.vim8
-rw-r--r--src/nvim/testdir/test_filter_cmd.vim35
-rw-r--r--src/nvim/testdir/test_quickfix.vim23
-rw-r--r--src/nvim/testdir/test_visual.vim58
-rw-r--r--src/nvim/testdir/test_writefile.vim148
-rw-r--r--test/functional/api/vim_spec.lua25
-rw-r--r--test/functional/editor/put_spec.lua12
28 files changed, 607 insertions, 227 deletions
diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml
index 17dbf8704d..3de0c453a5 100644
--- a/.github/workflows/labeler.yml
+++ b/.github/workflows/labeler.yml
@@ -32,41 +32,3 @@ jobs:
- name: "Extract commit scope and add as label"
continue-on-error: true
run: gh pr edit "$PR_NUMBER" --add-label "$(echo "$PR_TITLE" | sed -E 's|[[:alpha:]]+\((.+)\)!?:.*|\1|')"
-
- add-reviewer:
- runs-on: ubuntu-latest
- needs: ["triage", "type-scope"]
- permissions:
- pull-requests: write
- steps:
- - uses: actions/github-script@v5
- with:
- script: |
- const reviewers = []
-
- const { data: { labels } } = await github.rest.pulls.get({
- owner: context.repo.owner,
- repo: context.repo.repo,
- pull_number: context.issue.number
- })
- const label_names = labels.map(label => label.name)
-
- if (label_names.includes('ci')) {
- reviewers.push("jamessan")
- }
-
- if (label_names.includes('vim-patch')) {
- reviewers.push("seandewar")
- }
-
- const index = reviewers.indexOf(context.actor);
- if (index > -1) {
- reviewers.splice(index, 1);
- }
-
- github.rest.pulls.requestReviewers({
- owner: context.repo.owner,
- repo: context.repo.repo,
- pull_number: context.issue.number,
- reviewers: reviewers
- });
diff --git a/.github/workflows/reviews.yml b/.github/workflows/reviews.yml
new file mode 100644
index 0000000000..1491482b98
--- /dev/null
+++ b/.github/workflows/reviews.yml
@@ -0,0 +1,99 @@
+name: "Request reviews"
+on:
+ pull_request_target:
+ types: [labeled]
+ workflow_run:
+ workflows: [Pull Request Labeler]
+ types: [completed]
+jobs:
+ request-reviewer:
+ runs-on: ubuntu-latest
+ permissions:
+ pull-requests: write
+ steps:
+ - uses: actions/github-script@v5
+ with:
+ script: |
+ // The number of the pull request that triggered this run. If label
+ // was added manually by a person the number will be stored in current
+ // context, otherwise the number will be stored in the payload.
+ const pr_number = context.issue.number || context.payload.workflow_run.pull_requests[0].number
+
+ const pr_data = await github.rest.pulls.get({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ pull_number: pr_number
+ })
+ const labels = pr_data.data.labels.map(e => e.name)
+
+ const reviewers = new Set()
+ if (labels.includes('api')) {
+ reviewers.add("bfredl")
+ reviewers.add("gpanders")
+ reviewers.add("muniter")
+ }
+
+ if (labels.includes('ci')) {
+ reviewers.add("jamessan")
+ }
+
+ if (labels.includes('diagnostic')) {
+ reviewers.add("gpanders")
+ }
+
+ if (labels.includes('distribution')) {
+ reviewers.add("jamessan")
+ }
+
+ if (labels.includes('documentation')) {
+ reviewers.add("clason")
+ }
+
+ if (labels.includes('extmarks')) {
+ reviewers.add("bfredl")
+ }
+
+ if (labels.includes('filetype')) {
+ reviewers.add("clason")
+ reviewers.add("gpanders")
+ }
+
+ if (labels.includes('gui')) {
+ reviewers.add("glacambre")
+ reviewers.add("smolck")
+ }
+
+ if (labels.includes('lsp')) {
+ reviewers.add("mfussenegger")
+ reviewers.add("mjlbach")
+ }
+
+ if (labels.includes('treesitter')) {
+ reviewers.add("bfredl")
+ reviewers.add("vigoux")
+ }
+
+ if (labels.includes('typo')) {
+ reviewers.add("dundargoc")
+ }
+
+ if (labels.includes('ui')) {
+ reviewers.add("bfredl")
+ }
+
+ if (labels.includes('vim-patch')) {
+ reviewers.add("janlazo")
+ reviewers.add("seandewar")
+ reviewers.add("zeertzjq")
+ }
+
+ // Remove person that opened the PR since they can't review themselves
+ const pr_opener = pr_data.data.user.login
+ reviewers.delete(pr_opener)
+
+ github.rest.pulls.requestReviewers({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ pull_number: pr_number,
+ reviewers: Array.from(reviewers)
+ });
diff --git a/ci/common/build.sh b/ci/common/build.sh
index c44c234274..b8bbff0b16 100644
--- a/ci/common/build.sh
+++ b/ci/common/build.sh
@@ -44,7 +44,9 @@ build_deps() {
cd "${CI_BUILD_DIR}"
}
-prepare_build() {
+build_nvim() {
+ check_core_dumps --delete quiet
+
if test -n "${CLANG_SANITIZER}" ; then
CMAKE_FLAGS="${CMAKE_FLAGS} -DCLANG_${CLANG_SANITIZER}=ON"
fi
@@ -53,9 +55,8 @@ prepare_build() {
cd "${BUILD_DIR}"
echo "Configuring with '${CMAKE_FLAGS} $@'."
cmake -G Ninja ${CMAKE_FLAGS} "$@" "${CI_BUILD_DIR}"
-}
-build_nvim() {
+
echo "Building nvim."
if ! top_make nvim ; then
exit 1
diff --git a/ci/common/suite.sh b/ci/common/suite.sh
index f6a8c22d21..8f6d81e264 100644
--- a/ci/common/suite.sh
+++ b/ci/common/suite.sh
@@ -47,13 +47,7 @@ exit_suite() {
ci_fold "end" ""
fi
export NVIM_TEST_CURRENT_SUITE="${NVIM_TEST_CURRENT_SUITE%/*}"
- if test "$1" != "--continue" ; then
- exit $FAILED
- else
- local saved_failed=$FAILED
- FAILED=0
- return $saved_failed
- fi
+ FAILED=0
}
fail() {
@@ -71,12 +65,6 @@ fail() {
FAILED=1
}
-run_test() {
- local cmd="$1"
- local test_name="$2"
- eval "$cmd" || fail "$test_name"
-}
-
ended_successfully() {
if test -f "${FAIL_SUMMARY_FILE}" ; then
echo 'Test failed, complete summary:'
@@ -100,7 +88,7 @@ run_suite() {
local suite_name="$2"
enter_suite "$suite_name"
- run_test "$command" "$suite_name"
- exit_suite --continue
+ eval "$command" || fail "$suite_name"
+ exit_suite
}
diff --git a/ci/common/test.sh b/ci/common/test.sh
index 798f2926c6..c5f67edd2c 100644
--- a/ci/common/test.sh
+++ b/ci/common/test.sh
@@ -87,18 +87,15 @@ check_sanitizer() {
}
run_unittests() {(
- enter_suite unittests
ulimit -c unlimited || true
if ! build_make unittest ; then
fail 'unittests' F 'Unit tests failed'
fi
submit_coverage unittest
check_core_dumps "$(command -v luajit)"
- exit_suite
)}
run_functionaltests() {(
- enter_suite functionaltests
ulimit -c unlimited || true
if ! build_make ${FUNCTIONALTEST}; then
fail 'functionaltests' F 'Functional tests failed'
@@ -107,11 +104,9 @@ run_functionaltests() {(
check_sanitizer "${LOG_DIR}"
valgrind_check "${LOG_DIR}"
check_core_dumps
- exit_suite
)}
run_oldtests() {(
- enter_suite oldtests
ulimit -c unlimited || true
if ! make oldtest; then
reset
@@ -121,7 +116,6 @@ run_oldtests() {(
check_sanitizer "${LOG_DIR}"
valgrind_check "${LOG_DIR}"
check_core_dumps
- exit_suite
)}
check_runtime_files() {(
@@ -146,7 +140,6 @@ check_runtime_files() {(
)}
install_nvim() {(
- enter_suite 'install_nvim'
if ! build_make install ; then
fail 'install' E 'make install failed'
exit_suite
@@ -179,6 +172,4 @@ install_nvim() {(
if ! grep -q "$gpat" "${INSTALL_PREFIX}/share/nvim/runtime/$genvimsynf" ; then
fail 'funcnames' F "It appears that $genvimsynf does not contain $gpat."
fi
-
- exit_suite
)}
diff --git a/ci/run_tests.sh b/ci/run_tests.sh
index 6c310ccc76..1baeb090a8 100755
--- a/ci/run_tests.sh
+++ b/ci/run_tests.sh
@@ -8,29 +8,17 @@ source "${CI_DIR}/common/build.sh"
source "${CI_DIR}/common/test.sh"
source "${CI_DIR}/common/suite.sh"
-enter_suite build
+run_suite 'build_nvim' 'build'
-check_core_dumps --delete quiet
-
-prepare_build
-build_nvim
-
-exit_suite --continue
-
-enter_suite tests
-
-if test "$CLANG_SANITIZER" != "TSAN" ; then
+if test "$CLANG_SANITIZER" != "TSAN"; then
# Additional threads are only created when the builtin UI starts, which
# doesn't happen in the unit/functional tests
if test "${FUNCTIONALTEST}" != "functionaltest-lua"; then
- run_test run_unittests unittests
+ run_suite run_unittests unittests
fi
- run_test run_functionaltests functionaltests
+ run_suite run_functionaltests functionaltests
fi
-run_test run_oldtests oldtests
-
-run_test install_nvim install_nvim
-
-exit_suite --continue
+run_suite run_oldtests oldtests
+run_suite install_nvim install_nvim
end_tests
diff --git a/runtime/doc/change.txt b/runtime/doc/change.txt
index e26a84f80f..b4d3304880 100644
--- a/runtime/doc/change.txt
+++ b/runtime/doc/change.txt
@@ -1118,8 +1118,11 @@ register. With blockwise selection it also depends on the size of the block
and whether the corners are on an existing character. (Implementation detail:
it actually works by first putting the register after the selection and then
deleting the selection.)
-The previously selected text is put in the unnamed register. If you want to
-put the same text into a Visual selection several times you need to use
+With 'p' the previously selected text is put in the unnamed register. This is
+useful if you want to put that text somewhere else. But you cannot repeat the
+same change.
+With 'P' the unnamed register is not changed, you can repeat the same change.
+But the deleted text cannot be used. If you do need it you can use 'p' with
another register. E.g., yank the text to copy, Visually select the text to
replace and use "0p . You can repeat this as many times as you like, and the
unnamed register will be changed each time.
diff --git a/runtime/doc/index.txt b/runtime/doc/index.txt
index f02f9f8032..e3bc3d5437 100644
--- a/runtime/doc/index.txt
+++ b/runtime/doc/index.txt
@@ -923,7 +923,9 @@ tag command note action in Visual mode ~
before the highlighted area
|v_J| J 2 join the highlighted lines
|v_K| K run 'keywordprg' on the highlighted area
-|v_O| O move horizontally to other corner of area.
+|v_O| O move horizontally to other corner of area
+|v_P| P replace highlighted area with register
+ contents; unnamed register is unchanged
Q does not start Ex mode
|v_R| R 2 delete the highlighted lines and start
insert
diff --git a/runtime/doc/quickfix.txt b/runtime/doc/quickfix.txt
index ed736ad4eb..5b68da8be9 100644
--- a/runtime/doc/quickfix.txt
+++ b/runtime/doc/quickfix.txt
@@ -1339,12 +1339,17 @@ Basic items
%f file name (finds a string)
%o module name (finds a string)
%l line number (finds a number)
+ %e end line number (finds a number)
%c column number (finds a number representing character
column of the error, byte index, a <tab> is 1
character column)
%v virtual column number (finds a number representing
screen column of the error (1 <tab> == 8 screen
columns))
+ %k end column number (finds a number representing
+ the character column of the error, byte index, or a
+ number representing screen end column of the error if
+ it's used with %v)
%t error type (finds a single character):
e - error message
w - warning message
diff --git a/runtime/doc/various.txt b/runtime/doc/various.txt
index fc0230c62d..38869f8e94 100644
--- a/runtime/doc/various.txt
+++ b/runtime/doc/various.txt
@@ -388,6 +388,8 @@ g8 Print the hex values of the bytes used in the
|:marks| - filter by text in the current file,
or file name for other files
|:oldfiles| - filter by file name
+ |:registers| - filter by register contents
+ (does not work multi-line)
|:set| - filter by option name
Only normal messages are filtered, error messages are
diff --git a/runtime/doc/visual.txt b/runtime/doc/visual.txt
index 5563a56216..4d5366a41a 100644
--- a/runtime/doc/visual.txt
+++ b/runtime/doc/visual.txt
@@ -255,6 +255,7 @@ Additionally the following commands can be used:
X delete (2) |v_X|
Y yank (2) |v_Y|
p put |v_p|
+ P put without unnamed register overwrite |v_P|
J join (1) |v_J|
U make uppercase |v_U|
u make lowercase |v_u|
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index ada041bab2..f7c55344f5 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -31,6 +31,7 @@
#include "nvim/file_search.h"
#include "nvim/fileio.h"
#include "nvim/getchar.h"
+#include "nvim/globals.h"
#include "nvim/highlight.h"
#include "nvim/highlight_defs.h"
#include "nvim/lua/executor.h"
@@ -545,20 +546,19 @@ void nvim_set_current_dir(String dir, Error *err)
return;
}
- char string[MAXPATHL];
+ char_u string[MAXPATHL];
memcpy(string, dir.data, dir.size);
string[dir.size] = NUL;
try_start();
- if (vim_chdir((char_u *)string)) {
+ if (!changedir_func(string, kCdScopeGlobal)) {
if (!try_end(err)) {
api_set_error(err, kErrorTypeException, "Failed to change directory");
}
return;
}
- post_chdir(kCdScopeGlobal, true);
try_end(err);
}
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index bb8483f644..96ddd9a2f5 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -3327,7 +3327,7 @@ void maketitle(void)
len = (int)STRLEN(buf_p);
if (len > 100) {
len -= 100;
- len += (*mb_tail_off)(buf_p, buf_p + len) + 1;
+ len += mb_tail_off(buf_p, buf_p + len) + 1;
buf_p += len;
}
STRCPY(icon_str, buf_p);
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 926c385892..c197754685 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -10700,7 +10700,7 @@ repeat:
pbuf = NULL;
// Need full path first (use expand_env() to remove a "~/")
if (!has_fullname && !has_homerelative) {
- if ((c == '.' || c == '~') && **fnamep == '~') {
+ if (**fnamep == '~') {
p = pbuf = expand_env_save(*fnamep);
} else {
p = pbuf = (char_u *)FullName_save((char *)*fnamep, FALSE);
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index e5cec0e060..090422088a 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -12,6 +12,7 @@
#include <string.h>
#include "nvim/ascii.h"
+#include "nvim/globals.h"
#include "nvim/vim.h"
#ifdef HAVE_LOCALE_H
# include <locale.h>
@@ -2190,9 +2191,11 @@ void ex_scriptnames(exarg_T *eap)
if (SCRIPT_ITEM(i).sn_name != NULL) {
home_replace(NULL, SCRIPT_ITEM(i).sn_name, NameBuff, MAXPATHL, true);
vim_snprintf((char *)IObuff, IOSIZE, "%3d: %s", i, NameBuff);
- msg_putchar('\n');
- msg_outtrans(IObuff);
- line_breakcheck();
+ if (!message_filtered(IObuff)) {
+ msg_putchar('\n');
+ msg_outtrans(IObuff);
+ line_breakcheck();
+ }
}
}
}
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index f28ee1bfcb..8e1be3bbf7 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -3318,7 +3318,7 @@ restore_backup:
if (end == 0
|| (lnum == end
&& (write_bin || !buf->b_p_fixeol)
- && (lnum == buf->b_no_eol_lnum
+ && ((write_bin && lnum == buf->b_no_eol_lnum)
|| (lnum == buf->b_ml.ml_line_count && !buf->b_p_eol)))) {
lnum++; // written the line, count it
no_eol = true;
diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c
index 7fa2562be0..e5fa80a242 100644
--- a/src/nvim/mbyte.c
+++ b/src/nvim/mbyte.c
@@ -1821,12 +1821,10 @@ void mb_copy_char(const char_u **const fp, char_u **const tp)
*fp += l;
}
-/*
- * Return the offset from "p" to the first byte of a character. When "p" is
- * at the start of a character 0 is returned, otherwise the offset to the next
- * character. Can start anywhere in a stream of bytes.
- */
-int mb_off_next(char_u *base, char_u *p)
+/// Return the offset from "p" to the first byte of a character. When "p" is
+/// at the start of a character 0 is returned, otherwise the offset to the next
+/// character. Can start anywhere in a stream of bytes.
+int mb_off_next(const char_u *base, const char_u *p)
{
int i;
int j;
@@ -1854,7 +1852,7 @@ int mb_off_next(char_u *base, char_u *p)
/// Return the offset from "p" to the last byte of the character it points
/// into. Can start anywhere in a stream of bytes.
/// Composing characters are not included.
-int mb_tail_off(char_u *base, char_u *p)
+int mb_tail_off(const char_u *base, const char_u *p)
{
int i;
int j;
@@ -1882,12 +1880,13 @@ int mb_tail_off(char_u *base, char_u *p)
/// Return the offset from "p" to the first byte of the character it points
/// into. Can start anywhere in a stream of bytes.
+/// Unlike utf_head_off() this doesn't include composing characters and returns a negative value.
///
/// @param[in] base Pointer to start of string
/// @param[in] p Pointer to byte for which to return the offset to the previous codepoint
//
/// @return 0 if invalid sequence, else offset to previous codepoint
-int mb_head_off(char_u *base, char_u *p)
+int mb_head_off(const char_u *base, const char_u *p)
{
int i;
int j;
@@ -2037,13 +2036,11 @@ char_u *mb_prevptr(char_u *line, char_u *p)
return p;
}
-/*
- * Return the character length of "str". Each multi-byte character (with
- * following composing characters) counts as one.
- */
-int mb_charlen(char_u *str)
+/// Return the character length of "str". Each multi-byte character (with
+/// following composing characters) counts as one.
+int mb_charlen(const char_u *str)
{
- char_u *p = str;
+ const char_u *p = str;
int count;
if (p == NULL) {
@@ -2057,12 +2054,10 @@ int mb_charlen(char_u *str)
return count;
}
-/*
- * Like mb_charlen() but for a string with specified length.
- */
-int mb_charlen_len(char_u *str, int len)
+/// Like mb_charlen() but for a string with specified length.
+int mb_charlen_len(const char_u *str, int len)
{
- char_u *p = str;
+ const char_u *p = str;
int count;
for (count = 0; *p != NUL && p < str + len; count++) {
@@ -2201,11 +2196,9 @@ char_u *enc_canonize(char_u *enc) FUNC_ATTR_NONNULL_RET
return r;
}
-/*
- * Search for an encoding alias of "name".
- * Returns -1 when not found.
- */
-static int enc_alias_search(char_u *name)
+/// Search for an encoding alias of "name".
+/// Returns -1 when not found.
+static int enc_alias_search(const char_u *name)
{
int i;
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 225c66aae1..21c465434a 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -7509,9 +7509,9 @@ static void nv_put_opt(cmdarg_T *cap, bool fix_indent)
// overwrites if the old contents is being put.
was_visual = true;
regname = cap->oap->regname;
+ bool save_unnamed = cap->cmdchar == 'P';
// '+' and '*' could be the same selection
- bool clipoverwrite = (regname == '+' || regname == '*')
- && (cb_flags & CB_UNNAMEDMASK);
+ bool clipoverwrite = (regname == '+' || regname == '*') && (cb_flags & CB_UNNAMEDMASK);
if (regname == 0 || regname == '"' || clipoverwrite
|| ascii_isdigit(regname) || regname == '-') {
// The delete might overwrite the register we want to put, save it first
@@ -7524,6 +7524,10 @@ static void nv_put_opt(cmdarg_T *cap, bool fix_indent)
// do_put(), which requires the visual selection to still be active.
if (!VIsual_active || VIsual_mode == 'V' || regname != '.') {
// Now delete the selected text. Avoid messages here.
+ yankreg_T *old_y_previous;
+ if (save_unnamed) {
+ old_y_previous = get_y_previous();
+ }
cap->cmdchar = 'd';
cap->nchar = NUL;
cap->oap->regname = NUL;
@@ -7533,6 +7537,10 @@ static void nv_put_opt(cmdarg_T *cap, bool fix_indent)
empty = (curbuf->b_ml.ml_flags & ML_EMPTY);
msg_silent--;
+ if (save_unnamed) {
+ set_y_previous(old_y_previous);
+ }
+
// delete PUT_LINE_BACKWARD;
cap->oap->regname = regname;
}
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index b8b639265c..f999b68236 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -135,10 +135,18 @@ static char opchars[][3] =
{ Ctrl_X, NUL, OPF_CHANGE }, // OP_NR_SUB
};
-/*
- * Translate a command name into an operator type.
- * Must only be called with a valid operator name!
- */
+yankreg_T *get_y_previous(void)
+{
+ return y_previous;
+}
+
+void set_y_previous(yankreg_T *yreg)
+{
+ y_previous = yreg;
+}
+
+/// Translate a command name into an operator type.
+/// Must only be called with a valid operator name!
int get_op_type(int char1, int char2)
{
int i;
@@ -566,7 +574,7 @@ static void block_insert(oparg_T *oap, char_u *s, int b_insert, struct block_def
if (b_insert) {
off = utf_head_off(oldp, oldp + offset + spaces);
} else {
- off = (*mb_off_next)(oldp, oldp + offset);
+ off = mb_off_next(oldp, oldp + offset);
offset += off;
}
spaces -= off;
@@ -3724,7 +3732,7 @@ void ex_display(exarg_T *eap)
int name;
char_u *arg = eap->arg;
int clen;
- char_u type[2];
+ int type;
if (arg != NULL && *arg == NUL) {
arg = NULL;
@@ -3737,11 +3745,11 @@ void ex_display(exarg_T *eap)
name = get_register_name(i);
switch (get_reg_type(name, NULL)) {
case kMTLineWise:
- type[0] = 'l'; break;
+ type = 'l'; break;
case kMTCharWise:
- type[0] = 'c'; break;
+ type = 'c'; break;
default:
- type[0] = 'b'; break;
+ type = 'b'; break;
}
if (arg != NULL && vim_strchr(arg, name) == NULL) {
@@ -3768,88 +3776,87 @@ void ex_display(exarg_T *eap)
}
if (yb->y_array != NULL) {
- msg_putchar('\n');
- msg_puts(" ");
- msg_putchar(type[0]);
- msg_puts(" ");
- msg_putchar('"');
- msg_putchar(name);
- msg_puts(" ");
-
- int n = Columns - 11;
- for (size_t j = 0; j < yb->y_size && n > 1; j++) {
- if (j) {
- msg_puts_attr("^J", attr);
- n -= 2;
+ bool do_show = false;
+
+ for (size_t j = 0; !do_show && j < yb->y_size; j++) {
+ do_show = !message_filtered(yb->y_array[j]);
+ }
+
+ if (do_show || yb->y_size == 0) {
+ msg_putchar('\n');
+ msg_puts(" ");
+ msg_putchar(type);
+ msg_puts(" ");
+ msg_putchar('"');
+ msg_putchar(name);
+ msg_puts(" ");
+
+ int n = Columns - 11;
+ for (size_t j = 0; j < yb->y_size && n > 1; j++) {
+ if (j) {
+ msg_puts_attr("^J", attr);
+ n -= 2;
+ }
+ for (p = yb->y_array[j]; *p && (n -= ptr2cells(p)) >= 0; p++) {
+ clen = utfc_ptr2len(p);
+ msg_outtrans_len(p, clen);
+ p += clen - 1;
+ }
}
- for (p = yb->y_array[j]; *p && (n -= ptr2cells(p)) >= 0; p++) { // -V1019 NOLINT(whitespace/line_length)
- clen = utfc_ptr2len(p);
- msg_outtrans_len(p, clen);
- p += clen - 1;
+ if (n > 1 && yb->y_type == kMTLineWise) {
+ msg_puts_attr("^J", attr);
}
+ ui_flush(); // show one line at a time
}
- if (n > 1 && yb->y_type == kMTLineWise) {
- msg_puts_attr("^J", attr);
- }
- ui_flush(); // show one line at a time
+ os_breakcheck();
}
- os_breakcheck();
}
- /*
- * display last inserted text
- */
+ // display last inserted text
if ((p = get_last_insert()) != NULL
- && (arg == NULL || vim_strchr(arg, '.') != NULL) && !got_int) {
+ && (arg == NULL || vim_strchr(arg, '.') != NULL) && !got_int
+ && !message_filtered(p)) {
msg_puts("\n c \". ");
dis_msg(p, true);
}
- /*
- * display last command line
- */
+ // display last command line
if (last_cmdline != NULL && (arg == NULL || vim_strchr(arg, ':') != NULL)
- && !got_int) {
+ && !got_int && !message_filtered(last_cmdline)) {
msg_puts("\n c \": ");
dis_msg(last_cmdline, false);
}
- /*
- * display current file name
- */
+ // display current file name
if (curbuf->b_fname != NULL
- && (arg == NULL || vim_strchr(arg, '%') != NULL) && !got_int) {
+ && (arg == NULL || vim_strchr(arg, '%') != NULL) && !got_int
+ && !message_filtered(curbuf->b_fname)) {
msg_puts("\n c \"% ");
dis_msg(curbuf->b_fname, false);
}
- /*
- * display alternate file name
- */
+ // display alternate file name
if ((arg == NULL || vim_strchr(arg, '%') != NULL) && !got_int) {
char_u *fname;
linenr_T dummy;
- if (buflist_name_nr(0, &fname, &dummy) != FAIL) {
+ if (buflist_name_nr(0, &fname, &dummy) != FAIL && !message_filtered(fname)) {
msg_puts("\n c \"# ");
dis_msg(fname, false);
}
}
- /*
- * display last search pattern
- */
+ // display last search pattern
if (last_search_pat() != NULL
- && (arg == NULL || vim_strchr(arg, '/') != NULL) && !got_int) {
+ && (arg == NULL || vim_strchr(arg, '/') != NULL) && !got_int
+ && !message_filtered(last_search_pat())) {
msg_puts("\n c \"/ ");
dis_msg(last_search_pat(), false);
}
- /*
- * display last used expression
- */
+ // display last used expression
if (expr_line != NULL && (arg == NULL || vim_strchr(arg, '=') != NULL)
- && !got_int) {
+ && !got_int && !message_filtered(expr_line)) {
msg_puts("\n c \"= ");
dis_msg(expr_line, false);
}
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index d4b71994cc..b12f407460 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -131,7 +131,7 @@ struct qf_info_S {
static qf_info_T ql_info; // global quickfix list
static unsigned last_qf_id = 0; // Last Used quickfix list id
-#define FMT_PATTERNS 11 // maximum number of % recognized
+#define FMT_PATTERNS 13 // maximum number of % recognized
// Structure used to hold the info of one part of 'errorformat'
typedef struct efm_S efm_T;
@@ -332,22 +332,27 @@ int qf_init(win_T *wp, const char_u *restrict efile, char_u *restrict errorforma
// Maximum number of bytes allowed per line while reading an errorfile.
static const size_t LINE_MAXLEN = 4096;
+/// Patterns used. Keep in sync with qf_parse_fmt[].
static struct fmtpattern {
char_u convchar;
char *pattern;
} fmt_pat[FMT_PATTERNS] =
{
- { 'f', ".\\+" }, // only used when at end
- { 'n', "\\d\\+" },
- { 'l', "\\d\\+" },
- { 'c', "\\d\\+" },
- { 't', "." },
- { 'm', ".\\+" },
- { 'r', ".*" },
- { 'p', "[- .]*"}, // NOLINT(whitespace/tab)
- { 'v', "\\d\\+" },
- { 's', ".\\+" },
- { 'o', ".\\+" }
+ { 'f', ".\\+" }, // only used when at end
+ { 'n', "\\d\\+" }, // 1
+ { 'l', "\\d\\+" }, // 2
+ { 'e', "\\d\\+" }, // 3
+ { 'c', "\\d\\+" }, // 4
+ { 'k', "\\d\\+" }, // 5
+ { 't', "." }, // 6
+#define FMT_PATTERN_M 7
+ { 'm', ".\\+" }, // 7
+#define FMT_PATTERN_R 8
+ { 'r', ".*" }, // 8
+ { 'p', "[- \t.]*" }, // 9
+ { 'v', "\\d\\+" }, // 10
+ { 's', ".\\+" }, // 11
+ { 'o', ".\\+" } // 12
};
/// Convert an errorformat pattern to a regular expression pattern.
@@ -363,9 +368,9 @@ static char_u *efmpat_to_regpat(const char_u *efmpat, char_u *regpat, efm_T *efm
semsg(_("E372: Too many %%%c in format string"), *efmpat);
return NULL;
}
- if ((idx && idx < 6
+ if ((idx && idx < FMT_PATTERN_R
&& vim_strchr((char_u *)"DXOPQ", efminfo->prefix) != NULL)
- || (idx == 6
+ || (idx == FMT_PATTERN_R
&& vim_strchr((char_u *)"OPQ", efminfo->prefix) == NULL)) {
semsg(_("E373: Unexpected %%%c in format string"), *efmpat);
return NULL;
@@ -1288,7 +1293,7 @@ static int qf_parse_fmt_n(regmatch_T *rmp, int midx, qffields_T *fields)
return QF_OK;
}
-/// Parse the match for line number (%l') pattern in regmatch.
+/// Parse the match for line number ('%l') pattern in regmatch.
/// Return the matched value in "fields->lnum".
static int qf_parse_fmt_l(regmatch_T *rmp, int midx, qffields_T *fields)
{
@@ -1299,6 +1304,17 @@ static int qf_parse_fmt_l(regmatch_T *rmp, int midx, qffields_T *fields)
return QF_OK;
}
+/// Parse the match for end line number ('%e') pattern in regmatch.
+/// Return the matched value in "fields->end_lnum".
+static int qf_parse_fmt_e(regmatch_T *rmp, int midx, qffields_T *fields)
+{
+ if (rmp->startp[midx] == NULL) {
+ return QF_FAIL;
+ }
+ fields->end_lnum = atol((char *)rmp->startp[midx]);
+ return QF_OK;
+}
+
/// Parse the match for column number ('%c') pattern in regmatch.
/// Return the matched value in "fields->col".
static int qf_parse_fmt_c(regmatch_T *rmp, int midx, qffields_T *fields)
@@ -1310,6 +1326,17 @@ static int qf_parse_fmt_c(regmatch_T *rmp, int midx, qffields_T *fields)
return QF_OK;
}
+/// Parse the match for end line number ('%e') pattern in regmatch.
+/// Return the matched value in "fields->end_lnum".
+static int qf_parse_fmt_k(regmatch_T *rmp, int midx, qffields_T *fields)
+{
+ if (rmp->startp[midx] == NULL) {
+ return QF_FAIL;
+ }
+ fields->end_col = (int)atol((char *)rmp->startp[midx]);
+ return QF_OK;
+}
+
/// Parse the match for error type ('%t') pattern in regmatch.
/// Return the matched value in "fields->type".
static int qf_parse_fmt_t(regmatch_T *rmp, int midx, qffields_T *fields)
@@ -1442,14 +1469,17 @@ static int qf_parse_fmt_o(regmatch_T *rmp, int midx, qffields_T *fields)
/// 'errorformat' format pattern parser functions.
/// The '%f' and '%r' formats are parsed differently from other formats.
/// See qf_parse_match() for details.
+/// Keep in sync with fmt_pat[].
static int (*qf_parse_fmt[FMT_PATTERNS])(regmatch_T *, int, qffields_T *) = {
- NULL,
+ NULL, // %f
qf_parse_fmt_n,
qf_parse_fmt_l,
+ qf_parse_fmt_e,
qf_parse_fmt_c,
+ qf_parse_fmt_k,
qf_parse_fmt_t,
qf_parse_fmt_m,
- NULL,
+ NULL, // %r
qf_parse_fmt_p,
qf_parse_fmt_v,
qf_parse_fmt_s,
@@ -1485,13 +1515,13 @@ static int qf_parse_match(char_u *linebuf, size_t linelen, efm_T *fmt_ptr, regma
midx = (int)fmt_ptr->addr[i];
if (i == 0 && midx > 0) { // %f
status = qf_parse_fmt_f(regmatch, midx, fields, idx);
- } else if (i == 5) {
+ } else if (i == FMT_PATTERN_M) {
if (fmt_ptr->flags == '+' && !qf_multiscan) { // %+
qf_parse_fmt_plus(linebuf, linelen, fields);
} else if (midx > 0) { // %m
status = qf_parse_fmt_m(regmatch, midx, fields);
}
- } else if (i == 6 && midx > 0) { // %r
+ } else if (i == FMT_PATTERN_R && midx > 0) { // %r
status = qf_parse_fmt_r(regmatch, midx, tail);
} else if (midx > 0) { // others
status = (qf_parse_fmt[i])(regmatch, midx, fields);
@@ -1636,10 +1666,16 @@ static int qf_parse_multiline_pfx(int idx, qf_list_T *qfl, qffields_T *fields)
if (!qfprev->qf_lnum) {
qfprev->qf_lnum = fields->lnum;
}
+ if (!qfprev->qf_end_lnum) {
+ qfprev->qf_end_lnum = fields->end_lnum;
+ }
if (!qfprev->qf_col) {
qfprev->qf_col = fields->col;
qfprev->qf_viscol = fields->use_viscol;
}
+ if (!qfprev->qf_end_col) {
+ qfprev->qf_end_col = fields->end_col;
+ }
if (!qfprev->qf_fnum) {
qfprev->qf_fnum = qf_get_fnum(qfl, qfl->qf_directory,
*fields->namebuf || qfl->qf_directory
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 6b2a2afa41..0644a08210 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -3753,34 +3753,30 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
}
c = wp->w_p_lcs_chars.tab1;
p = xmalloc(len + 1);
- if (p == NULL) {
- n_extra = 0;
- } else {
- memset(p, ' ', len);
- p[len] = NUL;
- xfree(p_extra_free);
- p_extra_free = p;
- for (i = 0; i < tab_len; i++) {
- if (*p == NUL) {
- tab_len = i;
- break;
- }
- int lcs = wp->w_p_lcs_chars.tab2;
-
- // if tab3 is given, use it for the last char
- if (wp->w_p_lcs_chars.tab3 && i == tab_len - 1) {
- lcs = wp->w_p_lcs_chars.tab3;
- }
- p += utf_char2bytes(lcs, p);
- n_extra += utf_char2len(lcs) - (saved_nextra > 0 ? 1 : 0);
+ memset(p, ' ', len);
+ p[len] = NUL;
+ xfree(p_extra_free);
+ p_extra_free = p;
+ for (i = 0; i < tab_len; i++) {
+ if (*p == NUL) {
+ tab_len = i;
+ break;
}
- p_extra = p_extra_free;
+ int lcs = wp->w_p_lcs_chars.tab2;
- // n_extra will be increased by FIX_FOX_BOGUSCOLS
- // macro below, so need to adjust for that here
- if (vcol_off > 0) {
- n_extra -= vcol_off;
+ // if tab3 is given, use it for the last char
+ if (wp->w_p_lcs_chars.tab3 && i == tab_len - 1) {
+ lcs = wp->w_p_lcs_chars.tab3;
}
+ p += utf_char2bytes(lcs, p);
+ n_extra += utf_char2len(lcs) - (saved_nextra > 0 ? 1 : 0);
+ }
+ p_extra = p_extra_free;
+
+ // n_extra will be increased by FIX_FOX_BOGUSCOLS
+ // macro below, so need to adjust for that here
+ if (vcol_off > 0) {
+ n_extra -= vcol_off;
}
}
diff --git a/src/nvim/testdir/test_cursor_func.vim b/src/nvim/testdir/test_cursor_func.vim
index f2ffd50726..47e74a24d6 100644
--- a/src/nvim/testdir/test_cursor_func.vim
+++ b/src/nvim/testdir/test_cursor_func.vim
@@ -75,7 +75,6 @@ func Test_curswant_with_cursorline()
endfunc
func Test_screenpos()
- throw 'skipped: TODO: '
rightbelow new
rightbelow 20vsplit
call setline(1, ["\tsome text", "long wrapping line here", "next line"])
@@ -103,9 +102,10 @@ func Test_screenpos()
bwipe!
call assert_equal({'col': 1, 'row': 1, 'endcol': 1, 'curscol': 1}, screenpos(win_getid(), 1, 1))
- nmenu WinBar.TEST :
- call assert_equal({'col': 1, 'row': 2, 'endcol': 1, 'curscol': 1}, screenpos(win_getid(), 1, 1))
- nunmenu WinBar.TEST
+ " Needs WinBar
+ " nmenu WinBar.TEST :
+ " call assert_equal({'col': 1, 'row': 2, 'endcol': 1, 'curscol': 1}, screenpos(win_getid(), 1, 1))
+ " nunmenu WinBar.TEST
endfunc
func Test_screenpos_number()
diff --git a/src/nvim/testdir/test_filter_cmd.vim b/src/nvim/testdir/test_filter_cmd.vim
index 0c45db049b..d465e48c7b 100644
--- a/src/nvim/testdir/test_filter_cmd.vim
+++ b/src/nvim/testdir/test_filter_cmd.vim
@@ -145,3 +145,38 @@ func Test_filter_commands()
bwipe! file.h
bwipe! file.hs
endfunc
+
+func Test_filter_display()
+ edit Xdoesnotmatch
+ let @a = '!!willmatch'
+ let @b = '!!doesnotmatch'
+ let @c = "oneline\ntwoline\nwillmatch\n"
+ let @/ = '!!doesnotmatch'
+ call feedkeys(":echo '!!doesnotmatch:'\<CR>", 'ntx')
+ let lines = map(split(execute('filter /willmatch/ display'), "\n"), 'v:val[5:6]')
+
+ call assert_true(index(lines, '"a') >= 0)
+ call assert_false(index(lines, '"b') >= 0)
+ call assert_true(index(lines, '"c') >= 0)
+ call assert_false(index(lines, '"/') >= 0)
+ call assert_false(index(lines, '":') >= 0)
+ call assert_false(index(lines, '"%') >= 0)
+
+ let lines = map(split(execute('filter /doesnotmatch/ display'), "\n"), 'v:val[5:6]')
+ call assert_true(index(lines, '"a') < 0)
+ call assert_false(index(lines, '"b') < 0)
+ call assert_true(index(lines, '"c') < 0)
+ call assert_false(index(lines, '"/') < 0)
+ call assert_false(index(lines, '":') < 0)
+ call assert_false(index(lines, '"%') < 0)
+
+ bwipe!
+endfunc
+
+func Test_filter_scriptnames()
+ let lines = split(execute('filter /test_filter_cmd/ scriptnames'), "\n")
+ call assert_equal(1, len(lines))
+ call assert_match('filter_cmd', lines[0])
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim
index 00679e1958..c4d70fb1de 100644
--- a/src/nvim/testdir/test_quickfix.vim
+++ b/src/nvim/testdir/test_quickfix.vim
@@ -1384,6 +1384,29 @@ func Test_efm_error_type()
let &efm = save_efm
endfunc
+" Test for end_lnum ('%e') and end_col ('%k') fields in 'efm'
+func Test_efm_end_lnum_col()
+ let save_efm = &efm
+
+ " single line
+ set efm=%f:%l-%e:%c-%k:%t:%m
+ cexpr ["Xfile1:10-20:1-2:E:msg1", "Xfile1:20-30:2-3:W:msg2",]
+ let output = split(execute('clist'), "\n")
+ call assert_equal([
+ \ ' 1 Xfile1:10-20 col 1-2 error: msg1',
+ \ ' 2 Xfile1:20-30 col 2-3 warning: msg2'], output)
+
+ " multiple lines
+ set efm=%A%n)%m,%Z%f:%l-%e:%c-%k
+ cexpr ["1)msg1", "Xfile1:14-24:1-2",
+ \ "2)msg2", "Xfile1:24-34:3-4"]
+ let output = split(execute('clist'), "\n")
+ call assert_equal([
+ \ ' 1 Xfile1:14-24 col 1-2 error 1: msg1',
+ \ ' 2 Xfile1:24-34 col 3-4 error 2: msg2'], output)
+ let &efm = save_efm
+endfunc
+
func XquickfixChangedByAutocmd(cchar)
call s:setup_commands(a:cchar)
if a:cchar == 'c'
diff --git a/src/nvim/testdir/test_visual.vim b/src/nvim/testdir/test_visual.vim
index 76274fb038..099a90643f 100644
--- a/src/nvim/testdir/test_visual.vim
+++ b/src/nvim/testdir/test_visual.vim
@@ -1184,8 +1184,66 @@ func Test_visual_undo_deletes_last_line()
exe "normal ggvjfxO"
undo
normal gNU
+
bwipe!
endfunc
+func Test_visual_paste()
+ new
+
+ " v_p overwrites unnamed register.
+ call setline(1, ['xxxx'])
+ call setreg('"', 'foo')
+ call setreg('-', 'bar')
+ normal gg0vp
+ call assert_equal('x', @")
+ call assert_equal('x', @-)
+ call assert_equal('fooxxx', getline(1))
+ normal $vp
+ call assert_equal('x', @")
+ call assert_equal('x', @-)
+ call assert_equal('fooxxx', getline(1))
+ " Test with a different register as unnamed register.
+ call setline(2, ['baz'])
+ normal 2gg0"rD
+ call assert_equal('baz', @")
+ normal gg0vp
+ call assert_equal('f', @")
+ call assert_equal('f', @-)
+ call assert_equal('bazooxxx', getline(1))
+ normal $vp
+ call assert_equal('x', @")
+ call assert_equal('x', @-)
+ call assert_equal('bazooxxf', getline(1))
+
+ if has('clipboard')
+ " v_P does not overwrite unnamed register.
+ call setline(1, ['xxxx'])
+ call setreg('"', 'foo')
+ call setreg('-', 'bar')
+ normal gg0vP
+ call assert_equal('foo', @")
+ call assert_equal('x', @-)
+ call assert_equal('fooxxx', getline(1))
+ normal $vP
+ call assert_equal('foo', @")
+ call assert_equal('x', @-)
+ call assert_equal('fooxxfoo', getline(1))
+ " Test with a different register as unnamed register.
+ call setline(2, ['baz'])
+ normal 2gg0"rD
+ call assert_equal('baz', @")
+ normal gg0vP
+ call assert_equal('baz', @")
+ call assert_equal('f', @-)
+ call assert_equal('bazooxxfoo', getline(1))
+ normal $vP
+ call assert_equal('baz', @")
+ call assert_equal('o', @-)
+ call assert_equal('bazooxxfobaz', getline(1))
+ endif
+
+ bwipe!
+endfunc
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_writefile.vim b/src/nvim/testdir/test_writefile.vim
index 1d9fc6e3f7..b42665c9b5 100644
--- a/src/nvim/testdir/test_writefile.vim
+++ b/src/nvim/testdir/test_writefile.vim
@@ -369,6 +369,154 @@ func Test_write_file_encoding()
%bw!
endfunc
+" Test for writing and reading a file starting with a BOM.
+" Byte Order Mark (BOM) character for various encodings is below:
+" UTF-8 : EF BB BF
+" UTF-16 (BE): FE FF
+" UTF-16 (LE): FF FE
+" UTF-32 (BE): 00 00 FE FF
+" UTF-32 (LE): FF FE 00 00
+func Test_readwrite_file_with_bom()
+ let utf8_bom = "\xEF\xBB\xBF"
+ let utf16be_bom = "\xFE\xFF"
+ let utf16le_bom = "\xFF\xFE"
+ let utf32be_bom = "\n\n\xFE\xFF"
+ let utf32le_bom = "\xFF\xFE\n\n"
+ let save_fileencoding = &fileencoding
+ set cpoptions+=S
+
+ " Check that editing a latin1 file doesn't see a BOM
+ call writefile(["\xFE\xFElatin-1"], 'Xtest1')
+ edit Xtest1
+ call assert_equal('latin1', &fileencoding)
+ call assert_equal(0, &bomb)
+ set fenc=latin1
+ write Xfile2
+ call assert_equal(["\xFE\xFElatin-1", ''], readfile('Xfile2', 'b'))
+ set bomb fenc=latin1
+ write Xtest3
+ call assert_equal(["\xFE\xFElatin-1", ''], readfile('Xtest3', 'b'))
+ set bomb&
+
+ " Check utf-8 BOM
+ %bw!
+ call writefile([utf8_bom .. "utf-8"], 'Xtest1')
+ edit! Xtest1
+ call assert_equal('utf-8', &fileencoding)
+ call assert_equal(1, &bomb)
+ call assert_equal('utf-8', getline(1))
+ set fenc=latin1
+ write! Xfile2
+ call assert_equal(['utf-8', ''], readfile('Xfile2', 'b'))
+ set fenc=utf-8
+ w! Xtest3
+ call assert_equal([utf8_bom .. "utf-8", ''], readfile('Xtest3', 'b'))
+
+ " Check utf-8 with an error (will fall back to latin-1)
+ %bw!
+ call writefile([utf8_bom .. "utf-8\x80err"], 'Xtest1')
+ edit! Xtest1
+ call assert_equal('latin1', &fileencoding)
+ call assert_equal(0, &bomb)
+ call assert_equal("\xC3\xAF\xC2\xBB\xC2\xBFutf-8\xC2\x80err", getline(1))
+ set fenc=latin1
+ write! Xfile2
+ call assert_equal([utf8_bom .. "utf-8\x80err", ''], readfile('Xfile2', 'b'))
+ set fenc=utf-8
+ w! Xtest3
+ call assert_equal(["\xC3\xAF\xC2\xBB\xC2\xBFutf-8\xC2\x80err", ''],
+ \ readfile('Xtest3', 'b'))
+
+ " Check ucs-2 BOM
+ %bw!
+ call writefile([utf16be_bom .. "\nu\nc\ns\n-\n2\n"], 'Xtest1')
+ edit! Xtest1
+ call assert_equal('utf-16', &fileencoding)
+ call assert_equal(1, &bomb)
+ call assert_equal('ucs-2', getline(1))
+ set fenc=latin1
+ write! Xfile2
+ call assert_equal(["ucs-2", ''], readfile('Xfile2', 'b'))
+ set fenc=ucs-2
+ w! Xtest3
+ call assert_equal([utf16be_bom .. "\nu\nc\ns\n-\n2\n", ''],
+ \ readfile('Xtest3', 'b'))
+
+ " Check ucs-2le BOM
+ %bw!
+ call writefile([utf16le_bom .. "u\nc\ns\n-\n2\nl\ne\n"], 'Xtest1')
+ " Need to add a NUL byte after the NL byte
+ call writefile(0z00, 'Xtest1', 'a')
+ edit! Xtest1
+ call assert_equal('utf-16le', &fileencoding)
+ call assert_equal(1, &bomb)
+ call assert_equal('ucs-2le', getline(1))
+ set fenc=latin1
+ write! Xfile2
+ call assert_equal(["ucs-2le", ''], readfile('Xfile2', 'b'))
+ set fenc=ucs-2le
+ w! Xtest3
+ call assert_equal([utf16le_bom .. "u\nc\ns\n-\n2\nl\ne\n", "\n"],
+ \ readfile('Xtest3', 'b'))
+
+ " Check ucs-4 BOM
+ %bw!
+ call writefile([utf32be_bom .. "\n\n\nu\n\n\nc\n\n\ns\n\n\n-\n\n\n4\n\n\n"], 'Xtest1')
+ edit! Xtest1
+ call assert_equal('ucs-4', &fileencoding)
+ call assert_equal(1, &bomb)
+ call assert_equal('ucs-4', getline(1))
+ set fenc=latin1
+ write! Xfile2
+ call assert_equal(["ucs-4", ''], readfile('Xfile2', 'b'))
+ set fenc=ucs-4
+ w! Xtest3
+ call assert_equal([utf32be_bom .. "\n\n\nu\n\n\nc\n\n\ns\n\n\n-\n\n\n4\n\n\n", ''], readfile('Xtest3', 'b'))
+
+ " Check ucs-4le BOM
+ %bw!
+ call writefile([utf32le_bom .. "u\n\n\nc\n\n\ns\n\n\n-\n\n\n4\n\n\nl\n\n\ne\n\n\n"], 'Xtest1')
+ " Need to add three NUL bytes after the NL byte
+ call writefile(0z000000, 'Xtest1', 'a')
+ edit! Xtest1
+ call assert_equal('ucs-4le', &fileencoding)
+ call assert_equal(1, &bomb)
+ call assert_equal('ucs-4le', getline(1))
+ set fenc=latin1
+ write! Xfile2
+ call assert_equal(["ucs-4le", ''], readfile('Xfile2', 'b'))
+ set fenc=ucs-4le
+ w! Xtest3
+ call assert_equal([utf32le_bom .. "u\n\n\nc\n\n\ns\n\n\n-\n\n\n4\n\n\nl\n\n\ne\n\n\n", "\n\n\n"], readfile('Xtest3', 'b'))
+
+ set cpoptions-=S
+ let &fileencoding = save_fileencoding
+ call delete('Xtest1')
+ call delete('Xfile2')
+ call delete('Xtest3')
+ %bw!
+endfunc
+
+func Test_read_write_bin()
+ " write file missing EOL
+ call writefile(['noeol'], "XNoEolSetEol", 'bS')
+ call assert_equal(0z6E6F656F6C, readfile('XNoEolSetEol', 'B'))
+
+ " when file is read 'eol' is off
+ set nofixeol
+ e! ++ff=unix XNoEolSetEol
+ call assert_equal(0, &eol)
+
+ " writing with 'eol' set adds the newline
+ setlocal eol
+ w
+ call assert_equal(0z6E6F656F6C0A, readfile('XNoEolSetEol', 'B'))
+
+ call delete('XNoEolSetEol')
+ set ff&
+ bwipe! XNoEolSetEol
+endfunc
+
" Check that buffer is written before triggering QuitPre
func Test_wq_quitpre_autocommand()
edit Xsomefile
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index 937b6559de..ccf3e81b22 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -536,6 +536,31 @@ describe('API', function()
end)
end)
+ describe('nvim_set_current_dir', function()
+ local start_dir
+
+ before_each(function()
+ clear()
+ funcs.mkdir("Xtestdir")
+ start_dir = funcs.getcwd()
+ end)
+
+ after_each(function()
+ helpers.rmdir("Xtestdir")
+ end)
+
+ it('works', function()
+ meths.set_current_dir("Xtestdir")
+ eq(funcs.getcwd(), start_dir .. helpers.get_pathsep() .. "Xtestdir")
+ end)
+
+ it('sets previous directory', function()
+ meths.set_current_dir("Xtestdir")
+ meths.exec('cd -', false)
+ eq(funcs.getcwd(), start_dir)
+ end)
+ end)
+
describe('nvim_exec_lua', function()
it('works', function()
meths.exec_lua('vim.api.nvim_set_var("test", 3)', {})
diff --git a/test/functional/editor/put_spec.lua b/test/functional/editor/put_spec.lua
index fdda2be131..c367f8fdd0 100644
--- a/test/functional/editor/put_spec.lua
+++ b/test/functional/editor/put_spec.lua
@@ -507,7 +507,9 @@ describe('put command', function()
return function(exception_table, after_redo)
test_expect(exception_table, after_redo)
if selection_string then
- eq(selection_string, getreg('"'))
+ if not conversion_table.put_backwards then
+ eq(selection_string, getreg('"'))
+ end
else
eq('test_string"', getreg('"'))
end
@@ -714,7 +716,9 @@ describe('put command', function()
expect_base, conversion_table)
return function(exception_table, after_redo)
test_expect(exception_table, after_redo)
- eq('Line of words 1\n', getreg('"'))
+ if not conversion_table.put_backwards then
+ eq('Line of words 1\n', getreg('"'))
+ end
end
end
local base_expect_string = [[
@@ -748,7 +752,9 @@ describe('put command', function()
end, expect_base, conversion_table)
return function(e,c)
test_expect(e,c)
- eq('Lin\nLin', getreg('"'))
+ if not conversion_table.put_backwards then
+ eq('Lin\nLin', getreg('"'))
+ end
end
end