aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/option.c6
-rw-r--r--src/nvim/strings.c13
-rw-r--r--src/nvim/testdir/test_functions.vim23
-rw-r--r--src/nvim/window.c34
4 files changed, 75 insertions, 1 deletions
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 23b488ea68..fb7a0446b6 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -7644,6 +7644,12 @@ int csh_like_shell(void)
return strstr((char *)path_tail(p_sh), "csh") != NULL;
}
+/// Return true when 'shell' has "fish" in the tail.
+bool fish_like_shell(void)
+{
+ return strstr((char *)path_tail(p_sh), "fish") != NULL;
+}
+
/// Return the number of requested sign columns, based on current
/// buffer signs and on user configuration.
int win_signcol_count(win_T *wp)
diff --git a/src/nvim/strings.c b/src/nvim/strings.c
index 0363afe02d..79a3db4843 100644
--- a/src/nvim/strings.c
+++ b/src/nvim/strings.c
@@ -190,6 +190,7 @@ char_u *vim_strsave_shellescape(const char_u *string,
char_u *escaped_string;
size_t l;
int csh_like;
+ bool fish_like;
/* Only csh and similar shells expand '!' within single quotes. For sh and
* the like we must not put a backslash before it, it will be taken
@@ -197,6 +198,10 @@ char_u *vim_strsave_shellescape(const char_u *string,
* Csh also needs to have "\n" escaped twice when do_special is set. */
csh_like = csh_like_shell();
+ // Fish shell uses '\' as an escape character within single quotes, so '\'
+ // itself must be escaped to get a literal '\'.
+ fish_like = fish_like_shell();
+
/* First count the number of extra bytes required. */
size_t length = STRLEN(string) + 3; // two quotes and a trailing NUL
for (const char_u *p = string; *p != NUL; MB_PTR_ADV(p)) {
@@ -220,6 +225,9 @@ char_u *vim_strsave_shellescape(const char_u *string,
++length; /* insert backslash */
p += l - 1;
}
+ if (*p == '\\' && fish_like) {
+ length++; // insert backslash
+ }
}
/* Allocate memory for the result and fill it. */
@@ -267,6 +275,11 @@ char_u *vim_strsave_shellescape(const char_u *string,
*d++ = *p++;
continue;
}
+ if (*p == '\\' && fish_like) {
+ *d++ = '\\';
+ *d++ = *p++;
+ continue;
+ }
MB_COPY_CHAR(p, d);
}
diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim
index ed46730cbb..e82fefc7fc 100644
--- a/src/nvim/testdir/test_functions.vim
+++ b/src/nvim/testdir/test_functions.vim
@@ -1172,6 +1172,29 @@ func Test_shellescape()
call assert_equal("'te\\\nxt'", shellescape("te\nxt"))
call assert_equal("'te\\\\\nxt'", shellescape("te\nxt", 1))
+ set shell=fish
+ call assert_equal("'text'", shellescape('text'))
+ call assert_equal("'te\"xt'", shellescape('te"xt'))
+ call assert_equal("'te'\\''xt'", shellescape("te'xt"))
+
+ call assert_equal("'te%xt'", shellescape("te%xt"))
+ call assert_equal("'te\\%xt'", shellescape("te%xt", 1))
+ call assert_equal("'te#xt'", shellescape("te#xt"))
+ call assert_equal("'te\\#xt'", shellescape("te#xt", 1))
+ call assert_equal("'te!xt'", shellescape("te!xt"))
+ call assert_equal("'te\\!xt'", shellescape("te!xt", 1))
+
+ call assert_equal("'te\\\\xt'", shellescape("te\\xt"))
+ call assert_equal("'te\\\\xt'", shellescape("te\\xt", 1))
+ call assert_equal("'te\\\\'\\''xt'", shellescape("te\\'xt"))
+ call assert_equal("'te\\\\'\\''xt'", shellescape("te\\'xt", 1))
+ call assert_equal("'te\\\\!xt'", shellescape("te\\!xt"))
+ call assert_equal("'te\\\\\\!xt'", shellescape("te\\!xt", 1))
+ call assert_equal("'te\\\\%xt'", shellescape("te\\%xt"))
+ call assert_equal("'te\\\\\\%xt'", shellescape("te\\%xt", 1))
+ call assert_equal("'te\\\\#xt'", shellescape("te\\#xt"))
+ call assert_equal("'te\\\\\\#xt'", shellescape("te\\#xt", 1))
+
let &shell = save_shell
endfunc
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 42fe2c0f49..55a7882401 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -737,6 +737,37 @@ void win_config_float(win_T *wp, FloatConfig fconfig)
redraw_later(wp, NOT_VALID);
}
+ // compute initial position
+ if (wp->w_float_config.relative == kFloatRelativeWindow) {
+ int row = wp->w_float_config.row;
+ int col = wp->w_float_config.col;
+ Error dummy = ERROR_INIT;
+ win_T *parent = find_window_by_handle(wp->w_float_config.window, &dummy);
+ if (parent) {
+ row += parent->w_winrow;
+ col += parent->w_wincol;
+ ScreenGrid *grid = &parent->w_grid;
+ int row_off = 0, col_off = 0;
+ screen_adjust_grid(&grid, &row_off, &col_off);
+ row += row_off;
+ col += col_off;
+ }
+ api_clear_error(&dummy);
+ if (wp->w_float_config.bufpos.lnum >= 0) {
+ pos_T pos = { wp->w_float_config.bufpos.lnum + 1,
+ wp->w_float_config.bufpos.col, 0 };
+ int trow, tcol, tcolc, tcole;
+ textpos2screenpos(wp, &pos, &trow, &tcol, &tcolc, &tcole, true);
+ row += trow - 1;
+ col += tcol - 1;
+ }
+ wp->w_winrow = row;
+ wp->w_wincol = col;
+ } else {
+ wp->w_winrow = fconfig.row;
+ wp->w_wincol = fconfig.col;
+ }
+
// changing border style while keeping border only requires redrawing border
if (fconfig.border) {
wp->w_redr_border = true;
@@ -770,7 +801,6 @@ int win_fdccol_count(win_T *wp)
}
}
-
void ui_ext_win_position(win_T *wp)
{
if (!wp->w_floating) {
@@ -817,6 +847,8 @@ void ui_ext_win_position(win_T *wp)
int comp_row = (int)row - (south ? wp->w_height : 0);
int comp_col = (int)col - (east ? wp->w_width : 0);
+ comp_row += grid->comp_row;
+ comp_col += grid->comp_col;
comp_row = MAX(MIN(comp_row, Rows-wp->w_height_outer-1), 0);
comp_col = MAX(MIN(comp_col, Columns-wp->w_width_outer), 0);
wp->w_winrow = comp_row;