aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/tips.txt2
-rw-r--r--src/nvim/eval.c5
-rw-r--r--src/nvim/event/libuv_process.c7
-rw-r--r--src/nvim/event/process.c36
-rw-r--r--src/nvim/ex_cmds.c2
-rw-r--r--src/nvim/globals.h2
-rw-r--r--src/nvim/if_cscope.c5
-rw-r--r--src/nvim/os/pty_process_unix.c40
-rw-r--r--src/nvim/os/shell.c33
-rw-r--r--src/nvim/testdir/Makefile1
-rw-r--r--src/nvim/testdir/runtest.vim1
-rw-r--r--src/nvim/testdir/samples/memfile_test.c143
-rw-r--r--src/nvim/testdir/test_cscope.vim266
-rw-r--r--src/nvim/testdir/test_digraph.vim461
-rw-r--r--src/nvim/version.c22
15 files changed, 954 insertions, 72 deletions
diff --git a/runtime/doc/tips.txt b/runtime/doc/tips.txt
index 8032af7d0a..9d2eb3deba 100644
--- a/runtime/doc/tips.txt
+++ b/runtime/doc/tips.txt
@@ -400,7 +400,7 @@ when they are not in the same location as the compressed "doc" directory. See
==============================================================================
Hex editing *hex-editing* *using-xxd*
-See section |23.4| of the user manual.
+See section |23.3| of the user manual.
If one has a particular extension that one uses for binary files (such as exe,
bin, etc), you may find it helpful to automate the process with the following
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 1cc84f8c16..823b621638 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -23046,8 +23046,9 @@ static inline bool common_job_start(TerminalJobData *data, typval_T *rettv)
data->refcount++;
char *cmd = xstrdup(proc->argv[0]);
- if (!process_spawn(proc)) {
- EMSG2(_(e_jobspawn), cmd);
+ int status = process_spawn(proc);
+ if (status) {
+ EMSG3(_(e_jobspawn), os_strerror(status), cmd);
xfree(cmd);
if (proc->type == kProcessTypePty) {
xfree(data->proc.pty.term_name);
diff --git a/src/nvim/event/libuv_process.c b/src/nvim/event/libuv_process.c
index 907187aa17..3da0c386b4 100644
--- a/src/nvim/event/libuv_process.c
+++ b/src/nvim/event/libuv_process.c
@@ -13,7 +13,8 @@
# include "event/libuv_process.c.generated.h"
#endif
-bool libuv_process_spawn(LibuvProcess *uvproc)
+/// @returns zero on success, or negative error code
+int libuv_process_spawn(LibuvProcess *uvproc)
FUNC_ATTR_NONNULL_ALL
{
Process *proc = (Process *)uvproc;
@@ -51,11 +52,11 @@ bool libuv_process_spawn(LibuvProcess *uvproc)
int status;
if ((status = uv_spawn(&proc->loop->uv, &uvproc->uv, &uvproc->uvopts))) {
ELOG("uv_spawn failed: %s", uv_strerror(status));
- return false;
+ return status;
}
proc->pid = uvproc->uv.pid;
- return true;
+ return status;
}
void libuv_process_close(LibuvProcess *uvproc)
diff --git a/src/nvim/event/process.c b/src/nvim/event/process.c
index dc7886469b..4429a65f92 100644
--- a/src/nvim/event/process.c
+++ b/src/nvim/event/process.c
@@ -30,7 +30,8 @@
static bool process_is_tearing_down = false;
-bool process_spawn(Process *proc) FUNC_ATTR_NONNULL_ALL
+/// @returns zero on success, or negative error code
+int process_spawn(Process *proc) FUNC_ATTR_NONNULL_ALL
{
if (proc->in) {
uv_pipe_init(&proc->loop->uv, &proc->in->uv.pipe, 0);
@@ -44,19 +45,19 @@ bool process_spawn(Process *proc) FUNC_ATTR_NONNULL_ALL
uv_pipe_init(&proc->loop->uv, &proc->err->uv.pipe, 0);
}
- bool success;
+ int status;
switch (proc->type) {
case kProcessTypeUv:
- success = libuv_process_spawn((LibuvProcess *)proc);
+ status = libuv_process_spawn((LibuvProcess *)proc);
break;
case kProcessTypePty:
- success = pty_process_spawn((PtyProcess *)proc);
+ status = pty_process_spawn((PtyProcess *)proc);
break;
default:
abort();
}
- if (!success) {
+ if (status) {
if (proc->in) {
uv_close((uv_handle_t *)&proc->in->uv.pipe, NULL);
}
@@ -74,7 +75,7 @@ bool process_spawn(Process *proc) FUNC_ATTR_NONNULL_ALL
}
shell_free_argv(proc->argv);
proc->status = -1;
- return false;
+ return status;
}
if (proc->in) {
@@ -105,7 +106,7 @@ bool process_spawn(Process *proc) FUNC_ATTR_NONNULL_ALL
proc->internal_close_cb = decref;
proc->refcount++;
kl_push(WatcherPtr, proc->loop->children, proc);
- return true;
+ return 0;
}
void process_teardown(Loop *loop) FUNC_ATTR_NONNULL_ALL
@@ -155,19 +156,16 @@ void process_close_err(Process *proc) FUNC_ATTR_NONNULL_ALL
/// Synchronously wait for a process to finish
///
-/// @param process The Process instance
-/// @param ms Number of milliseconds to wait, 0 for not waiting, -1 for
-/// waiting until the process quits.
-/// @return returns the status code of the exited process. -1 if the process is
-/// still running and the `timeout` has expired. Note that this is
-/// indistinguishable from the process returning -1 by itself. Which
-/// is possible on some OS. Returns -2 if an user has interruped the
-/// wait.
+/// @param process Process instance
+/// @param ms Time in milliseconds to wait for the process.
+/// 0 for no wait. -1 to wait until the process quits.
+/// @return Exit code of the process.
+/// -1 if the timeout expired while the process is still running.
+/// -2 if the user interruped the wait.
int process_wait(Process *proc, int ms, MultiQueue *events)
FUNC_ATTR_NONNULL_ARG(1)
{
- // The default status is -1, which represents a timeout
- int status = -1;
+ int status = -1; // default
bool interrupted = false;
if (!proc->refcount) {
status = proc->status;
@@ -179,8 +177,8 @@ int process_wait(Process *proc, int ms, MultiQueue *events)
events = proc->events;
}
- // Increase refcount to stop the exit callback from being called(and possibly
- // being freed) before we have a chance to get the status.
+ // Increase refcount to stop the exit callback from being called (and possibly
+ // freed) before we have a chance to get the status.
proc->refcount++;
LOOP_PROCESS_EVENTS_UNTIL(proc->loop, events, ms,
// Until...
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 3b7f3b7b97..4b3798794c 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -2340,6 +2340,7 @@ int do_ecmd(
}
xfree(new_name);
au_new_curbuf.br_buf = NULL;
+ au_new_curbuf.br_buf_free_count = 0;
}
curwin->w_pcmark.lnum = 1;
@@ -2625,6 +2626,7 @@ static void delbuf_msg(char_u *name)
name == NULL ? (char_u *)"" : name);
xfree(name);
au_new_curbuf.br_buf = NULL;
+ au_new_curbuf.br_buf_free_count = 0;
}
static int append_indent = 0; /* autoindent for first line */
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index 9da6062ffb..696bdf586f 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -1127,7 +1127,7 @@ EXTERN char_u e_isadir2[] INIT(= N_("E17: \"%s\" is a directory"));
EXTERN char_u e_invjob[] INIT(= N_("E900: Invalid job id"));
EXTERN char_u e_jobtblfull[] INIT(= N_("E901: Job table is full"));
EXTERN char_u e_jobspawn[] INIT(= N_(
- "E903: Process for command \"%s\" could not be spawned"));
+ "E903: Process failed to start: %s: \"%s\""));
EXTERN char_u e_jobnotpty[] INIT(= N_("E904: Job is not connected to a pty"));
EXTERN char_u e_libcall[] INIT(= N_("E364: Library call failed for \"%s()\""));
EXTERN char_u e_mkdir[] INIT(= N_("E739: Cannot create directory %s: %s"));
diff --git a/src/nvim/if_cscope.c b/src/nvim/if_cscope.c
index 0b20647771..9d50058257 100644
--- a/src/nvim/if_cscope.c
+++ b/src/nvim/if_cscope.c
@@ -1294,9 +1294,10 @@ static int cs_kill(exarg_T *eap)
}
}
- if (i >= csinfo_size || csinfo[i].fname == NULL) {
- if (p_csverbose)
+ if (!killall && (i >= csinfo_size || csinfo[i].fname == NULL)) {
+ if (p_csverbose) {
(void)EMSG2(_("E261: cscope connection %s not found"), stok);
+ }
return CSCOPE_FAILURE;
} else {
if (killall) {
diff --git a/src/nvim/os/pty_process_unix.c b/src/nvim/os/pty_process_unix.c
index b57a69b82b..f5ba0c2612 100644
--- a/src/nvim/os/pty_process_unix.c
+++ b/src/nvim/os/pty_process_unix.c
@@ -33,7 +33,8 @@
# include "os/pty_process_unix.c.generated.h"
#endif
-bool pty_process_spawn(PtyProcess *ptyproc)
+/// @returns zero on success, or negative error code
+int pty_process_spawn(PtyProcess *ptyproc)
FUNC_ATTR_NONNULL_ALL
{
static struct termios termios;
@@ -41,6 +42,7 @@ bool pty_process_spawn(PtyProcess *ptyproc)
init_termios(&termios);
}
+ int status = 0; // zero or negative error code (libuv convention)
Process *proc = (Process *)ptyproc;
assert(!proc->err);
uv_signal_start(&proc->loop->children_watcher, chld_handler, SIGCHLD);
@@ -50,8 +52,9 @@ bool pty_process_spawn(PtyProcess *ptyproc)
int pid = forkpty(&master, NULL, &termios, &ptyproc->winsize);
if (pid < 0) {
+ status = -errno;
ELOG("forkpty failed: %s", strerror(errno));
- return false;
+ return status;
} else if (pid == 0) {
init_child(ptyproc);
abort();
@@ -60,30 +63,34 @@ bool pty_process_spawn(PtyProcess *ptyproc)
// make sure the master file descriptor is non blocking
int master_status_flags = fcntl(master, F_GETFL);
if (master_status_flags == -1) {
+ status = -errno;
ELOG("Failed to get master descriptor status flags: %s", strerror(errno));
goto error;
}
if (fcntl(master, F_SETFL, master_status_flags | O_NONBLOCK) == -1) {
+ status = -errno;
ELOG("Failed to make master descriptor non-blocking: %s", strerror(errno));
goto error;
}
- if (proc->in && !set_duplicating_descriptor(master, &proc->in->uv.pipe)) {
+ if (proc->in
+ && (status = set_duplicating_descriptor(master, &proc->in->uv.pipe))) {
goto error;
}
- if (proc->out && !set_duplicating_descriptor(master, &proc->out->uv.pipe)) {
+ if (proc->out
+ && (status = set_duplicating_descriptor(master, &proc->out->uv.pipe))) {
goto error;
}
ptyproc->tty_fd = master;
proc->pid = pid;
- return true;
+ return 0;
error:
close(master);
kill(pid, SIGKILL);
waitpid(pid, NULL, 0);
- return false;
+ return status;
}
void pty_process_resize(PtyProcess *ptyproc, uint16_t width, uint16_t height)
@@ -137,9 +144,10 @@ static void init_child(PtyProcess *ptyproc) FUNC_ATTR_NONNULL_ALL
return;
}
+ char *prog = ptyproc->process.argv[0];
setenv("TERM", ptyproc->term_name ? ptyproc->term_name : "ansi", 1);
- execvp(ptyproc->process.argv[0], ptyproc->process.argv);
- fprintf(stderr, "execvp failed: %s\n", strerror(errno));
+ execvp(prog, ptyproc->process.argv);
+ fprintf(stderr, "execvp failed: %s: %s\n", strerror(errno), prog);
}
static void init_termios(struct termios *termios) FUNC_ATTR_NONNULL_ALL
@@ -197,22 +205,24 @@ static void init_termios(struct termios *termios) FUNC_ATTR_NONNULL_ALL
termios->c_cc[VTIME] = 0;
}
-static bool set_duplicating_descriptor(int fd, uv_pipe_t *pipe)
+static int set_duplicating_descriptor(int fd, uv_pipe_t *pipe)
FUNC_ATTR_NONNULL_ALL
{
+ int status = 0; // zero or negative error code (libuv convention)
int fd_dup = dup(fd);
if (fd_dup < 0) {
+ status = -errno;
ELOG("Failed to dup descriptor %d: %s", fd, strerror(errno));
- return false;
+ return status;
}
- int uv_result = uv_pipe_open(pipe, fd_dup);
- if (uv_result) {
+ status = uv_pipe_open(pipe, fd_dup);
+ if (status) {
ELOG("Failed to set pipe to descriptor %d: %s",
- fd_dup, uv_strerror(uv_result));
+ fd_dup, uv_strerror(status));
close(fd_dup);
- return false;
+ return status;
}
- return true;
+ return status;
}
static void chld_handler(uv_signal_t *handle, int signum)
diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c
index 9514936ad0..a5fd37ed5c 100644
--- a/src/nvim/os/shell.c
+++ b/src/nvim/os/shell.c
@@ -124,13 +124,9 @@ int os_call_shell(char_u *cmd, ShellOpts opts, char_u *extra_args)
size_t nread;
- int status = do_os_system(shell_build_argv((char *)cmd, (char *)extra_args),
- input.data,
- input.len,
- output_ptr,
- &nread,
- emsg_silent,
- forward_output);
+ int exitcode = do_os_system(shell_build_argv((char *)cmd, (char *)extra_args),
+ input.data, input.len, output_ptr, &nread,
+ emsg_silent, forward_output);
xfree(input.data);
@@ -139,16 +135,16 @@ int os_call_shell(char_u *cmd, ShellOpts opts, char_u *extra_args)
xfree(output);
}
- if (!emsg_silent && status != 0 && !(opts & kShellOptSilent)) {
+ if (!emsg_silent && exitcode != 0 && !(opts & kShellOptSilent)) {
MSG_PUTS(_("\nshell returned "));
- msg_outnum(status);
+ msg_outnum(exitcode);
msg_putchar('\n');
}
State = current_state;
signal_accept_deadly();
- return status;
+ return exitcode;
}
/// os_system - synchronously execute a command in the shell
@@ -157,7 +153,7 @@ int os_call_shell(char_u *cmd, ShellOpts opts, char_u *extra_args)
/// char *output = NULL;
/// size_t nread = 0;
/// char *argv[] = {"ls", "-la", NULL};
-/// int status = os_sytem(argv, NULL, 0, &output, &nread);
+/// int exitcode = os_sytem(argv, NULL, 0, &output, &nread);
///
/// @param argv The commandline arguments to be passed to the shell. `argv`
/// will be consumed.
@@ -218,11 +214,14 @@ static int do_os_system(char **argv,
proc->in = input != NULL ? &in : NULL;
proc->out = &out;
proc->err = &err;
- if (!process_spawn(proc)) {
+ int status = process_spawn(proc);
+ if (status) {
loop_poll_events(&main_loop, 0);
- // Failed, probably due to 'sh' not being executable
+ // Failed, probably 'shell' is not executable.
if (!silent) {
- MSG_PUTS(_("\nCannot execute "));
+ MSG_PUTS(_("\nshell failed to start: "));
+ msg_outtrans((char_u *)os_strerror(status));
+ MSG_PUTS(": ");
msg_outtrans((char_u *)prog);
msg_putchar('\n');
}
@@ -262,7 +261,7 @@ static int do_os_system(char **argv,
// busy state.
ui_busy_start();
ui_flush();
- int status = process_wait(proc, -1, NULL);
+ int exitcode = process_wait(proc, -1, NULL);
if (!got_int && out_data_decide_throttle(0)) {
// Last chunk of output was skipped; display it now.
out_data_ring(NULL, SIZE_MAX);
@@ -289,7 +288,7 @@ static int do_os_system(char **argv,
assert(multiqueue_empty(events));
multiqueue_free(events);
- return status;
+ return exitcode;
}
/// - ensures at least `desired` bytes in buffer
@@ -321,7 +320,7 @@ static void system_data_cb(Stream *stream, RBuffer *buf, size_t count,
/// Tracks output received for the current executing shell command, and displays
/// a pulsing "..." when output should be skipped. Tracking depends on the
/// synchronous/blocking nature of ":!".
-//
+///
/// Purpose:
/// 1. CTRL-C is more responsive. #1234 #5396
/// 2. Improves performance of :! (UI, esp. TUI, is the bottleneck).
diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile
index 7bcc78e58a..59c93f1673 100644
--- a/src/nvim/testdir/Makefile
+++ b/src/nvim/testdir/Makefile
@@ -31,6 +31,7 @@ NEW_TESTS = \
test_bufwintabinfo.res \
test_cmdline.res \
test_cscope.res \
+ test_digraph.res \
test_diffmode.res \
test_gn.res \
test_hardcopy.res \
diff --git a/src/nvim/testdir/runtest.vim b/src/nvim/testdir/runtest.vim
index eb5912086b..316aba968d 100644
--- a/src/nvim/testdir/runtest.vim
+++ b/src/nvim/testdir/runtest.vim
@@ -65,6 +65,7 @@ set shellslash
" Align with vim defaults.
set directory^=.
set nohidden
+set backspace=
function RunTheTest(test)
echo 'Executing ' . a:test
diff --git a/src/nvim/testdir/samples/memfile_test.c b/src/nvim/testdir/samples/memfile_test.c
new file mode 100644
index 0000000000..0fa1e14c40
--- /dev/null
+++ b/src/nvim/testdir/samples/memfile_test.c
@@ -0,0 +1,143 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ * See README.txt for an overview of the Vim source code.
+ */
+
+/*
+ * memfile_test.c: Unittests for memfile.c
+ * Mostly by Ivan Krasilnikov.
+ */
+
+#undef NDEBUG
+#include <assert.h>
+
+/* Must include main.c because it contains much more than just main() */
+#define NO_VIM_MAIN
+#include "main.c"
+
+/* This file has to be included because the tested functions are static */
+#include "memfile.c"
+
+#define index_to_key(i) ((i) ^ 15167)
+#define TEST_COUNT 50000
+
+/*
+ * Test mf_hash_*() functions.
+ */
+ static void
+test_mf_hash(void)
+{
+ mf_hashtab_T ht;
+ mf_hashitem_T *item;
+ blocknr_T key;
+ long_u i;
+ long_u num_buckets;
+
+ mf_hash_init(&ht);
+
+ /* insert some items and check invariants */
+ for (i = 0; i < TEST_COUNT; i++)
+ {
+ assert(ht.mht_count == i);
+
+ /* check that number of buckets is a power of 2 */
+ num_buckets = ht.mht_mask + 1;
+ assert(num_buckets > 0 && (num_buckets & (num_buckets - 1)) == 0);
+
+ /* check load factor */
+ assert(ht.mht_count <= (num_buckets << MHT_LOG_LOAD_FACTOR));
+
+ if (i < (MHT_INIT_SIZE << MHT_LOG_LOAD_FACTOR))
+ {
+ /* first expansion shouldn't have occurred yet */
+ assert(num_buckets == MHT_INIT_SIZE);
+ assert(ht.mht_buckets == ht.mht_small_buckets);
+ }
+ else
+ {
+ assert(num_buckets > MHT_INIT_SIZE);
+ assert(ht.mht_buckets != ht.mht_small_buckets);
+ }
+
+ key = index_to_key(i);
+ assert(mf_hash_find(&ht, key) == NULL);
+
+ /* allocate and add new item */
+ item = (mf_hashitem_T *)lalloc_clear(sizeof(mf_hashtab_T), FALSE);
+ assert(item != NULL);
+ item->mhi_key = key;
+ mf_hash_add_item(&ht, item);
+
+ assert(mf_hash_find(&ht, key) == item);
+
+ if (ht.mht_mask + 1 != num_buckets)
+ {
+ /* hash table was expanded */
+ assert(ht.mht_mask + 1 == num_buckets * MHT_GROWTH_FACTOR);
+ assert(i + 1 == (num_buckets << MHT_LOG_LOAD_FACTOR));
+ }
+ }
+
+ /* check presence of inserted items */
+ for (i = 0; i < TEST_COUNT; i++)
+ {
+ key = index_to_key(i);
+ item = mf_hash_find(&ht, key);
+ assert(item != NULL);
+ assert(item->mhi_key == key);
+ }
+
+ /* delete some items */
+ for (i = 0; i < TEST_COUNT; i++)
+ {
+ if (i % 100 < 70)
+ {
+ key = index_to_key(i);
+ item = mf_hash_find(&ht, key);
+ assert(item != NULL);
+ assert(item->mhi_key == key);
+
+ mf_hash_rem_item(&ht, item);
+ assert(mf_hash_find(&ht, key) == NULL);
+
+ mf_hash_add_item(&ht, item);
+ assert(mf_hash_find(&ht, key) == item);
+
+ mf_hash_rem_item(&ht, item);
+ assert(mf_hash_find(&ht, key) == NULL);
+
+ vim_free(item);
+ }
+ }
+
+ /* check again */
+ for (i = 0; i < TEST_COUNT; i++)
+ {
+ key = index_to_key(i);
+ item = mf_hash_find(&ht, key);
+
+ if (i % 100 < 70)
+ {
+ assert(item == NULL);
+ }
+ else
+ {
+ assert(item != NULL);
+ assert(item->mhi_key == key);
+ }
+ }
+
+ /* free hash table and all remaining items */
+ mf_hash_free_all(&ht);
+}
+
+ int
+main(void)
+{
+ test_mf_hash();
+ return 0;
+}
diff --git a/src/nvim/testdir/test_cscope.vim b/src/nvim/testdir/test_cscope.vim
index b6d70f0765..c8d2ebd7da 100644
--- a/src/nvim/testdir/test_cscope.vim
+++ b/src/nvim/testdir/test_cscope.vim
@@ -1,9 +1,262 @@
" Test for cscope commands.
-if !has('cscope')
+if !has('cscope') || !executable('cscope') || !has('quickfix')
finish
endif
+func CscopeSetupOrClean(setup)
+ if a:setup
+ noa sp samples/memfile_test.c
+ saveas! Xmemfile_test.c
+ call system('cscope -bk -fXcscope.out Xmemfile_test.c')
+ call system('cscope -bk -fXcscope2.out Xmemfile_test.c')
+ cscope add Xcscope.out
+ set cscopequickfix=s-,g-,d-,c-,t-,e-,f-,i-,a-
+ else
+ cscope kill -1
+ for file in ['Xcscope.out', 'Xcscope2.out', 'Xmemfile_test.c']
+ call delete(file)
+ endfo
+ endif
+endfunc
+
+func Test_cscopeWithCscopeConnections()
+ call CscopeSetupOrClean(1)
+ " Test 0: E568: duplicate cscope database not added
+ try
+ set nocscopeverbose
+ cscope add Xcscope.out
+ set cscopeverbose
+ catch
+ call assert_true(0)
+ endtry
+ call assert_fails('cscope add', 'E560')
+ call assert_fails('cscope add Xcscope.out', 'E568')
+ call assert_fails('cscope add doesnotexist.out', 'E563')
+
+ " Test 1: Find this C-Symbol
+ for cmd in ['cs find s main', 'cs find 0 main']
+ let a=execute(cmd)
+ " Test 1.1 test where it moves the cursor
+ call assert_equal('main(void)', getline('.'))
+ " Test 1.2 test the output of the :cs command
+ call assert_match('\n(1 of 1): <<main>> main(void )', a)
+ endfor
+
+ " Test 2: Find this definition
+ for cmd in ['cs find g test_mf_hash', 'cs find 1 test_mf_hash']
+ exe cmd
+ call assert_equal(['', '/*', ' * Test mf_hash_*() functions.', ' */', ' static void', 'test_mf_hash(void)', '{'], getline(line('.')-5, line('.')+1))
+ endfor
+
+ " Test 3: Find functions called by this function
+ for cmd in ['cs find d test_mf_hash', 'cs find 2 test_mf_hash']
+ let a=execute(cmd)
+ call assert_match('\n(1 of 42): <<mf_hash_init>> mf_hash_init(&ht);', a)
+ call assert_equal(' mf_hash_init(&ht);', getline('.'))
+ endfor
+
+ " Test 4: Find functions calling this function
+ for cmd in ['cs find c test_mf_hash', 'cs find 3 test_mf_hash']
+ let a=execute(cmd)
+ call assert_match('\n(1 of 1): <<main>> test_mf_hash();', a)
+ call assert_equal(' test_mf_hash();', getline('.'))
+ endfor
+
+ " Test 5: Find this text string
+ for cmd in ['cs find t Bram', 'cs find 4 Bram']
+ let a=execute(cmd)
+ call assert_match('(1 of 1): <<<unknown>>> \* VIM - Vi IMproved^Iby Bram Moolenaar', a)
+ call assert_equal(' * VIM - Vi IMproved by Bram Moolenaar', getline('.'))
+ endfor
+
+ " Test 6: Find this egrep pattern
+ " test all matches returned by cscope
+ for cmd in ['cs find e ^\#includ.', 'cs find 6 ^\#includ.']
+ let a=execute(cmd)
+ call assert_match('\n(1 of 3): <<<unknown>>> #include <assert.h>', a)
+ call assert_equal('#include <assert.h>', getline('.'))
+ cnext
+ call assert_equal('#include "main.c"', getline('.'))
+ cnext
+ call assert_equal('#include "memfile.c"', getline('.'))
+ call assert_fails('cnext', 'E553:')
+ endfor
+
+ " Test 7: Find the same egrep pattern using lcscope this time.
+ let a=execute('lcs find e ^\#includ.')
+ call assert_match('\n(1 of 3): <<<unknown>>> #include <assert.h>', a)
+ call assert_equal('#include <assert.h>', getline('.'))
+ lnext
+ call assert_equal('#include "main.c"', getline('.'))
+ lnext
+ call assert_equal('#include "memfile.c"', getline('.'))
+ call assert_fails('lnext', 'E553:')
+
+ " Test 8: Find this file
+ for cmd in ['cs find f Xmemfile_test.c', 'cs find 7 Xmemfile_test.c']
+ enew
+ let a=execute(cmd)
+ call assert_true(a =~ '"Xmemfile_test.c" \d\+L, \d\+C')
+ call assert_equal('Xmemfile_test.c', @%)
+ endfor
+
+ " Test 9: Find files #including this file
+ for cmd in ['cs find i assert.h', 'cs find 8 assert.h']
+ enew
+ let a=execute(cmd)
+ let alines = split(a, '\n', 1)
+ call assert_equal('', alines[0])
+ call assert_true(alines[1] =~ '"Xmemfile_test.c" \d\+L, \d\+C')
+ call assert_equal('(1 of 1): <<global>> #include <assert.h>', alines[2])
+ call assert_equal('#include <assert.h>', getline('.'))
+ endfor
+
+ " Test 10: Invalid find command
+ call assert_fails('cs find x', 'E560:')
+
+ " Test 11: Find places where this symbol is assigned a value
+ " this needs a cscope >= 15.8
+ " unfortunately, Travis has cscope version 15.7
+ let cscope_version=systemlist('cscope --version')[0]
+ let cs_version=str2float(matchstr(cscope_version, '\d\+\(\.\d\+\)\?'))
+ if cs_version >= 15.8
+ for cmd in ['cs find a item', 'cs find 9 item']
+ let a=execute(cmd)
+ call assert_equal(['', '(1 of 4): <<test_mf_hash>> item = (mf_hashitem_T *)lalloc_clear(sizeof(mf_hashtab_T), FALSE);'], split(a, '\n', 1))
+ call assert_equal(' item = (mf_hashitem_T *)lalloc_clear(sizeof(mf_hashtab_T), FALSE);', getline('.'))
+ cnext
+ call assert_equal(' item = mf_hash_find(&ht, key);', getline('.'))
+ cnext
+ call assert_equal(' item = mf_hash_find(&ht, key);', getline('.'))
+ cnext
+ call assert_equal(' item = mf_hash_find(&ht, key);', getline('.'))
+ endfor
+ endif
+
+ " Test 12: leading whitespace is not removed for cscope find text
+ let a=execute('cscope find t test_mf_hash')
+ call assert_equal(['', '(1 of 1): <<<unknown>>> test_mf_hash();'], split(a, '\n', 1))
+ call assert_equal(' test_mf_hash();', getline('.'))
+
+ " Test 13: test with scscope
+ let a=execute('scs find t Bram')
+ call assert_match('(1 of 1): <<<unknown>>> \* VIM - Vi IMproved^Iby Bram Moolenaar', a)
+ call assert_equal(' * VIM - Vi IMproved by Bram Moolenaar', getline('.'))
+
+ " Test 14: cscope help
+ for cmd in ['cs', 'cs help', 'cs xxx']
+ let a=execute(cmd)
+ call assert_match('^cscope commands:\n', a)
+ call assert_match('\nadd :', a)
+ call assert_match('\nfind :', a)
+ call assert_match('\nhelp : Show this message', a)
+ call assert_match('\nkill : Kill a connection', a)
+ call assert_match('\nreset: Reinit all connections', a)
+ call assert_match('\nshow : Show connections', a)
+ endfor
+ let a=execute('scscope help')
+ call assert_match('This cscope command does not support splitting the window\.', a)
+
+ " Test 15: reset connections
+ let a=execute('cscope reset')
+ call assert_match('\nAdded cscope database.*Xcscope.out (#0)', a)
+ call assert_match('\nAll cscope databases reset', a)
+
+ " Test 16: cscope show
+ let a=execute('cscope show')
+ call assert_match('\n 0 \d\+.*Xcscope.out\s*<none>', a)
+
+ " Test 17: cstag and 'csto' option
+ set csto=0
+ let a=execute('cstag TEST_COUNT')
+ call assert_match('(1 of 1): <<TEST_COUNT>> #define TEST_COUNT 50000', a)
+ call assert_equal('#define TEST_COUNT 50000', getline('.'))
+ set csto=1
+ let a=execute('cstag index_to_key')
+ call assert_match('(1 of 1): <<index_to_key>> #define index_to_key(i) ((i) ^ 15167)', a)
+ call assert_equal('#define index_to_key(i) ((i) ^ 15167)', getline('.'))
+ call assert_fails('cstag xxx', 'E257:')
+ call assert_fails('cstag', 'E562:')
+
+ " Test 18: 'cst' option
+ set nocst
+ call assert_fails('tag TEST_COUNT', 'E426:')
+ set cst
+ let a=execute('tag TEST_COUNT')
+ call assert_match('(1 of 1): <<TEST_COUNT>> #define TEST_COUNT 50000', a)
+ call assert_equal('#define TEST_COUNT 50000', getline('.'))
+ let a=execute('tags')
+ call assert_match('1 1 TEST_COUNT\s\+\d\+\s\+#define index_to_key', a)
+
+ " Test 19: this should trigger call to cs_print_tags()
+ " Unclear how to check result though, we just exercise the code.
+ set cst cscopequickfix=s0
+ call feedkeys(":cs find s main\<CR>", 't')
+
+ " Test 20: cscope kill
+ call assert_fails('cscope kill 2', 'E261:')
+ call assert_fails('cscope kill xxx', 'E261:')
+
+ let a=execute('cscope kill 0')
+ call assert_match('cscope connection 0 closed', a)
+
+ cscope add Xcscope.out
+ let a=execute('cscope kill Xcscope.out')
+ call assert_match('cscope connection Xcscope.out closed', a)
+
+ cscope add Xcscope.out .
+ let a=execute('cscope kill -1')
+ call assert_match('cscope connection .*Xcscope.out closed', a)
+ let a=execute('cscope kill -1')
+ call assert_equal('', a)
+
+ " Test 21: 'csprg' option
+ call assert_equal('cscope', &csprg)
+ set csprg=doesnotexist
+ call assert_fails('cscope add Xcscope2.out', 'E609:')
+ set csprg=cscope
+
+ " Test 22: multiple cscope connections
+ cscope add Xcscope.out
+ cscope add Xcscope2.out . -C
+ let a=execute('cscope show')
+ call assert_match('\n 0 \d\+.*Xcscope.out\s*<none>', a)
+ call assert_match('\n 1 \d\+.*Xcscope2.out\s*\.', a)
+
+ " Test 23: test Ex command line completion
+ call feedkeys(":cs \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"cs add find help kill reset show', @:)
+
+ call feedkeys(":scs \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"scs find', @:)
+
+ call feedkeys(":cs find \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"cs find a c d e f g i s t', @:)
+
+ call feedkeys(":cs kill \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"cs kill -1 0 1', @:)
+
+ call feedkeys(":cs add Xcscope\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"cs add Xcscope.out Xcscope2.out', @:)
+
+ " Test 24: cscope_connection()
+ call assert_equal(cscope_connection(), 1)
+ call assert_equal(cscope_connection(0, 'out'), 1)
+ call assert_equal(cscope_connection(0, 'xxx'), 1)
+ call assert_equal(cscope_connection(1, 'out'), 1)
+ call assert_equal(cscope_connection(1, 'xxx'), 0)
+ call assert_equal(cscope_connection(2, 'out'), 0)
+ call assert_equal(cscope_connection(3, 'xxx', '..'), 0)
+ call assert_equal(cscope_connection(3, 'out', 'xxx'), 0)
+ call assert_equal(cscope_connection(3, 'out', '.'), 1)
+ call assert_equal(cscope_connection(4, 'out', '.'), 0)
+
+ " CleanUp
+ call CscopeSetupOrClean(0)
+
+endfunc
+
func Test_cscopequickfix()
set cscopequickfix=s-,g-,d+,c-,t+,e-,f0,i-,a-
call assert_equal('s-,g-,d+,c-,t+,e-,f0,i-,a-', &cscopequickfix)
@@ -13,3 +266,14 @@ func Test_cscopequickfix()
call assert_fails('set cscopequickfix=s7', 'E474:')
call assert_fails('set cscopequickfix=s-a', 'E474:')
endfunc
+
+func Test_withoutCscopeConnection()
+ call assert_equal(cscope_connection(), 0)
+
+ call assert_fails('cscope find s main', 'E567:')
+ let a=execute('cscope show')
+ call assert_match('no cscope connections', a)
+endfunc
+
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_digraph.vim b/src/nvim/testdir/test_digraph.vim
new file mode 100644
index 0000000000..95500853f2
--- /dev/null
+++ b/src/nvim/testdir/test_digraph.vim
@@ -0,0 +1,461 @@
+" Tests for digraphs
+
+if !has("digraphs") || !has("multi_byte")
+ finish
+endif
+
+func! Put_Dig(chars)
+ exe "norm! o\<c-k>".a:chars
+endfu
+
+func! Put_Dig_BS(char1, char2)
+ exe "norm! o".a:char1."\<bs>".a:char2
+endfu
+
+func! Test_digraphs()
+ new
+ call Put_Dig("00")
+ call assert_equal("∞", getline('.'))
+ " not a digraph
+ call Put_Dig("el")
+ call assert_equal("l", getline('.'))
+ call Put_Dig("ht")
+ call assert_equal("þ", getline('.'))
+ " digraph "ab" is the same as "ba"
+ call Put_Dig("ab")
+ call Put_Dig("ba")
+ call assert_equal(["ば","ば"], getline(line('.')-1,line('.')))
+ " Euro sign
+ call Put_Dig("e=")
+ call Put_Dig("=e")
+ call Put_Dig("Eu")
+ call Put_Dig("uE")
+ call assert_equal(['е']+repeat(["€"],3), getline(line('.')-3,line('.')))
+ " Rouble sign
+ call Put_Dig("R=")
+ call Put_Dig("=R")
+ call Put_Dig("=P")
+ call Put_Dig("P=")
+ call assert_equal(['Р']+repeat(["₽"],2)+['П'], getline(line('.')-3,line('.')))
+ " Not a digraph
+ call Put_Dig("a\<bs>")
+ call Put_Dig("\<bs>a")
+ call assert_equal(["<BS>", "<BS>a"], getline(line('.')-1,line('.')))
+ " Grave
+ call Put_Dig("a!")
+ call Put_Dig("!e")
+ call Put_Dig("b!") " not defined
+ call assert_equal(["à", "è", "!"], getline(line('.')-2,line('.')))
+ " Acute accent
+ call Put_Dig("a'")
+ call Put_Dig("'e")
+ call Put_Dig("b'") " not defined
+ call assert_equal(["á", "é", "'"], getline(line('.')-2,line('.')))
+ " Cicumflex
+ call Put_Dig("a>")
+ call Put_Dig(">e")
+ call Put_Dig("b>") " not defined
+ call assert_equal(['â', 'ê', '>'], getline(line('.')-2,line('.')))
+ " Tilde
+ call Put_Dig("o~")
+ call Put_Dig("~u") " not defined
+ call Put_Dig("z~") " not defined
+ call assert_equal(['õ', 'u', '~'], getline(line('.')-2,line('.')))
+ " Tilde
+ call Put_Dig("o?")
+ call Put_Dig("?u")
+ call Put_Dig("z?") " not defined
+ call assert_equal(['õ', 'ũ', '?'], getline(line('.')-2,line('.')))
+ " Macron
+ call Put_Dig("o-")
+ call Put_Dig("-u")
+ call Put_Dig("z-") " not defined
+ call assert_equal(['ō', 'ū', '-'], getline(line('.')-2,line('.')))
+ " Breve
+ call Put_Dig("o(")
+ call Put_Dig("(u")
+ call Put_Dig("z(") " not defined
+ call assert_equal(['ŏ', 'ŭ', '('], getline(line('.')-2,line('.')))
+ " Dot above
+ call Put_Dig("b.")
+ call Put_Dig(".e")
+ call Put_Dig("a.") " not defined
+ call assert_equal(['ḃ', 'ė', '.'], getline(line('.')-2,line('.')))
+ " Diaresis
+ call Put_Dig("a:")
+ call Put_Dig(":u")
+ call Put_Dig("b:") " not defined
+ call assert_equal(['ä', 'ü', ':'], getline(line('.')-2,line('.')))
+ " Cedilla
+ call Put_Dig("',")
+ call Put_Dig(",C")
+ call Put_Dig("b,") " not defined
+ call assert_equal(['¸', 'Ç', ','], getline(line('.')-2,line('.')))
+ " Underline
+ call Put_Dig("B_")
+ call Put_Dig("_t")
+ call Put_Dig("a_") " not defined
+ call assert_equal(['Ḇ', 'ṯ', '_'], getline(line('.')-2,line('.')))
+ " Stroke
+ call Put_Dig("j/")
+ call Put_Dig("/l")
+ call Put_Dig("b/") " not defined
+ call assert_equal(['/', 'ł', '/'], getline(line('.')-2,line('.')))
+ " Double acute
+ call Put_Dig('O"')
+ call Put_Dig('"y')
+ call Put_Dig('b"') " not defined
+ call assert_equal(['Ő', 'ÿ', '"'], getline(line('.')-2,line('.')))
+ " Ogonek
+ call Put_Dig('u;')
+ call Put_Dig(';E')
+ call Put_Dig('b;') " not defined
+ call assert_equal(['ų', 'Ę', ';'], getline(line('.')-2,line('.')))
+ " Caron
+ call Put_Dig('u<')
+ call Put_Dig('<E')
+ call Put_Dig('b<') " not defined
+ call assert_equal(['ǔ', 'Ě', '<'], getline(line('.')-2,line('.')))
+ " Ring above
+ call Put_Dig('u0')
+ call Put_Dig('0E') " not defined
+ call Put_Dig('b0') " not defined
+ call assert_equal(['ů', 'E', '0'], getline(line('.')-2,line('.')))
+ " Hook
+ call Put_Dig('u2')
+ call Put_Dig('2E')
+ call Put_Dig('b2') " not defined
+ call assert_equal(['ủ', 'Ẻ', '2'], getline(line('.')-2,line('.')))
+ " Horn
+ call Put_Dig('u9')
+ call Put_Dig('9E') " not defined
+ call Put_Dig('b9') " not defined
+ call assert_equal(['ư', 'E', '9'], getline(line('.')-2,line('.')))
+ " Cyrillic
+ call Put_Dig('u=')
+ call Put_Dig('=b')
+ call Put_Dig('=_')
+ call assert_equal(['у', 'б', '〓'], getline(line('.')-2,line('.')))
+ " Greek
+ call Put_Dig('u*')
+ call Put_Dig('*b')
+ call Put_Dig('*_')
+ call assert_equal(['υ', 'β', '々'], getline(line('.')-2,line('.')))
+ " Greek/Cyrillic special
+ call Put_Dig('u%')
+ call Put_Dig('%b') " not defined
+ call Put_Dig('%_') " not defined
+ call assert_equal(['ύ', 'b', '_'], getline(line('.')-2,line('.')))
+ " Arabic
+ call Put_Dig('u+')
+ call Put_Dig('+b')
+ call Put_Dig('+_') " japanese industrial symbol
+ call assert_equal(['+', 'ب', '〄'], getline(line('.')-2,line('.')))
+ " Hebrew
+ call Put_Dig('Q+')
+ call Put_Dig('+B')
+ call Put_Dig('+X')
+ call assert_equal(['ק', 'ב', 'ח'], getline(line('.')-2,line('.')))
+ " Latin
+ call Put_Dig('a3')
+ call Put_Dig('A3')
+ call Put_Dig('3X')
+ call assert_equal(['ǣ', 'Ǣ', 'X'], getline(line('.')-2,line('.')))
+ " Bopomofo
+ call Put_Dig('a4')
+ call Put_Dig('A4')
+ call Put_Dig('4X')
+ call assert_equal(['ㄚ', '4', 'X'], getline(line('.')-2,line('.')))
+ " Hiragana
+ call Put_Dig('a5')
+ call Put_Dig('A5')
+ call Put_Dig('5X')
+ call assert_equal(['あ', 'ぁ', 'X'], getline(line('.')-2,line('.')))
+ " Katakana
+ call Put_Dig('a6')
+ call Put_Dig('A6')
+ call Put_Dig('6X')
+ call assert_equal(['ァ', 'ア', 'X'], getline(line('.')-2,line('.')))
+ " Superscripts
+ call Put_Dig('1S')
+ call Put_Dig('2S')
+ call Put_Dig('3S')
+ call assert_equal(['¹', '²', '³'], getline(line('.')-2,line('.')))
+ " Subscripts
+ call Put_Dig('1s')
+ call Put_Dig('2s')
+ call Put_Dig('3s')
+ call assert_equal(['₁', '₂', '₃'], getline(line('.')-2,line('.')))
+ " Eszet (only lowercase)
+ call Put_Dig("ss")
+ call Put_Dig("SS") " start of string
+ call assert_equal(["ß", "˜"], getline(line('.')-1,line('.')))
+ " High bit set
+ call Put_Dig("a ")
+ call Put_Dig(" A")
+ call assert_equal(['á', 'Á'], getline(line('.')-1,line('.')))
+ " Escape is not part of a digraph
+ call Put_Dig("a\<esc>")
+ call Put_Dig("\<esc>A")
+ call assert_equal(['', 'A'], getline(line('.')-1,line('.')))
+ " define some custom digraphs
+ " old: 00 ∞
+ " old: el l
+ digraph 00 9216
+ digraph el 0252
+ call Put_Dig("00")
+ call Put_Dig("el")
+ " Reset digraphs
+ digraph 00 8734
+ digraph el 108
+ call Put_Dig("00")
+ call Put_Dig("el")
+ call assert_equal(['␀', 'ü', '∞', 'l'], getline(line('.')-3,line('.')))
+ bw!
+endfunc
+
+func! Test_digraphs_option()
+ " reset whichwrap option, so that testing <esc><bs>A works,
+ " without moving up a line
+ set digraph ww=
+ new
+ call Put_Dig_BS("0","0")
+ call assert_equal("∞", getline('.'))
+ " not a digraph
+ call Put_Dig_BS("e","l")
+ call assert_equal("l", getline('.'))
+ call Put_Dig_BS("h","t")
+ call assert_equal("þ", getline('.'))
+ " digraph "ab" is the same as "ba"
+ call Put_Dig_BS("a","b")
+ call Put_Dig_BS("b","a")
+ call assert_equal(["ば","ば"], getline(line('.')-1,line('.')))
+ " Euro sign
+ call Put_Dig_BS("e","=")
+ call Put_Dig_BS("=","e")
+ call Put_Dig_BS("E","u")
+ call Put_Dig_BS("u","E")
+ call assert_equal(['е']+repeat(["€"],3), getline(line('.')-3,line('.')))
+ " Rouble sign
+ call Put_Dig_BS("R","=")
+ call Put_Dig_BS("=","R")
+ call Put_Dig_BS("=","P")
+ call Put_Dig_BS("P","=")
+ call assert_equal(['Р']+repeat(["₽"],2)+['П'], getline(line('.')-3,line('.')))
+ " Not a digraph: this is different from <c-k>!
+ call Put_Dig_BS("a","\<bs>")
+ call Put_Dig_BS("\<bs>","a")
+ call assert_equal(['','a'], getline(line('.')-1,line('.')))
+ " Grave
+ call Put_Dig_BS("a","!")
+ call Put_Dig_BS("!","e")
+ call Put_Dig_BS("b","!") " not defined
+ call assert_equal(["à", "è", "!"], getline(line('.')-2,line('.')))
+ " Acute accent
+ call Put_Dig_BS("a","'")
+ call Put_Dig_BS("'","e")
+ call Put_Dig_BS("b","'") " not defined
+ call assert_equal(["á", "é", "'"], getline(line('.')-2,line('.')))
+ " Cicumflex
+ call Put_Dig_BS("a",">")
+ call Put_Dig_BS(">","e")
+ call Put_Dig_BS("b",">") " not defined
+ call assert_equal(['â', 'ê', '>'], getline(line('.')-2,line('.')))
+ " Tilde
+ call Put_Dig_BS("o","~")
+ call Put_Dig_BS("~","u") " not defined
+ call Put_Dig_BS("z","~") " not defined
+ call assert_equal(['õ', 'u', '~'], getline(line('.')-2,line('.')))
+ " Tilde
+ call Put_Dig_BS("o","?")
+ call Put_Dig_BS("?","u")
+ call Put_Dig_BS("z","?") " not defined
+ call assert_equal(['õ', 'ũ', '?'], getline(line('.')-2,line('.')))
+ " Macron
+ call Put_Dig_BS("o","-")
+ call Put_Dig_BS("-","u")
+ call Put_Dig_BS("z","-") " not defined
+ call assert_equal(['ō', 'ū', '-'], getline(line('.')-2,line('.')))
+ " Breve
+ call Put_Dig_BS("o","(")
+ call Put_Dig_BS("(","u")
+ call Put_Dig_BS("z","(") " not defined
+ call assert_equal(['ŏ', 'ŭ', '('], getline(line('.')-2,line('.')))
+ " Dot above
+ call Put_Dig_BS("b",".")
+ call Put_Dig_BS(".","e")
+ call Put_Dig_BS("a",".") " not defined
+ call assert_equal(['ḃ', 'ė', '.'], getline(line('.')-2,line('.')))
+ " Diaresis
+ call Put_Dig_BS("a",":")
+ call Put_Dig_BS(":","u")
+ call Put_Dig_BS("b",":") " not defined
+ call assert_equal(['ä', 'ü', ':'], getline(line('.')-2,line('.')))
+ " Cedilla
+ call Put_Dig_BS("'",",")
+ call Put_Dig_BS(",","C")
+ call Put_Dig_BS("b",",") " not defined
+ call assert_equal(['¸', 'Ç', ','], getline(line('.')-2,line('.')))
+ " Underline
+ call Put_Dig_BS("B","_")
+ call Put_Dig_BS("_","t")
+ call Put_Dig_BS("a","_") " not defined
+ call assert_equal(['Ḇ', 'ṯ', '_'], getline(line('.')-2,line('.')))
+ " Stroke
+ call Put_Dig_BS("j","/")
+ call Put_Dig_BS("/","l")
+ call Put_Dig_BS("b","/") " not defined
+ call assert_equal(['/', 'ł', '/'], getline(line('.')-2,line('.')))
+ " Double acute
+ call Put_Dig_BS('O','"')
+ call Put_Dig_BS('"','y')
+ call Put_Dig_BS('b','"') " not defined
+ call assert_equal(['Ő', 'ÿ', '"'], getline(line('.')-2,line('.')))
+ " Ogonek
+ call Put_Dig_BS('u',';')
+ call Put_Dig_BS(';','E')
+ call Put_Dig_BS('b',';') " not defined
+ call assert_equal(['ų', 'Ę', ';'], getline(line('.')-2,line('.')))
+ " Caron
+ call Put_Dig_BS('u','<')
+ call Put_Dig_BS('<','E')
+ call Put_Dig_BS('b','<') " not defined
+ call assert_equal(['ǔ', 'Ě', '<'], getline(line('.')-2,line('.')))
+ " Ring above
+ call Put_Dig_BS('u','0')
+ call Put_Dig_BS('0','E') " not defined
+ call Put_Dig_BS('b','0') " not defined
+ call assert_equal(['ů', 'E', '0'], getline(line('.')-2,line('.')))
+ " Hook
+ call Put_Dig_BS('u','2')
+ call Put_Dig_BS('2','E')
+ call Put_Dig_BS('b','2') " not defined
+ call assert_equal(['ủ', 'Ẻ', '2'], getline(line('.')-2,line('.')))
+ " Horn
+ call Put_Dig_BS('u','9')
+ call Put_Dig_BS('9','E') " not defined
+ call Put_Dig_BS('b','9') " not defined
+ call assert_equal(['ư', 'E', '9'], getline(line('.')-2,line('.')))
+ " Cyrillic
+ call Put_Dig_BS('u','=')
+ call Put_Dig_BS('=','b')
+ call Put_Dig_BS('=','_')
+ call assert_equal(['у', 'б', '〓'], getline(line('.')-2,line('.')))
+ " Greek
+ call Put_Dig_BS('u','*')
+ call Put_Dig_BS('*','b')
+ call Put_Dig_BS('*','_')
+ call assert_equal(['υ', 'β', '々'], getline(line('.')-2,line('.')))
+ " Greek/Cyrillic special
+ call Put_Dig_BS('u','%')
+ call Put_Dig_BS('%','b') " not defined
+ call Put_Dig_BS('%','_') " not defined
+ call assert_equal(['ύ', 'b', '_'], getline(line('.')-2,line('.')))
+ " Arabic
+ call Put_Dig_BS('u','+')
+ call Put_Dig_BS('+','b')
+ call Put_Dig_BS('+','_') " japanese industrial symbol
+ call assert_equal(['+', 'ب', '〄'], getline(line('.')-2,line('.')))
+ " Hebrew
+ call Put_Dig_BS('Q','+')
+ call Put_Dig_BS('+','B')
+ call Put_Dig_BS('+','X')
+ call assert_equal(['ק', 'ב', 'ח'], getline(line('.')-2,line('.')))
+ " Latin
+ call Put_Dig_BS('a','3')
+ call Put_Dig_BS('A','3')
+ call Put_Dig_BS('3','X')
+ call assert_equal(['ǣ', 'Ǣ', 'X'], getline(line('.')-2,line('.')))
+ " Bopomofo
+ call Put_Dig_BS('a','4')
+ call Put_Dig_BS('A','4')
+ call Put_Dig_BS('4','X')
+ call assert_equal(['ㄚ', '4', 'X'], getline(line('.')-2,line('.')))
+ " Hiragana
+ call Put_Dig_BS('a','5')
+ call Put_Dig_BS('A','5')
+ call Put_Dig_BS('5','X')
+ call assert_equal(['あ', 'ぁ', 'X'], getline(line('.')-2,line('.')))
+ " Katakana
+ call Put_Dig_BS('a','6')
+ call Put_Dig_BS('A','6')
+ call Put_Dig_BS('6','X')
+ call assert_equal(['ァ', 'ア', 'X'], getline(line('.')-2,line('.')))
+ " Superscripts
+ call Put_Dig_BS('1','S')
+ call Put_Dig_BS('2','S')
+ call Put_Dig_BS('3','S')
+ call assert_equal(['¹', '²', '³'], getline(line('.')-2,line('.')))
+ " Subscripts
+ call Put_Dig_BS('1','s')
+ call Put_Dig_BS('2','s')
+ call Put_Dig_BS('3','s')
+ call assert_equal(['₁', '₂', '₃'], getline(line('.')-2,line('.')))
+ " Eszet (only lowercase)
+ call Put_Dig_BS("s","s")
+ call Put_Dig_BS("S","S") " start of string
+ call assert_equal(["ß", "˜"], getline(line('.')-1,line('.')))
+ " High bit set (different from <c-k>)
+ call Put_Dig_BS("a"," ")
+ call Put_Dig_BS(" ","A")
+ call assert_equal([' ', 'A'], getline(line('.')-1,line('.')))
+ " Escape is not part of a digraph (different from <c-k>)
+ call Put_Dig_BS("a","\<esc>")
+ call Put_Dig_BS("\<esc>","A")
+ call assert_equal(['', ''], getline(line('.')-1,line('.')))
+ " define some custom digraphs
+ " old: 00 ∞
+ " old: el l
+ digraph 00 9216
+ digraph el 0252
+ call Put_Dig_BS("0","0")
+ call Put_Dig_BS("e","l")
+ " Reset digraphs
+ digraph 00 8734
+ digraph el 108
+ call Put_Dig_BS("0","0")
+ call Put_Dig_BS("e","l")
+ call assert_equal(['␀', 'ü', '∞', 'l'], getline(line('.')-3,line('.')))
+ set nodigraph ww&vim
+ bw!
+endfunc
+
+func! Test_digraphs_output()
+ new
+ let out = execute(':digraph')
+ call assert_equal('Eu € 8364', matchstr(out, '\C\<Eu\D*8364\>'))
+ call assert_equal('=e € 8364', matchstr(out, '\C=e\D*8364\>'))
+ call assert_equal('=R ₽ 8381', matchstr(out, '\C=R\D*8381\>'))
+ call assert_equal('=P ₽ 8381', matchstr(out, '\C=P\D*8381\>'))
+ call assert_equal('o: ö 246', matchstr(out, '\C\<o:\D*246\>'))
+ call assert_equal('v4 ㄪ 12586', matchstr(out, '\C\<v4\D*12586\>'))
+ call assert_equal("'0 ˚ 730", matchstr(out, '\C''0\D*730\>'))
+ call assert_equal('Z% Ж 1046', matchstr(out, '\C\<Z%\D*1046\>'))
+ call assert_equal('u- ū 363', matchstr(out, '\C\<u-\D*363\>'))
+ call assert_equal('SH ^A 1', matchstr(out, '\C\<SH\D*1\>'))
+ bw!
+endfunc
+
+func! Test_loadkeymap()
+ if !has('keymap')
+ return
+ endif
+ new
+ set keymap=czech
+ set iminsert=0
+ call feedkeys("o|\<c-^>|01234567890|\<esc>", 'tx')
+ call assert_equal("|'é+ěščřžýáíé'", getline('.'))
+ " reset keymap and encoding option
+ set keymap=
+ bw!
+endfunc
+
+func! Test_digraph_cmndline()
+ " Create digraph on commandline
+ " This is a hack, to let Vim create the digraph in commandline mode
+ let s = ''
+ exe "sil! norm! :let s.='\<c-k>Eu'\<cr>"
+ call assert_equal("€", s)
+endfunc
+
+" vim: tabstop=2 shiftwidth=0 sts=-1 expandtab
diff --git a/src/nvim/version.c b/src/nvim/version.c
index ee2288e1b0..763447295b 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -145,7 +145,7 @@ static int included_patches[] = {
// 2298 NA
// 2297 NA
// 2296,
- // 2295,
+ 2295,
2294,
// 2293,
// 2292,
@@ -265,7 +265,7 @@ static int included_patches[] = {
// 2178,
// 2177,
// 2176 NA
- // 2175,
+ 2175,
2174,
// 2173,
// 2172,
@@ -281,7 +281,7 @@ static int included_patches[] = {
2162,
// 2161,
2160,
- // 2159,
+ 2159,
2158,
// 2157 NA
// 2156 NA
@@ -292,7 +292,7 @@ static int included_patches[] = {
// 2151,
// 2150 NA
2149,
- // 2148,
+ 2148,
2147,
2146,
// 2145 NA
@@ -333,8 +333,8 @@ static int included_patches[] = {
2110,
2109,
// 2108 NA
- // 2107,
- // 2106,
+ 2107,
+ 2106,
// 2105 NA
// 2104,
2103,
@@ -352,13 +352,13 @@ static int included_patches[] = {
// 2091 NA
// 2090,
// 2089 NA
- // 2088,
- // 2087,
+ 2088,
+ 2087,
2086,
- // 2085,
- // 2084,
+ 2085,
+ 2084,
// 2083,
- // 2082,
+ 2082,
2081,
// 2080,
// 2079 NA