summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2021-03-29 20:49:05 +0200
committerBram Moolenaar <Bram@vim.org>2021-03-29 20:49:05 +0200
commit8b9abfd86c736ed3f298dfa8b50a962c118b3983 (patch)
tree65874e39326cd7bfa6f8a73861bb00d01d5e4d76
parent9dbe701fe19597ad59c0e0c70a05927b587bea9f (diff)
patch 8.2.2675: directory change in a terminal window shell is not followedv8.2.2675
Problem: Directory change in a terminal window shell is not followed. Solution: Add the 'autoshelldir' option. (closes #6290)
-rw-r--r--runtime/doc/options.txt9
-rw-r--r--runtime/doc/quickref.txt1
-rw-r--r--runtime/optwin.vim2
-rw-r--r--src/charset.c3
-rw-r--r--src/feature.h6
-rw-r--r--src/option.h3
-rw-r--r--src/optiondefs.h9
-rw-r--r--src/terminal.c75
-rw-r--r--src/testdir/check.vim8
-rw-r--r--src/testdir/test_terminal3.vim29
-rw-r--r--src/version.c2
11 files changed, 145 insertions, 2 deletions
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index 7fcdfbe953..babe7217d0 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -749,6 +749,15 @@ A jump table for the options with a short description can be found at |Q_op|.
or selected.
Note: When this option is on some plugins may not work.
+ *'autoshelldir'* *'asd'* *'noautoshelldir'* *'noasd'*
+'autoshelldir' 'asd' boolean (default off)
+ global
+ When on, Vim will change the current working directory whenever you
+ change the directory of the shell running in a terminal window. You
+ need proper setting-up, so whenever the shell's pwd changes an OSC 7
+ escape sequence will be emitted. For example, on Linux, you can source
+ /etc/profile.d/vte.sh in your shell profile if you use bash or zsh.
+
*'arabic'* *'arab'* *'noarabic'* *'noarab'*
'arabic' 'arab' boolean (default off)
local to window
diff --git a/runtime/doc/quickref.txt b/runtime/doc/quickref.txt
index c0a070d248..ead42f9968 100644
--- a/runtime/doc/quickref.txt
+++ b/runtime/doc/quickref.txt
@@ -605,6 +605,7 @@ Short explanation of each option: *option-list*
'ambiwidth' 'ambw' what to do with Unicode chars of ambiguous width
'antialias' 'anti' Mac OS X: use smooth, antialiased fonts
'autochdir' 'acd' change directory to the file in the current window
+'autoshelldir' 'asd' change directory to the shell's current directory
'arabic' 'arab' for Arabic as a default second language
'arabicshape' 'arshape' do shaping for Arabic characters
'autoindent' 'ai' take indent for new line from previous line
diff --git a/runtime/optwin.vim b/runtime/optwin.vim
index 45aa8f9307..176f9eafc8 100644
--- a/runtime/optwin.vim
+++ b/runtime/optwin.vim
@@ -266,6 +266,8 @@ if exists("+autochdir")
call <SID>AddOption("autochdir", gettext("change to directory of file in buffer"))
call <SID>BinOptionG("acd", &acd)
endif
+call <SID>AddOption("autoshelldir", gettext("change to pwd of shell in terminal buffer"))
+call <SID>BinOptionG("asd", &asd)
call <SID>AddOption("wrapscan", gettext("search commands wrap around the end of the buffer"))
call <SID>BinOptionG("ws", &ws)
call <SID>AddOption("incsearch", gettext("show match for partly typed search command"))
diff --git a/src/charset.c b/src/charset.c
index d06a273643..db0c146f88 100644
--- a/src/charset.c
+++ b/src/charset.c
@@ -2005,7 +2005,8 @@ hex2nr(int c)
return c - '0';
}
-#if defined(FEAT_TERMRESPONSE) || defined(FEAT_GUI_GTK) || defined(PROTO)
+#if defined(FEAT_TERMRESPONSE) || defined(FEAT_GUI_GTK) \
+ || defined(PROTO) || defined(FEAT_AUTOSHELLDIR)
/*
* Convert two hex characters to a byte.
* Return -1 if one of the characters is not hex.
diff --git a/src/feature.h b/src/feature.h
index 5f6f800c22..4df73d1cb4 100644
--- a/src/feature.h
+++ b/src/feature.h
@@ -1148,6 +1148,12 @@
#endif
/*
+ * +autoshelldir 'autoshelldir' option.
+ */
+#if defined(FEAT_TERMINAL)
+# define FEAT_AUTOSHELLDIR
+#endif
+/*
* +textprop and +popupwin Text PROPerties and POPUP windows
*/
#if defined(FEAT_EVAL) && defined(FEAT_SYN_HL)
diff --git a/src/option.h b/src/option.h
index 349268c3d4..0b1183fecf 100644
--- a/src/option.h
+++ b/src/option.h
@@ -383,6 +383,9 @@ EXTERN char_u *p_ambw; // 'ambiwidth'
#ifdef FEAT_AUTOCHDIR
EXTERN int p_acd; // 'autochdir'
#endif
+#ifdef FEAT_AUTOSHELLDIR
+EXTERN int p_asd; // 'autoshelldir'
+#endif
EXTERN int p_ai; // 'autoindent'
EXTERN int p_bin; // 'binary'
EXTERN int p_bomb; // 'bomb'
diff --git a/src/optiondefs.h b/src/optiondefs.h
index dcd195d7ef..42f355c287 100644
--- a/src/optiondefs.h
+++ b/src/optiondefs.h
@@ -372,6 +372,15 @@ static struct vimoption options[] =
{(char_u *)0L, (char_u *)0L}
#endif
SCTX_INIT},
+ {"autoshelldir", "asd", P_BOOL|P_VI_DEF,
+#ifdef FEAT_AUTOSHELLDIR
+ (char_u *)&p_asd, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCTX_INIT},
{"autoindent", "ai", P_BOOL|P_VI_DEF,
(char_u *)&p_ai, PV_AI,
{(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
diff --git a/src/terminal.c b/src/terminal.c
index 4c43ea7482..6f07055ebc 100644
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -4293,6 +4293,73 @@ handle_call_command(term_T *term, channel_T *channel, listitem_T *item)
}
/*
+ * URL decoding (also know as Percent-encoding).
+ *
+ * Note this function currently is only used for decoding shell's
+ * OSC 7 escape sequence which we can assume all bytes are valid
+ * UTF-8 bytes. Thus we don't need to deal with invalid UTF-8
+ * encoding bytes like 0xfe, 0xff.
+ */
+ static size_t
+url_decode(const char *src, const size_t len, char_u *dst)
+{
+ size_t i = 0, j = 0;
+
+ while (i < len)
+ {
+ if (src[i] == '%' && i + 2 < len)
+ {
+ dst[j] = hexhex2nr((char_u *)&src[i + 1]);
+ j++;
+ i += 3;
+ }
+ else
+ {
+ dst[j] = src[i];
+ i++;
+ j++;
+ }
+ }
+ dst[j] = '\0';
+ return j;
+}
+
+/*
+ * Sync terminal buffer's cwd with shell's pwd with the help of OSC 7.
+ *
+ * The OSC 7 sequence has the format of
+ * "\033]7;file://HOSTNAME/CURRENT/DIR\033\\"
+ * and what VTerm provides via VTermStringFragment is
+ * "file://HOSTNAME/CURRENT/DIR"
+ */
+ static void
+sync_shell_dir(VTermStringFragment *frag)
+{
+ int offset = 7; // len of "file://" is 7
+ char *pos = (char *)frag->str + offset;
+ char_u *new_dir;
+
+ // remove HOSTNAME to get PWD
+ while (*pos != '/' && offset < frag->len)
+ {
+ offset += 1;
+ pos += 1;
+ }
+
+ if (offset >= frag->len)
+ {
+ semsg(_(e_failed_to_extract_pwd_from_str_check_your_shell_config),
+ frag->str);
+ return;
+ }
+
+ new_dir = alloc(frag->len - offset + 1);
+ url_decode(pos, frag->len-offset, new_dir);
+ changedir_func(new_dir, TRUE, CDSCOPE_WINDOW);
+ vim_free(new_dir);
+}
+
+/*
* Called by libvterm when it cannot recognize an OSC sequence.
* We recognize a terminal API command.
*/
@@ -4306,7 +4373,13 @@ parse_osc(int command, VTermStringFragment frag, void *user)
: term->tl_job->jv_channel;
garray_T *gap = &term->tl_osc_buf;
- // We recognize only OSC 5 1 ; {command}
+ // We recognize only OSC 5 1 ; {command} and OSC 7 ; {command}
+ if (p_asd && command == 7)
+ {
+ sync_shell_dir(&frag);
+ return 1;
+ }
+
if (command != 51)
return 0;
diff --git a/src/testdir/check.vim b/src/testdir/check.vim
index 6190399e5d..4c5f3eef5d 100644
--- a/src/testdir/check.vim
+++ b/src/testdir/check.vim
@@ -92,6 +92,14 @@ func CheckLinux()
endif
endfunc
+" Command to check for not running on a BSD system.
+command CheckNotBSD call CheckNotBSD()
+func CheckNotBSD()
+ if has('bsd')
+ throw 'Skipped: does not work on BSD'
+ endif
+endfunc
+
" Command to check that making screendumps is supported.
" Caller must source screendump.vim
command CheckScreendump call CheckScreendump()
diff --git a/src/testdir/test_terminal3.vim b/src/testdir/test_terminal3.vim
index 037d935582..ab926b686a 100644
--- a/src/testdir/test_terminal3.vim
+++ b/src/testdir/test_terminal3.vim
@@ -475,6 +475,35 @@ func Test_term_mouse()
call delete('Xbuf')
endfunc
+" Test for sync buffer cwd with shell's pwd
+func Test_terminal_sync_shell_dir()
+ CheckUnix
+ " The test always use sh (see src/testdir/unix.vim).
+ " However, BSD's sh doesn't seem to play well with OSC 7 escape sequence.
+ CheckNotBSD
+
+ set asd
+ " , is
+ " 1. a valid character for directory names
+ " 2. a reserved character in url-encoding
+ let chars = ",a"
+ " "," is url-encoded as '%2C'
+ let chars_url = "%2Ca"
+ let tmpfolder = fnamemodify(tempname(),':h').'/'.chars
+ let tmpfolder_url = fnamemodify(tempname(),':h').'/'.chars_url
+ call mkdir(tmpfolder, "p")
+ let buf = Run_shell_in_terminal({})
+ call term_sendkeys(buf, "echo -ne $'\\e\]7;file://".tmpfolder_url."\\a'\<CR>")
+ "call term_sendkeys(buf, "cd ".tmpfolder."\<CR>")
+ call TermWait(buf)
+ if has("mac")
+ let expected = "/private".tmpfolder
+ else
+ let expected = tmpfolder
+ endif
+ call assert_equal(expected, getcwd(winnr()))
+endfunc
+
" Test for modeless selection in a terminal
func Test_term_modeless_selection()
CheckUnix
diff --git a/src/version.c b/src/version.c
index da20571e26..bc47c43909 100644
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 2675,
+/**/
2674,
/**/
2673,