diff options
author | Bram Moolenaar <Bram@vim.org> | 2021-03-29 20:49:05 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2021-03-29 20:49:05 +0200 |
commit | 8b9abfd86c736ed3f298dfa8b50a962c118b3983 (patch) | |
tree | 65874e39326cd7bfa6f8a73861bb00d01d5e4d76 /src | |
parent | 9dbe701fe19597ad59c0e0c70a05927b587bea9f (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)
Diffstat (limited to 'src')
-rw-r--r-- | src/charset.c | 3 | ||||
-rw-r--r-- | src/feature.h | 6 | ||||
-rw-r--r-- | src/option.h | 3 | ||||
-rw-r--r-- | src/optiondefs.h | 9 | ||||
-rw-r--r-- | src/terminal.c | 75 | ||||
-rw-r--r-- | src/testdir/check.vim | 8 | ||||
-rw-r--r-- | src/testdir/test_terminal3.vim | 29 | ||||
-rw-r--r-- | src/version.c | 2 |
8 files changed, 133 insertions, 2 deletions
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, |