aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--ISSUE_TEMPLATE.md11
-rw-r--r--runtime/doc/change.txt18
-rw-r--r--runtime/doc/eval.txt28
-rw-r--r--runtime/doc/options.txt31
-rw-r--r--runtime/doc/quickref.txt1
-rw-r--r--runtime/doc/tagsrch.txt31
-rw-r--r--runtime/doc/usr_29.txt3
-rw-r--r--runtime/optwin.vim4
-rwxr-xr-xscripts/git-log-pretty-since.sh32
-rwxr-xr-xscripts/release.sh63
-rwxr-xr-xscripts/vim-patch.sh20
-rw-r--r--src/nvim/buffer.c1
-rw-r--r--src/nvim/buffer_defs.h46
-rw-r--r--src/nvim/edit.c2
-rw-r--r--src/nvim/edit.h6
-rw-r--r--src/nvim/eval.c110
-rw-r--r--src/nvim/ex_cmds.c126
-rw-r--r--src/nvim/ex_cmds2.c5
-rw-r--r--src/nvim/fold.c17
-rw-r--r--src/nvim/if_cscope.c4
-rw-r--r--src/nvim/mouse.c94
-rw-r--r--src/nvim/mouse.h6
-rw-r--r--src/nvim/normal.c22
-rw-r--r--src/nvim/option.c29
-rw-r--r--src/nvim/option_defs.h9
-rw-r--r--src/nvim/options.lua7
-rw-r--r--src/nvim/search.c56
-rw-r--r--src/nvim/search.h27
-rw-r--r--src/nvim/tag.c18
-rw-r--r--src/nvim/testdir/Makefile7
-rw-r--r--src/nvim/testdir/test_alot.vim3
-rw-r--r--src/nvim/version.c18
-rw-r--r--src/nvim/window.c4
-rw-r--r--test/functional/legacy/057_sort_spec.lua18
-rw-r--r--test/functional/legacy/function_sort_spec.lua29
-rw-r--r--test/functional/legacy/searchpos_spec.lua35
-rw-r--r--test/functional/legacy/tagcase_spec.lua150
-rw-r--r--test/functional/ui/mouse_spec.lua31
-rw-r--r--test/functional/viml/completion_spec.lua603
-rw-r--r--test/unit/helpers.lua1
-rw-r--r--test/unit/os/shell_spec.lua31
42 files changed, 1469 insertions, 290 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0953bcd93a..98ffc77b15 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -59,7 +59,7 @@ set_property(CACHE CMAKE_BUILD_TYPE PROPERTY
# version string, else it is combined with the result of `git describe`.
set(NVIM_VERSION_MAJOR 0)
set(NVIM_VERSION_MINOR 1)
-set(NVIM_VERSION_PATCH 4)
+set(NVIM_VERSION_PATCH 5)
set(NVIM_VERSION_PRERELEASE "-dev") # for package maintainers
file(TO_CMAKE_PATH ${CMAKE_CURRENT_LIST_DIR}/.git FORCED_GIT_DIR)
diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md
index e0185844ad..d9fd758177 100644
--- a/ISSUE_TEMPLATE.md
+++ b/ISSUE_TEMPLATE.md
@@ -1,6 +1,5 @@
- Neovim version:
-- [ ] Vim behaves differently?
- - Vim version:
+- [ ] Vim behaves differently? Vim version:
- Operating system/version:
- Terminal name/version:
- `$TERM`:
@@ -9,7 +8,9 @@
### Expected behaviour
-### Steps to reproduce using `nvim -u NONE`
+### Steps to reproduce using `nvim -u NORC`
-1. `nvim -u NONE`
-2.
+```
+nvim -u NORC
+
+```
diff --git a/runtime/doc/change.txt b/runtime/doc/change.txt
index cfe8a87746..56b45497dc 100644
--- a/runtime/doc/change.txt
+++ b/runtime/doc/change.txt
@@ -1646,7 +1646,7 @@ Vim has a sorting function and a sorting command. The sorting function can be
found here: |sort()|, |uniq()|.
*:sor* *:sort*
-:[range]sor[t][!] [i][u][r][n][x][o][b] [/{pattern}/]
+:[range]sor[t][!] [b][f][i][n][o][r][u][x] [/{pattern}/]
Sort lines in [range]. When no range is given all
lines are sorted.
@@ -1654,10 +1654,18 @@ found here: |sort()|, |uniq()|.
With [i] case is ignored.
+ Options [n][f][x][o][b] are mutually exclusive.
+
With [n] sorting is done on the first decimal number
in the line (after or inside a {pattern} match).
One leading '-' is included in the number.
+ With [f] sorting is done on the Float in the line.
+ The value of Float is determined similar to passing
+ the text (after or inside a {pattern} match) to
+ str2float() function. This option is available only
+ if Vim was compiled with Floating point support.
+
With [x] sorting is done on the first hexadecimal
number in the line (after or inside a {pattern}
match). A leading "0x" or "0X" is ignored.
@@ -1669,10 +1677,10 @@ found here: |sort()|, |uniq()|.
With [b] sorting is done on the first binary number in
the line (after or inside a {pattern} match).
- With [u] only keep the first of a sequence of
- identical lines (ignoring case when [i] is used).
- Without this flag, a sequence of identical lines
- will be kept in their original order.
+ With [u] (u stands for unique) only keep the first of
+ a sequence of identical lines (ignoring case when [i]
+ is used). Without this flag, a sequence of identical
+ lines will be kept in their original order.
Note that leading and trailing white space may cause
lines to be different.
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 148ac7732a..e341a2247a 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -5548,14 +5548,15 @@ search({pattern} [, {flags} [, {stopline} [, {timeout}]]]) *search()*
move. No error message is given.
{flags} is a String, which can contain these character flags:
- 'b' search backward instead of forward
- 'c' accept a match at the cursor position
+ 'b' search Backward instead of forward
+ 'c' accept a match at the Cursor position
'e' move to the End of the match
'n' do Not move the cursor
- 'p' return number of matching sub-pattern (see below)
- 's' set the ' mark at the previous location of the cursor
- 'w' wrap around the end of the file
- 'W' don't wrap around the end of the file
+ 'p' return number of matching sub-Pattern (see below)
+ 's' Set the ' mark at the previous location of the cursor
+ 'w' Wrap around the end of the file
+ 'W' don't Wrap around the end of the file
+ 'z' start searching at the cursor column instead of Zero
If neither 'w' or 'W' is given, the 'wrapscan' option applies.
If the 's' flag is supplied, the ' mark is set, only if the
@@ -5563,6 +5564,12 @@ search({pattern} [, {flags} [, {stopline} [, {timeout}]]]) *search()*
flag.
'ignorecase', 'smartcase' and 'magic' are used.
+
+ When the 'z' flag is not given seaching always starts in
+ column zero and then matches before the cursor are skipped.
+ When the 'c' flag is present in 'cpo' the next search starts
+ after the match. Without the 'c' flag the next search starts
+ one column further.
When the {stopline} argument is given then the search stops
after searching this line. This is useful to restrict the
@@ -6144,6 +6151,10 @@ sort({list} [, {func} [, {dict}]]) *sort()* *E702*
strtod() function to parse numbers, Strings, Lists, Dicts and
Funcrefs will be considered as being 0).
+ When {func} is given and it is 'N' then all items will be
+ sorted numerical. This is like 'n' but a string containing
+ digits will be used as the number they represent.
+
When {func} is a |Funcref| or a function name, this function
is called to compare items. The function is invoked with two
items as argument and must return zero if they are equal, 1 or
@@ -6158,6 +6169,11 @@ sort({list} [, {func} [, {dict}]]) *sort()* *E702*
on numbers, text strings will sort next to each other, in the
same order as they were originally.
+ The sort is stable, items which compare equal (as number or as
+ string) will keep their relative position. E.g., when sorting
+ on numbers, text strings will sort next to each other, in the
+ same order as they were originally.
+
Also see |uniq()|.
Example: >
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index 6ed83ca855..ebb2f28fa5 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -3410,7 +3410,7 @@ A jump table for the options with a short description can be found at |Q_op|.
global
Ignore case in search patterns. Also used when searching in the tags
file.
- Also see 'smartcase'.
+ Also see 'smartcase' and 'tagcase'.
Can be overruled by using "\c" or "\C" in the pattern, see
|/ignorecase|.
@@ -6321,19 +6321,22 @@ A jump table for the options with a short description can be found at |Q_op|.
< [The whitespace before and after the '0' must be a single <Tab>]
When a binary search was done and no match was found in any of the
- files listed in 'tags', and 'ignorecase' is set or a pattern is used
+ files listed in 'tags', and case is ignored or a pattern is used
instead of a normal tag name, a retry is done with a linear search.
Tags in unsorted tags files, and matches with different case will only
be found in the retry.
If a tag file indicates that it is case-fold sorted, the second,
- linear search can be avoided for the 'ignorecase' case. Use a value
- of '2' in the "!_TAG_FILE_SORTED" line for this. A tag file can be
- case-fold sorted with the -f switch to "sort" in most unices, as in
- the command: "sort -f -o tags tags". For "Exuberant ctags" version
- 5.x or higher (at least 5.5) the --sort=foldcase switch can be used
- for this as well. Note that case must be folded to uppercase for this
- to work.
+ linear search can be avoided when case is ignored. Use a value of '2'
+ in the "!_TAG_FILE_SORTED" line for this. A tag file can be case-fold
+ sorted with the -f switch to "sort" in most unices, as in the command:
+ "sort -f -o tags tags". For "Exuberant ctags" version 5.x or higher
+ (at least 5.5) the --sort=foldcase switch can be used for this as
+ well. Note that case must be folded to uppercase for this to work.
+
+ By default, tag searches are case-sensitive. Case is ignored when
+ 'ignorecase' is set and 'tagcase' is "followic", or when 'tagcase' is
+ "ignore".
When 'tagbsearch' is off, tags searching is slower when a full match
exists, but faster when no full match exists. Tags in unsorted tags
@@ -6344,6 +6347,16 @@ A jump table for the options with a short description can be found at |Q_op|.
This option doesn't affect commands that find all matching tags (e.g.,
command-line completion and ":help").
+ *'tagcase'* *'tc'*
+'tagcase' 'tc' string (default "followic")
+ global or local to buffer |global-local|
+ {not in Vi}
+ This option specifies how case is handled when searching the tags
+ file:
+ followic Follow the 'ignorecase' option
+ ignore Ignore case
+ match Match case
+
*'taglength'* *'tl'*
'taglength' 'tl' number (default 0)
global
diff --git a/runtime/doc/quickref.txt b/runtime/doc/quickref.txt
index 120e027242..66773875c3 100644
--- a/runtime/doc/quickref.txt
+++ b/runtime/doc/quickref.txt
@@ -879,6 +879,7 @@ Short explanation of each option: *option-list*
'tabpagemax' 'tpm' maximum number of tab pages for |-p| and "tab all"
'tabstop' 'ts' number of spaces that <Tab> in file uses
'tagbsearch' 'tbs' use binary searching in tags files
+'tagcase' 'tc' how to handle case when searching in tags files
'taglength' 'tl' number of significant characters for a tag
'tagrelative' 'tr' file names in tag file are relative
'tags' 'tag' list of file names used by the tag command
diff --git a/runtime/doc/tagsrch.txt b/runtime/doc/tagsrch.txt
index 7d3697db07..75d820d072 100644
--- a/runtime/doc/tagsrch.txt
+++ b/runtime/doc/tagsrch.txt
@@ -84,11 +84,13 @@ changed, to avoid confusion when using ":tnext". It is changed when using
":tag {ident}".
The ignore-case matches are not found for a ":tag" command when the
-'ignorecase' option is off. They are found when a pattern is used (starting
-with a "/") and for ":tselect", also when 'ignorecase' is off. Note that
-using ignore-case tag searching disables binary searching in the tags file,
-which causes a slowdown. This can be avoided by fold-case sorting the tag
-file. See the 'tagbsearch' option for an explanation.
+'ignorecase' option is off and 'tagcase' is "followic" or when 'tagcase' is
+"match". They are found when a pattern is used (starting with a "/") and for
+":tselect", also when 'ignorecase' is off and 'tagcase' is "followic" or when
+'tagcase' is "match". Note that using ignore-case tag searching disables
+binary searching in the tags file, which causes a slowdown. This can be
+avoided by fold-case sorting the tag file. See the 'tagbsearch' option for an
+explanation.
==============================================================================
2. Tag stack *tag-stack* *tagstack* *E425*
@@ -418,12 +420,13 @@ file "tags". It can also be used to access a common tags file.
The next file in the list is not used when:
- A matching static tag for the current buffer has been found.
- A matching global tag has been found.
-This also depends on the 'ignorecase' option. If it is off, and the tags file
-only has a match without matching case, the next tags file is searched for a
-match with matching case. If no tag with matching case is found, the first
-match without matching case is used. If 'ignorecase' is on, and a matching
-global tag with or without matching case is found, this one is used, no
-further tags files are searched.
+This also depends on whether case is ignored. Case is ignored when
+'ignorecase' is set and 'tagcase' is "followic", or when 'tagcase' is
+"ignore". If case is not ignored, and the tags file only has a match without
+matching case, the next tags file is searched for a match with matching case.
+If no tag with matching case is found, the first match without matching case
+is used. If case is ignored, and a matching global tag with or without
+matching case is found, this one is used, no further tags files are searched.
When a tag file name starts with "./", the '.' is replaced with the path of
the current file. This makes it possible to use a tags file in the directory
@@ -556,8 +559,10 @@ that indicates if the file was sorted. When this line is found, Vim uses
binary searching for the tags file:
!_TAG_FILE_SORTED<Tab>1<Tab>{anything} ~
-A tag file may be case-fold sorted to avoid a linear search when 'ignorecase'
-is on. See 'tagbsearch' for details. The value '2' should be used then:
+A tag file may be case-fold sorted to avoid a linear search when case is
+ignored. (Case is ignored when 'ignorecase' is set and 'tagcase' is
+"followic", or when 'tagcase' is "ignore".) See 'tagbsearch' for details.
+The value '2' should be used then:
!_TAG_FILE_SORTED<Tab>2<Tab>{anything} ~
The other tag that Vim recognizes, but only when compiled with the
diff --git a/runtime/doc/usr_29.txt b/runtime/doc/usr_29.txt
index 22de2f6ce6..e495aad06d 100644
--- a/runtime/doc/usr_29.txt
+++ b/runtime/doc/usr_29.txt
@@ -255,7 +255,8 @@ function.
RELATED ITEMS
-You can set 'ignorecase' to make case in tag names be ignored.
+To make case in tag names be ignored, you can set 'ignorecase' while leaving
+'tagcase' as "followic", or set 'tagcase' to "ignore".
The 'tagbsearch' option tells if the tags file is sorted or not. The default
is to assume a sorted tags file, which makes a tags search a lot faster, but
diff --git a/runtime/optwin.vim b/runtime/optwin.vim
index 536c87ad7f..7050436aab 100644
--- a/runtime/optwin.vim
+++ b/runtime/optwin.vim
@@ -289,6 +289,10 @@ call append("$", " \tset tl=" . &tl)
call append("$", "tags\tlist of file names to search for tags")
call append("$", "\t(global or local to buffer)")
call <SID>OptionG("tag", &tag)
+call append("$", "tagcase\thow to handle case when searching in tags files:")
+call append("$", "\t\"followic\" to follow 'ignorecase', \"ignore\" or \"match\"")
+call append("$", "\t(global or local to buffer)")
+call <SID>OptionG("tc", &tc)
call append("$", "tagrelative\tfile names in a tags file are relative to the tags file")
call <SID>BinOptionG("tr", &tr)
call append("$", "tagstack\ta :tag command will use the tagstack")
diff --git a/scripts/git-log-pretty-since.sh b/scripts/git-log-pretty-since.sh
new file mode 100755
index 0000000000..d8e3282fb3
--- /dev/null
+++ b/scripts/git-log-pretty-since.sh
@@ -0,0 +1,32 @@
+#!/usr/bin/env bash
+
+# Shows a log with changes grouped next to their merge-commit.
+#
+# Parameters:
+# $1 "since" commit
+# $2 "inverse match" regex pattern
+
+set -e
+set -u
+set -o pipefail
+
+__SINCE=$1
+__INVMATCH=$2
+
+is_merge_commit() {
+ git rev-parse $1 >/dev/null 2>&1 \
+ || { echo "ERROR: invalid commit: $1"; exit 1; }
+ git log $1^2 >/dev/null 2>&1 && return 0 || return 1
+}
+
+for commit in $(git log --format='%H' --first-parent --since $__SINCE); do
+ if is_merge_commit ${commit} ; then
+ if [ -z "$__INVMATCH" ] || ! git log --oneline ${commit}^1..${commit}^2 \
+ | grep -E "$__INVMATCH" >/dev/null 2>&1 ; then
+ git log -1 --oneline ${commit}
+ git log --format=' %h %s' ${commit}^1..${commit}^2
+ fi
+ else
+ git log -1 --oneline ${commit}
+ fi
+done
diff --git a/scripts/release.sh b/scripts/release.sh
new file mode 100755
index 0000000000..514e5b380a
--- /dev/null
+++ b/scripts/release.sh
@@ -0,0 +1,63 @@
+#!/usr/bin/env bash
+
+# Performs steps to tag a release.
+#
+# Steps:
+# Create the "release" commit:
+# - CMakeLists.txt: Unset NVIM_VERSION_PRERELEASE
+# - Tag the commit.
+# Create the "version bump" commit:
+# - CMakeLists.txt: Set NVIM_VERSION_PRERELEASE to "-dev"
+#
+# Manual steps:
+# - CMakeLists.txt: Bump NVIM_VERSION_* as appropriate.
+# - git push --follow-tags
+
+set -e
+set -u
+set -o pipefail
+
+cd "$(git rev-parse --show-toplevel)"
+
+__LAST_TAG=$(git describe --abbrev=0)
+[ -z "$__LAST_TAG" ] && { echo 'ERROR: no tag found'; exit 1; }
+__VERSION_MAJOR=$(grep 'set(NVIM_VERSION_MAJOR' CMakeLists.txt\
+ |sed -r 's/.*NVIM_VERSION_MAJOR ([[:digit:]]).*/\1/')
+__VERSION_MINOR=$(grep 'set(NVIM_VERSION_MINOR' CMakeLists.txt\
+ |sed -r 's/.*NVIM_VERSION_MINOR ([[:digit:]]).*/\1/')
+__VERSION_PATCH=$(grep 'set(NVIM_VERSION_PATCH' CMakeLists.txt\
+ |sed -r 's/.*NVIM_VERSION_PATCH ([[:digit:]]).*/\1/')
+__VERSION="${__VERSION_MAJOR}.${__VERSION_MINOR}.${__VERSION_PATCH}"
+{ [ -z "$__VERSION_MAJOR" ] || [ -z "$__VERSION_MINOR" ] || [ -z "$__VERSION_PATCH" ]; } \
+ && { echo "ERROR: version parse failed: '${__VERSION}'"; exit 1; }
+__RELEASE_MSG="NVIM v${__VERSION}
+
+Features:
+
+Fixes:
+
+Changes:
+
+"
+__BUMP_MSG="version bump"
+
+echo "Most recent tag: ${__LAST_TAG}"
+echo "Release version: ${__VERSION}"
+sed -i -r 's/(NVIM_VERSION_PRERELEASE) "-dev"/\1 ""/' CMakeLists.txt
+echo "Building changelog since ${__LAST_TAG}..."
+__CHANGELOG="$(./scripts/git-log-pretty-since.sh $__LAST_TAG 'vim-patch:\S')"
+
+git add CMakeLists.txt
+git commit --edit -m "${__RELEASE_MSG} ${__CHANGELOG}"
+git tag -a v${__VERSION} -m "NVIM v${__VERSION}"
+
+sed -i -r 's/(NVIM_VERSION_PRERELEASE) ""/\1 "-dev"/' CMakeLists.txt
+nvim -c '/NVIM_VERSION' -c 'echo "Update version numbers"' CMakeLists.txt
+git add CMakeLists.txt
+git commit -m "$__BUMP_MSG"
+
+echo "
+Next steps:
+ - Double-check NVIM_VERSION_* in CMakeLists.txt
+ - git push --follow-tags
+ - update website: index.html"
diff --git a/scripts/vim-patch.sh b/scripts/vim-patch.sh
index 4dc24a8cdf..70777535cb 100755
--- a/scripts/vim-patch.sh
+++ b/scripts/vim-patch.sh
@@ -86,6 +86,11 @@ commit_message() {
"${vim_message}" "${vim_commit_url}"
}
+find_git_remote() {
+ git remote -v \
+ | awk '$2 ~ /github.com[:/]neovim\/neovim/ && $3 == "(fetch)" {print $1}'
+}
+
assign_commit_details() {
if [[ ${1} =~ [0-9]\.[0-9]\.[0-9]{3,4} ]]; then
# Interpret parameter as version number (tag).
@@ -132,21 +137,23 @@ get_vim_patch() {
local neovim_branch="${BRANCH_PREFIX}${vim_version}"
cd "${NEOVIM_SOURCE_DIR}"
+ local git_remote=$(find_git_remote)
local checked_out_branch="$(git rev-parse --abbrev-ref HEAD)"
+
if [[ "${checked_out_branch}" == ${BRANCH_PREFIX}* ]]; then
echo "✔ Current branch '${checked_out_branch}' seems to be a vim-patch"
echo " branch; not creating a new branch."
else
echo
- echo "Fetching 'upstream/master'."
- output="$(git fetch upstream master 2>&1)" &&
+ echo "Fetching '${git_remote}/master'."
+ output="$(git fetch "${git_remote}" master 2>&1)" &&
echo "✔ ${output}" ||
(echo "✘ ${output}"; false)
echo
- echo "Creating new branch '${neovim_branch}' based on 'upstream/master'."
+ echo "Creating new branch '${neovim_branch}' based on '${git_remote}/master'."
cd "${NEOVIM_SOURCE_DIR}"
- output="$(git checkout -b "${neovim_branch}" upstream/master 2>&1)" &&
+ output="$(git checkout -b "${neovim_branch}" "${git_remote}/master" 2>&1)" &&
echo "✔ ${output}" ||
(echo "✘ ${output}"; false)
fi
@@ -195,8 +202,9 @@ submit_pr() {
exit 1
fi
- local pr_body="$(git log --reverse --format='#### %s%n%n%b%n' upstream/master..HEAD)"
- local patches=("$(git log --reverse --format='%s' upstream/master..HEAD)")
+ local git_remote=$(find_git_remote)
+ local pr_body="$(git log --reverse --format='#### %s%n%n%b%n' ${git_remote}/master..HEAD)"
+ local patches=("$(git log --reverse --format='%s' ${git_remote}/master..HEAD)")
patches=(${patches[@]//vim-patch:}) # Remove 'vim-patch:' prefix for each item in array.
local pr_title="${patches[@]}" # Create space-separated string from array.
pr_title="${pr_title// /,}" # Replace spaces with commas.
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index c514c4378e..529d0889bd 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -1553,6 +1553,7 @@ void free_buf_options(buf_T *buf, int free_p_ff)
clear_string_option(&buf->b_p_ep);
clear_string_option(&buf->b_p_path);
clear_string_option(&buf->b_p_tags);
+ clear_string_option(&buf->b_p_tc);
clear_string_option(&buf->b_p_dict);
clear_string_option(&buf->b_p_tsr);
clear_string_option(&buf->b_p_qe);
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index ecd13d5ee0..c0cd801cd4 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -666,19 +666,21 @@ struct file_buffer {
long b_p_wm_nopaste; ///< b_p_wm saved for paste mode
char_u *b_p_keymap; ///< 'keymap'
- /* local values for options which are normally global */
- char_u *b_p_gp; /* 'grepprg' local value */
- char_u *b_p_mp; /* 'makeprg' local value */
- char_u *b_p_efm; /* 'errorformat' local value */
- char_u *b_p_ep; /* 'equalprg' local value */
- char_u *b_p_path; /* 'path' local value */
- int b_p_ar; /* 'autoread' local value */
- char_u *b_p_tags; /* 'tags' local value */
- char_u *b_p_dict; /* 'dictionary' local value */
- char_u *b_p_tsr; /* 'thesaurus' local value */
- long b_p_ul; /* 'undolevels' local value */
- int b_p_udf; /* 'undofile' */
- char_u *b_p_lw; // 'lispwords' local value
+ // local values for options which are normally global
+ char_u *b_p_gp; ///< 'grepprg' local value
+ char_u *b_p_mp; ///< 'makeprg' local value
+ char_u *b_p_efm; ///< 'errorformat' local value
+ char_u *b_p_ep; ///< 'equalprg' local value
+ char_u *b_p_path; ///< 'path' local value
+ int b_p_ar; ///< 'autoread' local value
+ char_u *b_p_tags; ///< 'tags' local value
+ char_u *b_p_tc; ///< 'tagcase' local value
+ unsigned b_tc_flags; ///< flags for 'tagcase'
+ char_u *b_p_dict; ///< 'dictionary' local value
+ char_u *b_p_tsr; ///< 'thesaurus' local value
+ long b_p_ul; ///< 'undolevels' local value
+ int b_p_udf; ///< 'undofile'
+ char_u *b_p_lw; ///< 'lispwords' local value
/* end of buffer options */
@@ -955,16 +957,14 @@ struct window_S {
time through cursupdate() to the
current virtual column */
- /*
- * the next six are used to update the visual part
- */
- char w_old_visual_mode; /* last known VIsual_mode */
- linenr_T w_old_cursor_lnum; /* last known end of visual part */
- colnr_T w_old_cursor_fcol; /* first column for block visual part */
- colnr_T w_old_cursor_lcol; /* last column for block visual part */
- linenr_T w_old_visual_lnum; /* last known start of visual part */
- colnr_T w_old_visual_col; /* last known start of visual part */
- colnr_T w_old_curswant; /* last known value of Curswant */
+ // the next seven are used to update the visual part
+ char w_old_visual_mode; ///< last known VIsual_mode
+ linenr_T w_old_cursor_lnum; ///< last known end of visual part
+ colnr_T w_old_cursor_fcol; ///< first column for block visual part
+ colnr_T w_old_cursor_lcol; ///< last column for block visual part
+ linenr_T w_old_visual_lnum; ///< last known start of visual part
+ colnr_T w_old_visual_col; ///< last known start of visual part
+ colnr_T w_old_curswant; ///< last known value of Curswant
/*
* "w_topline", "w_leftcol" and "w_skipcol" specify the offsets for
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 3a4b475bc8..667ce1e779 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -7741,6 +7741,8 @@ static void ins_mousescroll(int dir)
(long)(curwin->w_botline - curwin->w_topline));
else
scroll_redraw(dir, 3L);
+ } else {
+ mouse_scroll_horiz(dir);
}
did_scroll = TRUE;
}
diff --git a/src/nvim/edit.h b/src/nvim/edit.h
index 0289b2c3a6..0d61f26bcc 100644
--- a/src/nvim/edit.h
+++ b/src/nvim/edit.h
@@ -36,12 +36,6 @@ typedef int (*IndentGetter)(void);
#define INSCHAR_NO_FEX 8 /* don't use 'formatexpr' */
#define INSCHAR_COM_LIST 16 /* format comments with list/2nd line indent */
-/* direction for nv_mousescroll() and ins_mousescroll() */
-#define MSCR_DOWN 0 /* DOWN must be FALSE */
-#define MSCR_UP 1
-#define MSCR_LEFT -1
-#define MSCR_RIGHT -2
-
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "edit.h.generated.h"
#endif
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 31b264395b..9553c7a7ed 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -8304,12 +8304,12 @@ static void f_cscope_connection(typval_T *argvars, typval_T *rettv)
rettv->vval.v_number = cs_connection(num, dbpath, prepend);
}
-/*
- * "cursor(lnum, col)" function
- *
- * Moves the cursor to the specified line and column.
- * Returns 0 when the position could be set, -1 otherwise.
- */
+/// "cursor(lnum, col)" function, or
+/// "cursor(list)"
+///
+/// Moves the cursor to the specified line and column.
+///
+/// @returns 0 when the position could be set, -1 otherwise.
static void f_cursor(typval_T *argvars, typval_T *rettv)
{
long line, col;
@@ -8321,8 +8321,10 @@ static void f_cursor(typval_T *argvars, typval_T *rettv)
colnr_T curswant = -1;
if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL) {
+ EMSG(_(e_invarg));
return;
}
+
line = pos.lnum;
col = pos.col;
coladd = pos.coladd;
@@ -13536,14 +13538,14 @@ static void f_reverse(typval_T *argvars, typval_T *rettv)
}
}
-#define SP_NOMOVE 0x01 /* don't move cursor */
-#define SP_REPEAT 0x02 /* repeat to find outer pair */
-#define SP_RETCOUNT 0x04 /* return matchcount */
-#define SP_SETPCMARK 0x08 /* set previous context mark */
-#define SP_START 0x10 /* accept match at start position */
-#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
-#define SP_END 0x40 /* leave cursor at end of match */
-
+#define SP_NOMOVE 0x01 ///< don't move cursor
+#define SP_REPEAT 0x02 ///< repeat to find outer pair
+#define SP_RETCOUNT 0x04 ///< return matchcount
+#define SP_SETPCMARK 0x08 ///< set previous context mark
+#define SP_START 0x10 ///< accept match at start position
+#define SP_SUBPAT 0x20 ///< return nr of matching sub-pattern
+#define SP_END 0x40 ///< leave cursor at end of match
+#define SP_COLUMN 0x80 ///< start at cursor column
/*
* Get flags for a search function.
@@ -13569,13 +13571,14 @@ static int get_search_arg(typval_T *varp, int *flagsp)
default: mask = 0;
if (flagsp != NULL)
switch (*flags) {
- case 'c': mask = SP_START; break;
- case 'e': mask = SP_END; break;
- case 'm': mask = SP_RETCOUNT; break;
- case 'n': mask = SP_NOMOVE; break;
- case 'p': mask = SP_SUBPAT; break;
- case 'r': mask = SP_REPEAT; break;
- case 's': mask = SP_SETPCMARK; break;
+ case 'c': mask = SP_START; break;
+ case 'e': mask = SP_END; break;
+ case 'm': mask = SP_RETCOUNT; break;
+ case 'n': mask = SP_NOMOVE; break;
+ case 'p': mask = SP_SUBPAT; break;
+ case 'r': mask = SP_REPEAT; break;
+ case 's': mask = SP_SETPCMARK; break;
+ case 'z': mask = SP_COLUMN; break;
}
if (mask == 0) {
EMSG2(_(e_invarg2), flags);
@@ -13591,9 +13594,7 @@ static int get_search_arg(typval_T *varp, int *flagsp)
return dir;
}
-/*
- * Shared by search() and searchpos() functions
- */
+// Shared by search() and searchpos() functions.
static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
{
int flags;
@@ -13614,10 +13615,15 @@ static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
if (dir == 0)
goto theend;
flags = *flagsp;
- if (flags & SP_START)
+ if (flags & SP_START) {
options |= SEARCH_START;
- if (flags & SP_END)
+ }
+ if (flags & SP_END) {
options |= SEARCH_END;
+ }
+ if (flags & SP_COLUMN) {
+ options |= SEARCH_COL;
+ }
/* Optional arguments: line number to stop searching and timeout. */
if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN) {
@@ -14947,6 +14953,8 @@ typedef struct {
static int item_compare_ic;
static bool item_compare_numeric;
+static bool item_compare_numbers;
+static bool item_compare_float;
static char_u *item_compare_func;
static dict_T *item_compare_selfdict;
static int item_compare_func_err;
@@ -14968,6 +14976,21 @@ static int item_compare(const void *s1, const void *s2, bool keep_zero)
si2 = (sortItem_T *)s2;
typval_T *tv1 = &si1->item->li_tv;
typval_T *tv2 = &si2->item->li_tv;
+
+ if (item_compare_numbers) {
+ long v1 = get_tv_number(tv1);
+ long v2 = get_tv_number(tv2);
+
+ return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
+ }
+
+ if (item_compare_float) {
+ float_T v1 = get_tv_float(tv1);
+ float_T v2 = get_tv_float(tv2);
+
+ return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
+ }
+
// encode_tv2string() puts quotes around a string and allocates memory. Don't
// do that for string variables. Use a single quote when comparing with
// a non-string to do what the docs promise.
@@ -15114,6 +15137,8 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
item_compare_ic = FALSE;
item_compare_numeric = false;
+ item_compare_numbers = false;
+ item_compare_float = false;
item_compare_func = NULL;
item_compare_selfdict = NULL;
@@ -15135,6 +15160,12 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
if (STRCMP(item_compare_func, "n") == 0) {
item_compare_func = NULL;
item_compare_numeric = true;
+ } else if (STRCMP(item_compare_func, "N") == 0) {
+ item_compare_func = NULL;
+ item_compare_numbers = true;
+ } else if (STRCMP(item_compare_func, "f") == 0) {
+ item_compare_func = NULL;
+ item_compare_float = true;
} else if (STRCMP(item_compare_func, "i") == 0) {
item_compare_func = NULL;
item_compare_ic = TRUE;
@@ -17836,6 +17867,33 @@ long get_tv_number_chk(typval_T *varp, int *denote)
return n;
}
+static float_T get_tv_float(typval_T *varp)
+{
+ switch (varp->v_type) {
+ case VAR_NUMBER:
+ return (float_T)(varp->vval.v_number);
+ case VAR_FLOAT:
+ return varp->vval.v_float;
+ break;
+ case VAR_FUNC:
+ EMSG(_("E891: Using a Funcref as a Float"));
+ break;
+ case VAR_STRING:
+ EMSG(_("E892: Using a String as a Float"));
+ break;
+ case VAR_LIST:
+ EMSG(_("E893: Using a List as a Float"));
+ break;
+ case VAR_DICT:
+ EMSG(_("E894: Using a Dictionary as a Float"));
+ break;
+ default:
+ EMSG2(_(e_intern2), "get_tv_float()");
+ break;
+ }
+ return 0;
+}
+
/*
* Get the lnum from the first argument.
* Also accepts ".", "$", etc., but that only works for the current buffer.
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 69bf7abe6e..d020bc8f20 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -3,6 +3,7 @@
*/
#include <assert.h>
+#include <float.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
@@ -273,17 +274,26 @@ static int linelen(int *has_tab)
static char_u *sortbuf1;
static char_u *sortbuf2;
-static int sort_ic; /* ignore case */
-static int sort_nr; /* sort on number */
-static int sort_rx; /* sort on regex instead of skipping it */
+static int sort_ic; ///< ignore case
+static int sort_nr; ///< sort on number
+static int sort_rx; ///< sort on regex instead of skipping it
+static int sort_flt; ///< sort on floating number
-static int sort_abort; /* flag to indicate if sorting has been interrupted */
+static int sort_abort; ///< flag to indicate if sorting has been interrupted
-/* Struct to store info to be sorted. */
+/// Struct to store info to be sorted.
typedef struct {
- linenr_T lnum; /* line number */
- long start_col_nr; /* starting column number or number */
- long end_col_nr; /* ending column number */
+ linenr_T lnum; ///< line number
+ long start_col_nr; ///< starting column number or number
+ long end_col_nr; ///< ending column number
+ union {
+ struct {
+ long start_col_nr; ///< starting column number
+ long end_col_nr; ///< ending column number
+ } line;
+ long value; ///< value if sorting by integer
+ float_T value_flt; ///< value if sorting by float
+ } st_u;
} sorti_T;
@@ -302,21 +312,26 @@ static int sort_compare(const void *s1, const void *s2)
if (got_int)
sort_abort = TRUE;
- /* When sorting numbers "start_col_nr" is the number, not the column
- * number. */
- if (sort_nr)
- result = l1.start_col_nr == l2.start_col_nr ? 0
- : l1.start_col_nr > l2.start_col_nr ? 1 : -1;
- else {
- /* We need to copy one line into "sortbuf1", because there is no
- * guarantee that the first pointer becomes invalid when obtaining the
- * second one. */
- STRNCPY(sortbuf1, ml_get(l1.lnum) + l1.start_col_nr,
- l1.end_col_nr - l1.start_col_nr + 1);
- sortbuf1[l1.end_col_nr - l1.start_col_nr] = 0;
- STRNCPY(sortbuf2, ml_get(l2.lnum) + l2.start_col_nr,
- l2.end_col_nr - l2.start_col_nr + 1);
- sortbuf2[l2.end_col_nr - l2.start_col_nr] = 0;
+ // When sorting numbers "start_col_nr" is the number, not the column
+ // number.
+ if (sort_nr) {
+ result = l1.st_u.value == l2.st_u.value
+ ? 0 : l1.st_u.value > l2.st_u.value
+ ? 1 : -1;
+ } else if (sort_flt) {
+ result = l1.st_u.value_flt == l2.st_u.value_flt
+ ? 0 : l1.st_u.value_flt > l2.st_u.value_flt
+ ? 1 : -1;
+ } else {
+ // We need to copy one line into "sortbuf1", because there is no
+ // guarantee that the first pointer becomes invalid when obtaining the
+ // second one.
+ STRNCPY(sortbuf1, ml_get(l1.lnum) + l1.st_u.line.start_col_nr,
+ l1.st_u.line.end_col_nr - l1.st_u.line.start_col_nr + 1);
+ sortbuf1[l1.st_u.line.end_col_nr - l1.st_u.line.start_col_nr] = 0;
+ STRNCPY(sortbuf2, ml_get(l2.lnum) + l2.st_u.line.start_col_nr,
+ l2.st_u.line.end_col_nr - l2.st_u.line.start_col_nr + 1);
+ sortbuf2[l2.st_u.line.end_col_nr - l2.st_u.line.start_col_nr] = 0;
result = sort_ic ? STRICMP(sortbuf1, sortbuf2)
: STRCMP(sortbuf1, sortbuf2);
@@ -360,7 +375,7 @@ void ex_sort(exarg_T *eap)
regmatch.regprog = NULL;
sorti_T *nrs = xmalloc(count * sizeof(sorti_T));
- sort_abort = sort_ic = sort_rx = sort_nr = 0;
+ sort_abort = sort_ic = sort_rx = sort_nr = sort_flt = 0;
size_t format_found = 0;
for (p = eap->arg; *p != NUL; ++p) {
@@ -370,7 +385,10 @@ void ex_sort(exarg_T *eap)
} else if (*p == 'r') {
sort_rx = true;
} else if (*p == 'n') {
- sort_nr = 2;
+ sort_nr = 1;
+ format_found++;
+ } else if (*p == 'f') {
+ sort_flt = 1;
format_found++;
} else if (*p == 'b') {
sort_what = STR2NR_BIN + STR2NR_FORCE;
@@ -423,7 +441,8 @@ void ex_sort(exarg_T *eap)
goto sortend;
}
- // From here on "sort_nr" is used as a flag for any number sorting.
+ // From here on "sort_nr" is used as a flag for any integer number
+ // sorting.
sort_nr += sort_what;
// Make an array with all line numbers. This avoids having to copy all
@@ -452,7 +471,7 @@ void ex_sort(exarg_T *eap)
end_col = 0;
}
- if (sort_nr) {
+ if (sort_nr || sort_flt) {
// Make sure vim_str2nr doesn't read any digits past the end
// of the match, by temporarily terminating the string there
s2 = s + end_col;
@@ -460,29 +479,42 @@ void ex_sort(exarg_T *eap)
*s2 = NUL;
// Sorting on number: Store the number itself.
p = s + start_col;
- if (sort_what & STR2NR_HEX) {
- s = skiptohex(p);
- } else if (sort_what & STR2NR_BIN) {
- s = (char_u*) skiptobin((char*) p);
- } else {
- s = skiptodigit(p);
- }
- if (s > p && s[-1] == '-') {
- // include preceding negative sign
- s--;
- }
- if (*s == NUL) {
- // empty line should sort before any number
- nrs[lnum - eap->line1].start_col_nr = -MAXLNUM;
+ if (sort_nr) {
+ if (sort_what & STR2NR_HEX) {
+ s = skiptohex(p);
+ } else if (sort_what & STR2NR_BIN) {
+ s = (char_u *)skiptobin((char *)p);
+ } else {
+ s = skiptodigit(p);
+ }
+ if (s > p && s[-1] == '-') {
+ s--; // include preceding negative sign
+ }
+ if (*s == NUL) {
+ // empty line should sort before any number
+ nrs[lnum - eap->line1].st_u.value = -MAXLNUM;
+ } else {
+ vim_str2nr(s, NULL, NULL, sort_what,
+ &nrs[lnum - eap->line1].st_u.value, NULL, 0);
+ }
} else {
- vim_str2nr(s, NULL, NULL, sort_what,
- &nrs[lnum - eap->line1].start_col_nr, NULL, 0);
+ s = skipwhite(p);
+ if (*s == '+') {
+ s = skipwhite(s + 1);
+ }
+
+ if (*s == NUL) {
+ // empty line should sort before any number
+ nrs[lnum - eap->line1].st_u.value_flt = -DBL_MAX;
+ } else {
+ nrs[lnum - eap->line1].st_u.value_flt = strtod((char *)s, NULL);
+ }
}
*s2 = c;
} else {
// Store the column to sort at.
- nrs[lnum - eap->line1].start_col_nr = start_col;
- nrs[lnum - eap->line1].end_col_nr = end_col;
+ nrs[lnum - eap->line1].st_u.line.start_col_nr = start_col;
+ nrs[lnum - eap->line1].st_u.line.end_col_nr = end_col;
}
nrs[lnum - eap->line1].lnum = lnum;
@@ -5016,7 +5048,9 @@ helptags_one (
/*
* Sort the tags.
*/
- sort_strings((char_u **)ga.ga_data, ga.ga_len);
+ if (ga.ga_data != NULL) {
+ sort_strings((char_u **)ga.ga_data, ga.ga_len);
+ }
/*
* Check for duplicates.
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index 2c8271c696..a0a0b9d3a5 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -2373,8 +2373,9 @@ static FILE *fopen_noinh_readbin(char *filename)
# ifdef HAVE_FD_CLOEXEC
{
int fdflags = fcntl(fd_tmp, F_GETFD);
- if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
- fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
+ if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0) {
+ (void)fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
+ }
}
# endif
diff --git a/src/nvim/fold.c b/src/nvim/fold.c
index 7f46a37315..ac3cf959c8 100644
--- a/src/nvim/fold.c
+++ b/src/nvim/fold.c
@@ -2110,10 +2110,11 @@ static linenr_T foldUpdateIEMSRecurse(garray_T *gap, int level,
*/
if (getlevel == foldlevelMarker && flp->start <= flp->lvl - level
&& flp->lvl > 0) {
- foldFind(gap, startlnum - 1, &fp);
+ (void)foldFind(gap, startlnum - 1, &fp);
if (fp >= ((fold_T *)gap->ga_data) + gap->ga_len
- || fp->fd_top >= startlnum)
+ || fp->fd_top >= startlnum) {
fp = NULL;
+ }
}
/*
@@ -2167,13 +2168,15 @@ static linenr_T foldUpdateIEMSRecurse(garray_T *gap, int level,
}
}
if (lvl < level + i) {
- foldFind(&fp->fd_nested, flp->lnum - fp->fd_top, &fp2);
- if (fp2 != NULL)
+ (void)foldFind(&fp->fd_nested, flp->lnum - fp->fd_top, &fp2);
+ if (fp2 != NULL) {
bot = fp2->fd_top + fp2->fd_len - 1 + fp->fd_top;
- } else if (fp->fd_top + fp->fd_len <= flp->lnum && lvl >= level)
- finish = TRUE;
- else
+ }
+ } else if (fp->fd_top + fp->fd_len <= flp->lnum && lvl >= level) {
+ finish = true;
+ } else {
break;
+ }
}
/* At the start of the first nested fold and at the end of the current
diff --git a/src/nvim/if_cscope.c b/src/nvim/if_cscope.c
index daddd7cee4..2f9ec0b3ff 100644
--- a/src/nvim/if_cscope.c
+++ b/src/nvim/if_cscope.c
@@ -1062,8 +1062,8 @@ static int cs_find_common(char *opt, char *pat, int forceit, int verbose,
if (qf_init(wp, tmp, (char_u *)"%f%*\\t%l%*\\t%m",
*qfpos == '-', cmdline) > 0) {
if (postponed_split != 0) {
- win_split(postponed_split > 0 ? postponed_split : 0,
- postponed_split_flags);
+ (void)win_split(postponed_split > 0 ? postponed_split : 0,
+ postponed_split_flags);
RESET_BINDING(curwin);
postponed_split = 0;
}
diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c
index 3ae1a6a890..4611b69424 100644
--- a/src/nvim/mouse.c
+++ b/src/nvim/mouse.c
@@ -14,6 +14,8 @@
#include "nvim/misc1.h"
#include "nvim/cursor.h"
#include "nvim/buffer_defs.h"
+#include "nvim/memline.h"
+#include "nvim/charset.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "mouse.c.generated.h"
@@ -503,3 +505,95 @@ void set_mouse_topline(win_T *wp)
orig_topfill = wp->w_topfill;
}
+///
+/// Return length of line "lnum" for horizontal scrolling.
+///
+static colnr_T scroll_line_len(linenr_T lnum)
+{
+ colnr_T col = 0;
+ char_u *line = ml_get(lnum);
+ if (*line != NUL) {
+ for (;;) {
+ int numchar = chartabsize(line, col);
+ mb_ptr_adv(line);
+ if (*line == NUL) { // don't count the last character
+ break;
+ }
+ col += numchar;
+ }
+ }
+ return col;
+}
+
+///
+/// Find longest visible line number.
+///
+static linenr_T find_longest_lnum(void)
+{
+ linenr_T ret = 0;
+
+ // Calculate maximum for horizontal scrollbar. Check for reasonable
+ // line numbers, topline and botline can be invalid when displaying is
+ // postponed.
+ if (curwin->w_topline <= curwin->w_cursor.lnum &&
+ curwin->w_botline > curwin->w_cursor.lnum &&
+ curwin->w_botline <= curbuf->b_ml.ml_line_count + 1) {
+ long max = 0;
+
+ // Use maximum of all visible lines. Remember the lnum of the
+ // longest line, closest to the cursor line. Used when scrolling
+ // below.
+ for (linenr_T lnum = curwin->w_topline; lnum < curwin->w_botline; lnum++) {
+ colnr_T len = scroll_line_len(lnum);
+ if (len > (colnr_T)max) {
+ max = len;
+ ret = lnum;
+ } else if (len == (colnr_T)max
+ && abs((int)(lnum - curwin->w_cursor.lnum))
+ < abs((int)(ret - curwin->w_cursor.lnum))) {
+ ret = lnum;
+ }
+ }
+ } else {
+ // Use cursor line only.
+ ret = curwin->w_cursor.lnum;
+ }
+
+ return ret;
+}
+
+///
+/// Do a horizontal scroll. Return TRUE if the cursor moved, FALSE otherwise.
+///
+bool mouse_scroll_horiz(int dir)
+{
+ if (curwin->w_p_wrap) {
+ return false;
+ }
+
+ int step = 6;
+ if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL)) {
+ step = curwin->w_width;
+ }
+
+ int leftcol = curwin->w_leftcol + (dir == MSCR_RIGHT ? -step : +step);
+ if (leftcol < 0) {
+ leftcol = 0;
+ }
+
+ if (curwin->w_leftcol == leftcol) {
+ return false;
+ }
+
+ curwin->w_leftcol = (colnr_T)leftcol;
+
+ // When the line of the cursor is too short, move the cursor to the
+ // longest visible line.
+ if (!virtual_active()
+ && (colnr_T)leftcol > scroll_line_len(curwin->w_cursor.lnum)) {
+ curwin->w_cursor.lnum = find_longest_lnum();
+ curwin->w_cursor.col = 0;
+ }
+
+ return leftcol_changed();
+}
diff --git a/src/nvim/mouse.h b/src/nvim/mouse.h
index c824bcc8f0..0149f7c7c0 100644
--- a/src/nvim/mouse.h
+++ b/src/nvim/mouse.h
@@ -34,6 +34,12 @@
#define MOUSE_X1 0x300 // Mouse-button X1 (6th)
#define MOUSE_X2 0x400 // Mouse-button X2
+// Direction for nv_mousescroll() and ins_mousescroll()
+#define MSCR_DOWN 0 // DOWN must be FALSE
+#define MSCR_UP 1
+#define MSCR_LEFT -1
+#define MSCR_RIGHT -2
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "mouse.h.generated.h"
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 5b7c4b68b1..75ee11bc9d 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -2598,11 +2598,10 @@ do_mouse (
end_visual.col = leftcol;
else
end_visual.col = rightcol;
- if (curwin->w_cursor.lnum <
- (start_visual.lnum + end_visual.lnum) / 2)
- end_visual.lnum = end_visual.lnum;
- else
+ if (curwin->w_cursor.lnum >=
+ (start_visual.lnum + end_visual.lnum) / 2) {
end_visual.lnum = start_visual.lnum;
+ }
/* move VIsual to the right column */
start_visual = curwin->w_cursor; /* save the cursor pos */
@@ -3244,9 +3243,9 @@ void clear_showcmd(void)
top = curwin->w_cursor.lnum;
bot = VIsual.lnum;
}
- /* Include closed folds as a whole. */
- hasFolding(top, &top, NULL);
- hasFolding(bot, NULL, &bot);
+ // Include closed folds as a whole.
+ (void)hasFolding(top, &top, NULL);
+ (void)hasFolding(bot, NULL, &bot);
lines = bot - top + 1;
if (VIsual_mode == Ctrl_V) {
@@ -3927,6 +3926,8 @@ static void nv_mousescroll(cmdarg_T *cap)
cap->count0 = 3;
nv_scroll_line(cap);
}
+ } else {
+ mouse_scroll_horiz(cap->arg);
}
curwin->w_redr_status = true;
@@ -5152,9 +5153,10 @@ static void nv_gotofile(cmdarg_T *cap)
ptr = grab_file_name(cap->count1, &lnum);
if (ptr != NULL) {
- /* do autowrite if necessary */
- if (curbufIsChanged() && curbuf->b_nwindows <= 1 && !P_HID(curbuf))
- autowrite(curbuf, false);
+ // do autowrite if necessary
+ if (curbufIsChanged() && curbuf->b_nwindows <= 1 && !P_HID(curbuf)) {
+ (void)autowrite(curbuf, false);
+ }
setpcmark();
(void)do_ecmd(0, ptr, NULL, NULL, ECMD_LAST,
P_HID(curbuf) ? ECMD_HIDE : 0, curwin);
diff --git a/src/nvim/option.c b/src/nvim/option.c
index f9d1cdbaec..3376348d6f 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -2057,6 +2057,7 @@ static void didset_options(void)
(void)opt_strings_flags(p_vop, p_ssop_values, &vop_flags, true);
(void)opt_strings_flags(p_fdo, p_fdo_values, &fdo_flags, true);
(void)opt_strings_flags(p_dy, p_dy_values, &dy_flags, true);
+ (void)opt_strings_flags(p_tc, p_tc_values, &tc_flags, false);
(void)opt_strings_flags(p_ve, p_ve_values, &ve_flags, true);
(void)spell_check_msm();
(void)spell_check_sps();
@@ -2144,6 +2145,7 @@ void check_buf_options(buf_T *buf)
check_string_option(&buf->b_p_ep);
check_string_option(&buf->b_p_path);
check_string_option(&buf->b_p_tags);
+ check_string_option(&buf->b_p_tc);
check_string_option(&buf->b_p_dict);
check_string_option(&buf->b_p_tsr);
check_string_option(&buf->b_p_lw);
@@ -2983,6 +2985,24 @@ did_set_string_option (
if (opt_strings_flags(p_bo, p_bo_values, &bo_flags, true) != OK) {
errmsg = e_invarg;
}
+ } else if (gvarp == &p_tc) { // 'tagcase'
+ unsigned int *flags;
+
+ if (opt_flags & OPT_LOCAL) {
+ p = curbuf->b_p_tc;
+ flags = &curbuf->b_tc_flags;
+ } else {
+ p = p_tc;
+ flags = &tc_flags;
+ }
+
+ if ((opt_flags & OPT_LOCAL) && *p == NUL) {
+ // make the local value empty: use the global value
+ *flags = 0;
+ } else if (*p == NUL
+ || opt_strings_flags(p, p_tc_values, flags, false) != OK) {
+ errmsg = e_invarg;
+ }
} else if (varp == &p_cmp) { // 'casemap'
if (opt_strings_flags(p_cmp, p_cmp_values, &cmp_flags, true) != OK)
errmsg = e_invarg;
@@ -5111,6 +5131,10 @@ void unset_global_local_option(char *name, void *from)
case PV_TAGS:
clear_string_option(&buf->b_p_tags);
break;
+ case PV_TC:
+ clear_string_option(&buf->b_p_tc);
+ buf->b_tc_flags = 0;
+ break;
case PV_DEF:
clear_string_option(&buf->b_p_def);
break;
@@ -5164,6 +5188,7 @@ static char_u *get_varp_scope(vimoption_T *p, int opt_flags)
case PV_PATH: return (char_u *)&(curbuf->b_p_path);
case PV_AR: return (char_u *)&(curbuf->b_p_ar);
case PV_TAGS: return (char_u *)&(curbuf->b_p_tags);
+ case PV_TC: return (char_u *)&(curbuf->b_p_tc);
case PV_DEF: return (char_u *)&(curbuf->b_p_def);
case PV_INC: return (char_u *)&(curbuf->b_p_inc);
case PV_DICT: return (char_u *)&(curbuf->b_p_dict);
@@ -5201,6 +5226,8 @@ static char_u *get_varp(vimoption_T *p)
? (char_u *)&(curbuf->b_p_ar) : p->var;
case PV_TAGS: return *curbuf->b_p_tags != NUL
? (char_u *)&(curbuf->b_p_tags) : p->var;
+ case PV_TC: return *curbuf->b_p_tc != NUL
+ ? (char_u *)&(curbuf->b_p_tc) : p->var;
case PV_BKC: return *curbuf->b_p_bkc != NUL
? (char_u *)&(curbuf->b_p_bkc) : p->var;
case PV_DEF: return *curbuf->b_p_def != NUL
@@ -5580,6 +5607,8 @@ void buf_copy_options(buf_T *buf, int flags)
buf->b_p_kp = empty_option;
buf->b_p_path = empty_option;
buf->b_p_tags = empty_option;
+ buf->b_p_tc = empty_option;
+ buf->b_tc_flags = 0;
buf->b_p_def = empty_option;
buf->b_p_inc = empty_option;
buf->b_p_inex = vim_strsave(p_inex);
diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h
index bbe40873ec..87a9a7398c 100644
--- a/src/nvim/option_defs.h
+++ b/src/nvim/option_defs.h
@@ -597,6 +597,14 @@ static char *(p_swb_values[]) =
#define SWB_NEWTAB 0x008
#define SWB_VSPLIT 0x010
EXTERN int p_tbs; ///< 'tagbsearch'
+EXTERN char_u *p_tc; ///< 'tagcase'
+EXTERN unsigned tc_flags; ///< flags from 'tagcase'
+#ifdef IN_OPTION_C
+static char *(p_tc_values[]) = { "followic", "ignore", "match", NULL };
+#endif
+#define TC_FOLLOWIC 0x01
+#define TC_IGNORE 0x02
+#define TC_MATCH 0x04
EXTERN long p_tl; ///< 'taglength'
EXTERN int p_tr; ///< 'tagrelative'
EXTERN char_u *p_tags; ///< 'tags'
@@ -737,6 +745,7 @@ enum {
, BV_SW
, BV_SWF
, BV_TAGS
+ , BV_TC
, BV_TS
, BV_TW
, BV_TX
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index df77c374ec..a743e8c605 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -2332,6 +2332,13 @@ return {
defaults={if_true={vi=true}}
},
{
+ full_name='tagcase', abbreviation='tc',
+ type='string', scope={'global', 'buffer'},
+ vim=true,
+ varname='p_tc',
+ defaults={if_true={vi="followic", vim="followic"}}
+ },
+ {
full_name='taglength', abbreviation='tl',
type='number', scope={'global'},
vi_def=true,
diff --git a/src/nvim/search.c b/src/nvim/search.c
index fffae1ecb2..faf70472bf 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -453,25 +453,24 @@ void last_pat_prog(regmmatch_T *regmatch)
--emsg_off;
}
-/*
- * lowest level search function.
- * Search for 'count'th occurrence of pattern 'pat' in direction 'dir'.
- * Start at position 'pos' and return the found position in 'pos'.
- *
- * if (options & SEARCH_MSG) == 0 don't give any messages
- * if (options & SEARCH_MSG) == SEARCH_NFMSG don't give 'notfound' messages
- * if (options & SEARCH_MSG) == SEARCH_MSG give all messages
- * if (options & SEARCH_HIS) put search pattern in history
- * if (options & SEARCH_END) return position at end of match
- * if (options & SEARCH_START) accept match at pos itself
- * if (options & SEARCH_KEEP) keep previous search pattern
- * if (options & SEARCH_FOLD) match only once in a closed fold
- * if (options & SEARCH_PEEK) check for typed char, cancel search
- *
- * Return FAIL (zero) for failure, non-zero for success.
- * Returns the index of the first matching
- * subpattern plus one; one if there was none.
- */
+/// lowest level search function.
+/// Search for 'count'th occurrence of pattern 'pat' in direction 'dir'.
+/// Start at position 'pos' and return the found position in 'pos'.
+///
+/// if (options & SEARCH_MSG) == 0 don't give any messages
+/// if (options & SEARCH_MSG) == SEARCH_NFMSG don't give 'notfound' messages
+/// if (options & SEARCH_MSG) == SEARCH_MSG give all messages
+/// if (options & SEARCH_HIS) put search pattern in history
+/// if (options & SEARCH_END) return position at end of match
+/// if (options & SEARCH_START) accept match at pos itself
+/// if (options & SEARCH_KEEP) keep previous search pattern
+/// if (options & SEARCH_FOLD) match only once in a closed fold
+/// if (options & SEARCH_PEEK) check for typed char, cancel search
+/// if (options & SEARCH_COL) start at pos->col instead of zero
+///
+/// @returns FAIL (zero) for failure, non-zero for success.
+/// the index of the first matching
+/// subpattern plus one; one if there was none.
int searchit(
win_T *win, /* window to search in, can be NULL for a
buffer without a window! */
@@ -571,16 +570,14 @@ int searchit(
if (tm != NULL && profile_passed_limit(*tm))
break;
- /*
- * Look for a match somewhere in line "lnum".
- */
+ // Look for a match somewhere in line "lnum".
+ colnr_T col = at_first_line && (options & SEARCH_COL) ? pos->col : 0;
nmatched = vim_regexec_multi(&regmatch, win, buf,
- lnum, (colnr_T)0,
- tm
- );
- /* Abort searching on an error (e.g., out of stack). */
- if (called_emsg)
+ lnum, col, tm);
+ // Abort searching on an error (e.g., out of stack).
+ if (called_emsg) {
break;
+ }
if (nmatched > 0) {
/* match may actually be in another line when using \zs */
matchpos = regmatch.startpos[0];
@@ -881,9 +878,8 @@ static void set_vv_searchforward(void)
set_vim_var_nr(VV_SEARCHFORWARD, (long)(spats[0].off.dir == '/'));
}
-/*
- * Return the number of the first subpat that matched.
- */
+// Return the number of the first subpat that matched.
+// Return zero if none of them matched.
static int first_submatch(regmmatch_T *rp)
{
int submatch;
diff --git a/src/nvim/search.h b/src/nvim/search.h
index 6947f79d49..d4e40cb287 100644
--- a/src/nvim/search.h
+++ b/src/nvim/search.h
@@ -15,19 +15,20 @@
#define ACTION_SHOW_ALL 4
#define ACTION_EXPAND 5
-/* Values for 'options' argument in do_search() and searchit() */
-#define SEARCH_REV 0x01 /* go in reverse of previous dir. */
-#define SEARCH_ECHO 0x02 /* echo the search command and handle options */
-#define SEARCH_MSG 0x0c /* give messages (yes, it's not 0x04) */
-#define SEARCH_NFMSG 0x08 /* give all messages except not found */
-#define SEARCH_OPT 0x10 /* interpret optional flags */
-#define SEARCH_HIS 0x20 /* put search pattern in history */
-#define SEARCH_END 0x40 /* put cursor at end of match */
-#define SEARCH_NOOF 0x80 /* don't add offset to position */
-#define SEARCH_START 0x100 /* start search without col offset */
-#define SEARCH_MARK 0x200 /* set previous context mark */
-#define SEARCH_KEEP 0x400 /* keep previous search pattern */
-#define SEARCH_PEEK 0x800 /* peek for typed char, cancel search */
+// Values for 'options' argument in do_search() and searchit()
+#define SEARCH_REV 0x01 ///< go in reverse of previous dir.
+#define SEARCH_ECHO 0x02 ///< echo the search command and handle options
+#define SEARCH_MSG 0x0c ///< give messages (yes, it's not 0x04)
+#define SEARCH_NFMSG 0x08 ///< give all messages except not found
+#define SEARCH_OPT 0x10 ///< interpret optional flags
+#define SEARCH_HIS 0x20 ///< put search pattern in history
+#define SEARCH_END 0x40 ///< put cursor at end of match
+#define SEARCH_NOOF 0x80 ///< don't add offset to position
+#define SEARCH_START 0x100 ///< start search without col offset
+#define SEARCH_MARK 0x200 ///< set previous context mark
+#define SEARCH_KEEP 0x400 ///< keep previous search pattern
+#define SEARCH_PEEK 0x800 ///< peek for typed char, cancel search
+#define SEARCH_COL 0x1000 ///< start at specified column instead of zero
/* Values for flags argument for findmatchlimit() */
#define FM_BACKWARD 0x01 /* search backwards */
diff --git a/src/nvim/tag.c b/src/nvim/tag.c
index 26a89094aa..da84106454 100644
--- a/src/nvim/tag.c
+++ b/src/nvim/tag.c
@@ -1147,6 +1147,22 @@ find_tags (
int get_it_again = FALSE;
int use_cscope = (flags & TAG_CSCOPE);
int verbose = (flags & TAG_VERBOSE);
+ int save_p_ic = p_ic;
+
+ // Change the value of 'ignorecase' according to 'tagcase' for the
+ // duration of this function.
+ switch (curbuf->b_tc_flags ? curbuf->b_tc_flags : tc_flags) {
+ case TC_FOLLOWIC:
+ break;
+ case TC_IGNORE:
+ p_ic = true;
+ break;
+ case TC_MATCH:
+ p_ic = false;
+ break;
+ default:
+ assert(false);
+ }
help_save = curbuf->b_help;
orgpat.pat = pat;
@@ -1955,6 +1971,8 @@ findtag_end:
curbuf->b_help = help_save;
xfree(saved_pat);
+ p_ic = save_p_ic;
+
return retval;
}
diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile
index 55a49122d5..4debdd9acc 100644
--- a/src/nvim/testdir/Makefile
+++ b/src/nvim/testdir/Makefile
@@ -36,9 +36,12 @@ SCRIPTS := \
test_breakindent.out \
test_close_count.out \
test_marks.out \
- test_match_conceal.out \
-NEW_TESTS = test_viml.res
+# Tests using runtest.vim.vim.
+# Keep test_alot*.res as the last one, sort the others.
+NEW_TESTS = \
+ test_viml.res \
+ test_alot.res
SCRIPTS_GUI := test16.out
diff --git a/src/nvim/testdir/test_alot.vim b/src/nvim/testdir/test_alot.vim
new file mode 100644
index 0000000000..1d1da94bac
--- /dev/null
+++ b/src/nvim/testdir/test_alot.vim
@@ -0,0 +1,3 @@
+" A series of tests that can run in one Vim invocation.
+" This makes testing go faster, since Vim doesn't need to restart.
+
diff --git a/src/nvim/version.c b/src/nvim/version.c
index ca6b66f220..e07c4a242a 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -533,8 +533,8 @@ static int included_patches[] = {
// 1147,
// 1146 NA
// 1145 NA
- // 1144 NA
- // 1143,
+ 1144,
+ 1143,
// 1142,
1141,
// 1140,
@@ -584,7 +584,7 @@ static int included_patches[] = {
// 1096,
// 1095 NA
// 1094,
- // 1093,
+ 1093,
// 1092,
// 1091,
// 1090,
@@ -693,7 +693,7 @@ static int included_patches[] = {
// 987 NA
// 986 NA
// 985 NA
- // 984,
+ 984,
// 983,
// 982 NA
981,
@@ -720,13 +720,13 @@ static int included_patches[] = {
// 960 NA
// 959 NA
958,
- // 957,
+ 957,
// 956 NA
955,
// 954 NA
953,
952,
- // 951,
+ 951,
950,
949,
// 948 NA
@@ -735,8 +735,8 @@ static int included_patches[] = {
945,
944,
// 943 NA
- // 942,
- // 941,
+ 942,
+ 941,
// 940 NA
939,
// 938 NA
@@ -855,7 +855,7 @@ static int included_patches[] = {
825,
// 824 NA
823,
- // 822,
+ 822,
// 821 NA
820,
819,
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 93a7a58678..bea55c465f 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -97,7 +97,7 @@ do_window (
* don't replicate the quickfix buffer. */
if (bt_quickfix(curbuf))
goto newwindow;
- win_split((int)Prenum, 0);
+ (void)win_split((int)Prenum, 0);
break;
/* split current window in two parts, vertically */
@@ -108,7 +108,7 @@ do_window (
* don't replicate the quickfix buffer. */
if (bt_quickfix(curbuf))
goto newwindow;
- win_split((int)Prenum, WSP_VERT);
+ (void)win_split((int)Prenum, WSP_VERT);
break;
/* split current window and edit alternate file */
diff --git a/test/functional/legacy/057_sort_spec.lua b/test/functional/legacy/057_sort_spec.lua
index 7eed31e292..36062ded3a 100644
--- a/test/functional/legacy/057_sort_spec.lua
+++ b/test/functional/legacy/057_sort_spec.lua
@@ -668,4 +668,22 @@ describe(':sort', function()
b0b101100
b0b111000]])
end)
+
+ it('float', function()
+ insert([[
+ 1.234
+ 0.88
+ 123.456
+ 1.15e-6
+ -1.1e3
+ -1.01e3]])
+ execute([[sort f]])
+ expect([[
+ -1.1e3
+ -1.01e3
+ 1.15e-6
+ 0.88
+ 1.234
+ 123.456]])
+ end)
end)
diff --git a/test/functional/legacy/function_sort_spec.lua b/test/functional/legacy/function_sort_spec.lua
new file mode 100644
index 0000000000..9083911021
--- /dev/null
+++ b/test/functional/legacy/function_sort_spec.lua
@@ -0,0 +1,29 @@
+local helpers = require('test.functional.helpers')
+local clear = helpers.clear
+local eq = helpers.eq
+local eval = helpers.eval
+
+describe('sort', function()
+ before_each(clear)
+
+ it('numbers compared as strings', function()
+ eq({1, 2, 3}, eval('sort([3, 2, 1])'))
+ eq({13, 28, 3}, eval('sort([3, 28, 13])'))
+ end)
+
+ it('numbers compared as numeric', function()
+ eq({1, 2, 3}, eval("sort([3, 2, 1], 'n')"))
+ eq({3, 13, 28}, eval("sort([3, 28, 13], 'n')"))
+ -- Strings are not sorted.
+ eq({'13', '28', '3'}, eval("sort(['13', '28', '3'], 'n')"))
+ end)
+
+ it('numbers compared as numbers', function()
+ eq({3, 13, 28}, eval("sort([13, 28, 3], 'N')"))
+ eq({'3', '13', '28'}, eval("sort(['13', '28', '3'], 'N')"))
+ end)
+
+ it('numbers compared as float', function()
+ eq({0.28, 3, 13.5}, eval("sort([13.5, 0.28, 3], 'f')"))
+ end)
+end)
diff --git a/test/functional/legacy/searchpos_spec.lua b/test/functional/legacy/searchpos_spec.lua
new file mode 100644
index 0000000000..1c9b1ccee6
--- /dev/null
+++ b/test/functional/legacy/searchpos_spec.lua
@@ -0,0 +1,35 @@
+local helpers = require('test.functional.helpers')
+local call = helpers.call
+local clear = helpers.clear
+local execute = helpers.execute
+local eq = helpers.eq
+local eval = helpers.eval
+local insert = helpers.insert
+
+describe('searchpos', function()
+ before_each(clear)
+
+ it('is working', function()
+ insert([[
+ 1a3
+ 123xyz]])
+
+ call('cursor', 1, 1)
+ eq({1, 1, 2}, eval([[searchpos('\%(\([a-z]\)\|\_.\)\{-}xyz', 'pcW')]]))
+ call('cursor', 1, 2)
+ eq({2, 1, 1}, eval([[searchpos('\%(\([a-z]\)\|\_.\)\{-}xyz', 'pcW')]]))
+
+ execute('set cpo-=c')
+ call('cursor', 1, 2)
+ eq({1, 2, 2}, eval([[searchpos('\%(\([a-z]\)\|\_.\)\{-}xyz', 'pcW')]]))
+ call('cursor', 1, 3)
+ eq({1, 3, 1}, eval([[searchpos('\%(\([a-z]\)\|\_.\)\{-}xyz', 'pcW')]]))
+
+ -- Now with \zs, first match is in column 0, "a" is matched.
+ call('cursor', 1, 3)
+ eq({2, 4, 2}, eval([[searchpos('\%(\([a-z]\)\|\_.\)\{-}\zsxyz', 'pcW')]]))
+ -- With z flag start at cursor column, don't see the "a".
+ call('cursor', 1, 3)
+ eq({2, 4, 1}, eval([[searchpos('\%(\([a-z]\)\|\_.\)\{-}\zsxyz', 'pcWz')]]))
+ end)
+end)
diff --git a/test/functional/legacy/tagcase_spec.lua b/test/functional/legacy/tagcase_spec.lua
new file mode 100644
index 0000000000..9a8c6fbe42
--- /dev/null
+++ b/test/functional/legacy/tagcase_spec.lua
@@ -0,0 +1,150 @@
+local helpers = require('test.functional.helpers')
+local clear = helpers.clear
+local eq = helpers.eq
+local eval = helpers.eval
+local exc_exec = helpers.exc_exec
+local expect = helpers.expect
+local insert = helpers.insert
+local source = helpers.source
+local write_file = helpers.write_file
+
+describe("'tagcase' option", function()
+ setup(function()
+ write_file('Xtags', [[
+ Bar Xtext 3
+ Foo Xtext 2
+ foo Xtext 4]])
+ end)
+
+ before_each(function()
+ clear()
+ source([[
+ lang mess C
+ set tags=Xtags]])
+ end)
+
+ teardown(function()
+ os.remove('Xtags')
+ end)
+
+ it('should have correct default values', function()
+ source([[
+ set ic&
+ setg tc&
+ setl tc&
+ ]])
+
+ eq(0, eval('&ic'))
+ eq('followic', eval('&g:tc'))
+ eq('followic', eval('&l:tc'))
+ eq('followic', eval('&tc'))
+ end)
+
+ it('should accept <empty> only for setlocal', function()
+ -- Verify that the local setting accepts <empty> but that the global setting
+ -- does not. The first of these (setting the local value to <empty>) should
+ -- succeed; the other two should fail.
+ eq(0, exc_exec('setl tc='))
+ eq('Vim(setglobal):E474: Invalid argument: tc=', exc_exec('setg tc='))
+ eq('Vim(set):E474: Invalid argument: tc=', exc_exec('set tc='))
+ end)
+
+ it("should work with 'ignorecase' correctly in all combinations", function()
+ -- Verify that the correct number of matching tags is found for all values of
+ -- 'ignorecase' and global and local values 'tagcase', in all combinations.
+ insert([[
+
+ Foo
+ Bar
+ foo
+
+ end text]])
+
+ source([[
+ for &ic in [0, 1]
+ for &g:tc in ["followic", "ignore", "match"]
+ for &l:tc in ["", "followic", "ignore", "match"]
+ call append('$', "ic=".&ic." g:tc=".&g:tc." l:tc=".&l:tc." tc=".&tc)
+ call append('$', len(taglist("^foo$")))
+ call append('$', len(taglist("^Foo$")))
+ endfor
+ endfor
+ endfor
+
+ 1,/^end text$/d]])
+
+ expect([[
+ ic=0 g:tc=followic l:tc= tc=followic
+ 1
+ 1
+ ic=0 g:tc=followic l:tc=followic tc=followic
+ 1
+ 1
+ ic=0 g:tc=followic l:tc=ignore tc=ignore
+ 2
+ 2
+ ic=0 g:tc=followic l:tc=match tc=match
+ 1
+ 1
+ ic=0 g:tc=ignore l:tc= tc=ignore
+ 2
+ 2
+ ic=0 g:tc=ignore l:tc=followic tc=followic
+ 1
+ 1
+ ic=0 g:tc=ignore l:tc=ignore tc=ignore
+ 2
+ 2
+ ic=0 g:tc=ignore l:tc=match tc=match
+ 1
+ 1
+ ic=0 g:tc=match l:tc= tc=match
+ 1
+ 1
+ ic=0 g:tc=match l:tc=followic tc=followic
+ 1
+ 1
+ ic=0 g:tc=match l:tc=ignore tc=ignore
+ 2
+ 2
+ ic=0 g:tc=match l:tc=match tc=match
+ 1
+ 1
+ ic=1 g:tc=followic l:tc= tc=followic
+ 2
+ 2
+ ic=1 g:tc=followic l:tc=followic tc=followic
+ 2
+ 2
+ ic=1 g:tc=followic l:tc=ignore tc=ignore
+ 2
+ 2
+ ic=1 g:tc=followic l:tc=match tc=match
+ 1
+ 1
+ ic=1 g:tc=ignore l:tc= tc=ignore
+ 2
+ 2
+ ic=1 g:tc=ignore l:tc=followic tc=followic
+ 2
+ 2
+ ic=1 g:tc=ignore l:tc=ignore tc=ignore
+ 2
+ 2
+ ic=1 g:tc=ignore l:tc=match tc=match
+ 1
+ 1
+ ic=1 g:tc=match l:tc= tc=match
+ 1
+ 1
+ ic=1 g:tc=match l:tc=followic tc=followic
+ 2
+ 2
+ ic=1 g:tc=match l:tc=ignore tc=ignore
+ 2
+ 2
+ ic=1 g:tc=match l:tc=match tc=match
+ 1
+ 1]])
+ end)
+end)
diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua
index da9d6a0cd2..d0d791308b 100644
--- a/test/functional/ui/mouse_spec.lua
+++ b/test/functional/ui/mouse_spec.lua
@@ -426,4 +426,35 @@ describe('Mouse input', function()
|
]])
end)
+
+ it('horizontal scrolling', function()
+ feed("<esc>:set nowrap<cr>")
+
+ feed("a <esc>20Ab<esc>")
+ screen:expect([[
+ |
+ |
+ bbbbbbbbbbbbbbb^b |
+ ~ |
+ |
+ ]])
+
+ feed("<ScrollWheelLeft><0,0>")
+ screen:expect([[
+ |
+ |
+ n bbbbbbbbbbbbbbbbbbb^b |
+ ~ |
+ |
+ ]])
+
+ feed("^<ScrollWheelRight><0,0>")
+ screen:expect([[
+ g |
+ |
+ ^t and selection bbbbbbbbb|
+ ~ |
+ |
+ ]])
+ end)
end)
diff --git a/test/functional/viml/completion_spec.lua b/test/functional/viml/completion_spec.lua
index 8b507c8ffc..322d777ab6 100644
--- a/test/functional/viml/completion_spec.lua
+++ b/test/functional/viml/completion_spec.lua
@@ -6,8 +6,22 @@ local eval, eq, neq = helpers.eval, helpers.eq, helpers.neq
local execute, source, expect = helpers.execute, helpers.source, helpers.expect
describe('completion', function()
+ local screen
+
before_each(function()
clear()
+ screen = Screen.new(60, 8)
+ screen:attach()
+ screen:set_default_attr_ignore({{bold=true, foreground=Screen.colors.Blue}})
+ screen:set_default_attr_ids({
+ [1] = {background = Screen.colors.LightMagenta},
+ [2] = {background = Screen.colors.Grey},
+ [3] = {bold = true},
+ [4] = {bold = true, foreground = Screen.colors.SeaGreen},
+ [5] = {foreground = Screen.colors.Red},
+ [6] = {background = Screen.colors.Black},
+ [7] = {foreground = Screen.colors.White, background = Screen.colors.Red},
+ })
end)
describe('v:completed_item', function()
@@ -15,18 +29,40 @@ describe('completion', function()
eq({}, eval('v:completed_item'))
end)
it('is empty dict if the candidate is not inserted', function()
- feed('ifoo<ESC>o<C-x><C-n><C-e><ESC>')
+ feed('ifoo<ESC>o<C-x><C-n>')
+ screen:expect([[
+ foo |
+ foo^ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- Keyword Local completion (^N^P) The only match} |
+ ]])
+ feed('<C-e>')
+ screen:expect([[
+ foo |
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- INSERT --} |
+ ]])
+ feed('<ESC>')
eq({}, eval('v:completed_item'))
end)
it('returns expected dict in normal completion', function()
- feed('ifoo<ESC>o<C-x><C-n><ESC>')
+ feed('ifoo<ESC>o<C-x><C-n>')
eq('foo', eval('getline(2)'))
eq({word = 'foo', abbr = '', menu = '', info = '', kind = ''},
eval('v:completed_item'))
end)
it('is readonly', function()
+ screen:try_resize(80, 8)
feed('ifoo<ESC>o<C-x><C-n><ESC>')
-
execute('let v:completed_item.word = "bar"')
neq(nil, string.find(eval('v:errmsg'), '^E46: '))
execute('let v:errmsg = ""')
@@ -51,17 +87,29 @@ describe('completion', function()
source([[
function! TestOmni(findstart, base) abort
return a:findstart ? 0 : [{'word': 'foo', 'abbr': 'bar',
- \ 'menu': 'baz', 'info': 'foobar', 'kind': 'foobaz'}]
+ \ 'menu': 'baz', 'info': 'foobar', 'kind': 'foobaz'},
+ \ {'word': 'word', 'abbr': 'abbr', 'menu': 'menu', 'info': 'info', 'kind': 'kind'}]
endfunction
setlocal omnifunc=TestOmni
]])
- feed('i<C-x><C-o><ESC>')
+ feed('i<C-x><C-o>')
eq('foo', eval('getline(1)'))
+ screen:expect([[
+ foo^ |
+ {2:bar foobaz baz } |
+ {1:abbr kind menu } |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- Omni completion (^O^N^P) }{4:match 1 of 2} |
+ ]])
eq({word = 'foo', abbr = 'bar', menu = 'baz',
info = 'foobar', kind = 'foobaz'},
eval('v:completed_item'))
end)
end)
+
describe('completeopt', function()
before_each(function()
source([[
@@ -74,30 +122,182 @@ describe('completion', function()
it('inserts the first candidate if default', function()
execute('set completeopt+=menuone')
- feed('ifoo<ESC>o<C-x><C-n>bar<ESC>')
+ feed('ifoo<ESC>o')
+ screen:expect([[
+ foo |
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- INSERT --} |
+ ]])
+ feed('<C-x>')
+ -- the ^X prompt, only test this once
+ screen:expect([[
+ foo |
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)} |
+ ]])
+ feed('<C-n>')
+ screen:expect([[
+ foo |
+ foo^ |
+ {2:foo } |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- Keyword Local completion (^N^P) The only match} |
+ ]])
+ feed('bar<ESC>')
eq('foobar', eval('getline(2)'))
- feed('o<C-r>=TestComplete()<CR><ESC>')
+ feed('o<C-r>=TestComplete()<CR>')
+ screen:expect([[
+ foo |
+ foobar |
+ foo^ |
+ {2:foo } |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- INSERT --} |
+ ]])
eq('foo', eval('getline(3)'))
end)
it('selects the first candidate if noinsert', function()
execute('set completeopt+=menuone,noinsert')
- feed('ifoo<ESC>o<C-x><C-n><C-y><ESC>')
+ feed('ifoo<ESC>o<C-x><C-n>')
+ screen:expect([[
+ foo |
+ ^ |
+ {2:foo } |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- Keyword Local completion (^N^P) The only match} |
+ ]])
+ feed('<C-y>')
+ screen:expect([[
+ foo |
+ foo^ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- INSERT --} |
+ ]])
+ feed('<ESC>')
eq('foo', eval('getline(2)'))
- feed('o<C-r>=TestComplete()<CR><C-y><ESC>')
+ feed('o<C-r>=TestComplete()<CR>')
+ screen:expect([[
+ foo |
+ foo |
+ ^ |
+ {2:foo } |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- INSERT --} |
+ ]])
+ feed('<C-y><ESC>')
eq('foo', eval('getline(3)'))
end)
it('does not insert the first candidate if noselect', function()
execute('set completeopt+=menuone,noselect')
- feed('ifoo<ESC>o<C-x><C-n>bar<ESC>')
+ feed('ifoo<ESC>o<C-x><C-n>')
+ screen:expect([[
+ foo |
+ ^ |
+ {1:foo } |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- Keyword Local completion (^N^P) }{5:Back at original} |
+ ]])
+ feed('b')
+ screen:expect([[
+ foo |
+ b^ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- Keyword Local completion (^N^P) }{5:Back at original} |
+ ]])
+ feed('ar<ESC>')
eq('bar', eval('getline(2)'))
- feed('o<C-r>=TestComplete()<CR>bar<ESC>')
+ feed('o<C-r>=TestComplete()<CR>')
+ screen:expect([[
+ foo |
+ bar |
+ ^ |
+ {1:foo } |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- INSERT --} |
+ ]])
+ feed('bar<ESC>')
eq('bar', eval('getline(3)'))
end)
it('does not select/insert the first candidate if noselect and noinsert', function()
execute('set completeopt+=menuone,noselect,noinsert')
- feed('ifoo<ESC>o<C-x><C-n><ESC>')
+ feed('ifoo<ESC>o<C-x><C-n>')
+ screen:expect([[
+ foo |
+ ^ |
+ {1:foo } |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- Keyword Local completion (^N^P) }{5:Back at original} |
+ ]])
+ feed('<ESC>')
+ screen:expect([[
+ foo |
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ |
+ ]])
eq('', eval('getline(2)'))
- feed('o<C-r>=TestComplete()<CR><ESC>')
+ feed('o<C-r>=TestComplete()<CR>')
+ screen:expect([[
+ foo |
+ |
+ ^ |
+ {1:foo } |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- INSERT --} |
+ ]])
+ feed('<ESC>')
+ screen:expect([[
+ foo |
+ |
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ |
+ ]])
eq('', eval('getline(3)'))
end)
it('does not change modified state if noinsert', function()
@@ -142,12 +342,130 @@ describe('completion', function()
end )
it('completes on each input char', function ()
- feed('i<C-x><C-u>gu<Down><C-y>')
+ feed('i<C-x><C-u>')
+ screen:expect([[
+ ^ |
+ {1:January }{6: } |
+ {1:February }{6: } |
+ {1:March }{6: } |
+ {1:April }{2: } |
+ {1:May }{2: } |
+ {1:June }{2: } |
+ {3:-- User defined completion (^U^N^P) }{5:Back at original} |
+ ]])
+ feed('u')
+ screen:expect([[
+ u^ |
+ {1:January } |
+ {1:February } |
+ {1:June } |
+ {1:July } |
+ {1:August } |
+ ~ |
+ {3:-- User defined completion (^U^N^P) }{5:Back at original} |
+ ]])
+ feed('g')
+ screen:expect([[
+ ug^ |
+ {1:August } |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- User defined completion (^U^N^P) }{5:Back at original} |
+ ]])
+ feed('<Down>')
+ screen:expect([[
+ ug^ |
+ {2:August } |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- User defined completion (^U^N^P) The only match} |
+ ]])
+ feed('<C-y>')
+ screen:expect([[
+ August^ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- INSERT --} |
+ ]])
expect('August')
end)
it("repeats correctly after backspace #2674", function ()
- feed('o<C-x><C-u>Ja<BS><C-n><C-n><Esc>')
+ feed('o<C-x><C-u>Ja')
+ screen:expect([[
+ |
+ Ja^ |
+ {1:January } |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- User defined completion (^U^N^P) }{5:Back at original} |
+ ]])
+ feed('<BS>')
+ screen:expect([[
+ |
+ J^ |
+ {1:January } |
+ {1:June } |
+ {1:July } |
+ ~ |
+ ~ |
+ {3:-- User defined completion (^U^N^P) }{5:Back at original} |
+ ]])
+ feed('<C-n>')
+ screen:expect([[
+ |
+ January^ |
+ {2:January } |
+ {1:June } |
+ {1:July } |
+ ~ |
+ ~ |
+ {3:-- User defined completion (^U^N^P) }{4:match 1 of 3} |
+ ]])
+ feed('<C-n>')
+ screen:expect([[
+ |
+ June^ |
+ {1:January } |
+ {2:June } |
+ {1:July } |
+ ~ |
+ ~ |
+ {3:-- User defined completion (^U^N^P) }{4:match 2 of 3} |
+ ]])
+ feed('<Esc>')
+ screen:expect([[
+ |
+ Jun^e |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ |
+ ]])
feed('.')
+ screen:expect([[
+ |
+ June |
+ Jun^e |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ |
+ ]])
expect([[
June
@@ -155,60 +473,245 @@ describe('completion', function()
end)
end)
+ describe('with a lot of items', function()
+ before_each(function()
+ source([[
+ function! TestComplete() abort
+ call complete(1, map(range(0,100), "string(v:val)"))
+ return ''
+ endfunction
+ ]])
+ execute("set completeopt=menuone,noselect")
+ end)
+
+ it("works", function()
+ feed('i<C-r>=TestComplete()<CR>')
+ screen:expect([[
+ ^ |
+ {1:0 }{6: } |
+ {1:1 }{2: } |
+ {1:2 }{2: } |
+ {1:3 }{2: } |
+ {1:4 }{2: } |
+ {1:5 }{2: } |
+ {3:-- INSERT --} |
+ ]])
+ feed('7')
+ screen:expect([[
+ 7^ |
+ {1:7 }{6: } |
+ {1:70 }{6: } |
+ {1:71 }{6: } |
+ {1:72 }{2: } |
+ {1:73 }{2: } |
+ {1:74 }{2: } |
+ {3:-- INSERT --} |
+ ]])
+ feed('<c-n>')
+ screen:expect([[
+ 7^ |
+ {2:7 }{6: } |
+ {1:70 }{6: } |
+ {1:71 }{6: } |
+ {1:72 }{2: } |
+ {1:73 }{2: } |
+ {1:74 }{2: } |
+ {3:-- INSERT --} |
+ ]])
+ feed('<c-n>')
+ screen:expect([[
+ 70^ |
+ {1:7 }{6: } |
+ {2:70 }{6: } |
+ {1:71 }{6: } |
+ {1:72 }{2: } |
+ {1:73 }{2: } |
+ {1:74 }{2: } |
+ {3:-- INSERT --} |
+ ]])
+ end)
+
+ it('can be navigated with <PageDown>, <PageUp>', function()
+ feed('i<C-r>=TestComplete()<CR>')
+ screen:expect([[
+ ^ |
+ {1:0 }{6: } |
+ {1:1 }{2: } |
+ {1:2 }{2: } |
+ {1:3 }{2: } |
+ {1:4 }{2: } |
+ {1:5 }{2: } |
+ {3:-- INSERT --} |
+ ]])
+ feed('<PageDown>')
+ screen:expect([[
+ ^ |
+ {1:0 }{6: } |
+ {1:1 }{2: } |
+ {1:2 }{2: } |
+ {2:3 } |
+ {1:4 }{2: } |
+ {1:5 }{2: } |
+ {3:-- INSERT --} |
+ ]])
+ feed('<PageDown>')
+ screen:expect([[
+ ^ |
+ {1:5 }{6: } |
+ {1:6 }{2: } |
+ {2:7 } |
+ {1:8 }{2: } |
+ {1:9 }{2: } |
+ {1:10 }{2: } |
+ {3:-- INSERT --} |
+ ]])
+ feed('<Down>')
+ screen:expect([[
+ ^ |
+ {1:5 }{6: } |
+ {1:6 }{2: } |
+ {1:7 }{2: } |
+ {2:8 } |
+ {1:9 }{2: } |
+ {1:10 }{2: } |
+ {3:-- INSERT --} |
+ ]])
+ feed('<PageUp>')
+ screen:expect([[
+ ^ |
+ {1:2 }{6: } |
+ {1:3 }{2: } |
+ {2:4 } |
+ {1:5 }{2: } |
+ {1:6 }{2: } |
+ {1:7 }{2: } |
+ {3:-- INSERT --} |
+ ]])
+ feed('<PageUp>') -- stop on first item
+ screen:expect([[
+ ^ |
+ {2:0 }{6: } |
+ {1:1 }{2: } |
+ {1:2 }{2: } |
+ {1:3 }{2: } |
+ {1:4 }{2: } |
+ {1:5 }{2: } |
+ {3:-- INSERT --} |
+ ]])
+ feed('<PageUp>') -- when on first item, unselect
+ screen:expect([[
+ ^ |
+ {1:0 }{6: } |
+ {1:1 }{2: } |
+ {1:2 }{2: } |
+ {1:3 }{2: } |
+ {1:4 }{2: } |
+ {1:5 }{2: } |
+ {3:-- INSERT --} |
+ ]])
+ feed('<PageUp>') -- when unselected, select last item
+ screen:expect([[
+ ^ |
+ {1:95 }{2: } |
+ {1:96 }{2: } |
+ {1:97 }{2: } |
+ {1:98 }{2: } |
+ {1:99 }{2: } |
+ {2:100 }{6: } |
+ {3:-- INSERT --} |
+ ]])
+ feed('<PageUp>')
+ screen:expect([[
+ ^ |
+ {1:94 }{2: } |
+ {1:95 }{2: } |
+ {2:96 } |
+ {1:97 }{2: } |
+ {1:98 }{2: } |
+ {1:99 }{6: } |
+ {3:-- INSERT --} |
+ ]])
+ feed('<cr>')
+ screen:expect([[
+ 96^ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- INSERT --} |
+ ]])
+ end)
+ end)
+
+
it('disables folding during completion', function ()
execute("set foldmethod=indent")
- feed('i<Tab>foo<CR><Tab>bar<Esc>ggA<C-x><C-l>')
+ feed('i<Tab>foo<CR><Tab>bar<Esc>gg')
+ screen:expect([[
+ ^foo |
+ bar |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ |
+ ]])
+ feed('A<C-x><C-l>')
+ screen:expect([[
+ foo^ |
+ bar |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- Whole line completion (^L^N^P) }{7:Pattern not found} |
+ ]])
eq(-1, eval('foldclosed(1)'))
end)
it('popupmenu is not interrupted by events', function ()
- local screen = Screen.new(40, 8)
- screen:attach()
- screen:set_default_attr_ignore({{bold=true, foreground=Screen.colors.Blue}})
- screen:set_default_attr_ids({
- [1] = {background = Screen.colors.LightMagenta},
- [2] = {background = Screen.colors.Grey},
- [3] = {bold = true},
- [4] = {bold = true, foreground = Screen.colors.SeaGreen},
- })
-
execute("set complete=.")
+
feed('ifoobar fooegg<cr>f<c-p>')
screen:expect([[
- foobar fooegg |
- fooegg^ |
- {1:foobar } |
- {2:fooegg } |
- ~ |
- ~ |
- ~ |
- {3:-- }{4:match 1 of 2} |
+ foobar fooegg |
+ fooegg^ |
+ {1:foobar } |
+ {2:fooegg } |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- Keyword completion (^N^P) }{4:match 1 of 2} |
]])
eval('1 + 1')
-- popupmenu still visible
screen:expect([[
- foobar fooegg |
- fooegg^ |
- {1:foobar } |
- {2:fooegg } |
- ~ |
- ~ |
- ~ |
- {3:-- }{4:match 1 of 2} |
+ foobar fooegg |
+ fooegg^ |
+ {1:foobar } |
+ {2:fooegg } |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- Keyword completion (^N^P) }{4:match 1 of 2} |
]])
feed('<c-p>')
-- Didn't restart completion: old matches still used
screen:expect([[
- foobar fooegg |
- foobar^ |
- {2:foobar } |
- {1:fooegg } |
- ~ |
- ~ |
- ~ |
- {3:-- }{4:match 2 of 2} |
+ foobar fooegg |
+ foobar^ |
+ {2:foobar } |
+ {1:fooegg } |
+ ~ |
+ ~ |
+ ~ |
+ {3:-- Keyword completion (^N^P) }{4:match 2 of 2} |
]])
end)
diff --git a/test/unit/helpers.lua b/test/unit/helpers.lua
index 9b9c1fef0f..426ae2d9e0 100644
--- a/test/unit/helpers.lua
+++ b/test/unit/helpers.lua
@@ -140,6 +140,7 @@ do
local time = cimport('./src/nvim/os/time.h')
time.time_init()
main.early_init()
+ main.event_init()
end
-- C constants.
diff --git a/test/unit/os/shell_spec.lua b/test/unit/os/shell_spec.lua
index 6d1a9f3589..93103e4e8c 100644
--- a/test/unit/os/shell_spec.lua
+++ b/test/unit/os/shell_spec.lua
@@ -11,7 +11,7 @@ if allowed_os[jit.os] ~= true then
end
local helpers = require('test.unit.helpers')
-local shell = helpers.cimport(
+local cimported = helpers.cimport(
'./src/nvim/os/shell.h',
'./src/nvim/option_defs.h',
'./src/nvim/main.h',
@@ -25,18 +25,17 @@ local NULL = ffi.cast('void *', 0)
describe('shell functions', function()
setup(function()
- shell.event_init()
-- os_system() can't work when the p_sh and p_shcf variables are unset
- shell.p_sh = to_cstr('/bin/bash')
- shell.p_shcf = to_cstr('-c')
+ cimported.p_sh = to_cstr('/bin/bash')
+ cimported.p_shcf = to_cstr('-c')
end)
teardown(function()
- shell.event_teardown()
+ cimported.event_teardown()
end)
local function shell_build_argv(cmd, extra_args)
- local res = shell.shell_build_argv(
+ local res = cimported.shell_build_argv(
cmd and to_cstr(cmd),
extra_args and to_cstr(extra_args))
local argc = 0
@@ -45,10 +44,10 @@ describe('shell functions', function()
-- crash.
while res[argc] ~= nil do
ret[#ret + 1] = ffi.string(res[argc])
- shell.xfree(res[argc])
+ cimported.xfree(res[argc])
argc = argc + 1
end
- shell.xfree(res)
+ cimported.xfree(res)
return ret
end
@@ -59,8 +58,8 @@ describe('shell functions', function()
local nread = ffi.new('size_t[1]')
local argv = ffi.cast('char**',
- shell.shell_build_argv(to_cstr(cmd), nil))
- local status = shell.os_system(argv, input_or, input_len, output, nread)
+ cimported.shell_build_argv(to_cstr(cmd), nil))
+ local status = cimported.os_system(argv, input_or, input_len, output, nread)
return status, intern(output[0], nread[0])
end
@@ -97,13 +96,13 @@ describe('shell functions', function()
local saved_opts = {}
setup(function()
- saved_opts.p_sh = shell.p_sh
- saved_opts.p_shcf = shell.p_shcf
+ saved_opts.p_sh = cimported.p_sh
+ saved_opts.p_shcf = cimported.p_shcf
end)
teardown(function()
- shell.p_sh = saved_opts.p_sh
- shell.p_shcf = saved_opts.p_shcf
+ cimported.p_sh = saved_opts.p_sh
+ cimported.p_shcf = saved_opts.p_shcf
end)
it('works with NULL arguments', function()
@@ -123,8 +122,8 @@ describe('shell functions', function()
end)
it('splits and unquotes &shell and &shellcmdflag', function()
- shell.p_sh = to_cstr('/Program" "Files/zsh -f')
- shell.p_shcf = to_cstr('-x -o "sh word split" "-"c')
+ cimported.p_sh = to_cstr('/Program" "Files/zsh -f')
+ cimported.p_shcf = to_cstr('-x -o "sh word split" "-"c')
eq({'/Program Files/zsh', '-f',
'ghi jkl',
'-x', '-o', 'sh word split',