From cffdf102d4f01fe5675c389eb80bf55daa62697a Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Mon, 28 Aug 2023 07:22:19 -0500 Subject: [PATCH] feat(terminal): allow :terminal to take modifiers (#15427) The following modifiers are all now supported: :tab term :vertical term :horizontal term :botright term :topleft term Fixes: https://github.com/neovim/neovim/issues/11385 --- runtime/doc/news.txt | 3 +++ runtime/doc/windows.txt | 3 ++- src/nvim/ex_docmd.c | 30 ++++++++++++++++++++++++------ 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index 4f9f362b1e..a233b66d1f 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -158,6 +158,9 @@ The following new APIs and features were added. • Floating windows can now show footer with new `footer` and `footer_pos` config fields. Uses |hl-FloatFooter| by default. +• The |:terminal| command now accepts some |:command-modifiers| (specifically + |:horizontal| and those that affect splitting a window). + ============================================================================== CHANGED FEATURES *news-changed* diff --git a/runtime/doc/windows.txt b/runtime/doc/windows.txt index b78c1eeae5..842542bdc3 100644 --- a/runtime/doc/windows.txt +++ b/runtime/doc/windows.txt @@ -243,7 +243,8 @@ and 'winminwidth' are relevant. :hor[izontal] {cmd} Execute {cmd}. Currently only makes a difference for `horizontal wincmd =`, which will equalize windows only - horizontally. + horizontally, and |:terminal|, which will open a |terminal| + buffer in a split window. :lefta[bove] {cmd} *:lefta* *:leftabove* :abo[veleft] {cmd} *:abo* *:aboveleft* diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index aba50b2042..3ff1442640 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -7302,12 +7302,31 @@ void set_pressedreturn(bool val) static void ex_terminal(exarg_T *eap) { char ex_cmd[1024]; + size_t len = 0; + + if (cmdmod.cmod_tab > 0 || cmdmod.cmod_split != 0) { + bool multi_mods = false; + + // ex_cmd must be a null terminated string before passing to add_win_cmd_modifiers + ex_cmd[0] = '\0'; + + len = add_win_cmd_modifiers(ex_cmd, &cmdmod, &multi_mods); + assert(len < sizeof(ex_cmd)); + int result = snprintf(ex_cmd + len, sizeof(ex_cmd) - len, " new"); + assert(result > 0); + len += (size_t)result; + } else { + int result = snprintf(ex_cmd, sizeof(ex_cmd), "enew%s", eap->forceit ? "!" : ""); + assert(result > 0); + len += (size_t)result; + } + + assert(len < sizeof(ex_cmd)); if (*eap->arg != NUL) { // Run {cmd} in 'shell'. char *name = vim_strsave_escaped(eap->arg, "\"\\"); - snprintf(ex_cmd, sizeof(ex_cmd), - ":enew%s | call termopen(\"%s\")", - eap->forceit ? "!" : "", name); + snprintf(ex_cmd + len, sizeof(ex_cmd) - len, + " | call termopen(\"%s\")", name); xfree(name); } else { // No {cmd}: run the job with tokenized 'shell'. if (*p_sh == NUL) { @@ -7327,9 +7346,8 @@ static void ex_terminal(exarg_T *eap) } shell_free_argv(argv); - snprintf(ex_cmd, sizeof(ex_cmd), - ":enew%s | call termopen([%s])", - eap->forceit ? "!" : "", shell_argv + 1); + snprintf(ex_cmd + len, sizeof(ex_cmd) - len, + " | call termopen([%s])", shell_argv + 1); } do_cmdline_cmd(ex_cmd);