1
0
forked from aniani/vim

patch 8.2.2675: directory change in a terminal window shell is not followed

Problem:    Directory change in a terminal window shell is not followed.
Solution:   Add the 'autoshelldir' option. (closes #6290)
This commit is contained in:
Bram Moolenaar
2021-03-29 20:49:05 +02:00
parent 9dbe701fe1
commit 8b9abfd86c
11 changed files with 145 additions and 2 deletions

View File

@@ -749,6 +749,15 @@ A jump table for the options with a short description can be found at |Q_op|.
or selected. or selected.
Note: When this option is on some plugins may not work. 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'* *'noarabic'* *'noarab'*
'arabic' 'arab' boolean (default off) 'arabic' 'arab' boolean (default off)
local to window local to window

View File

@@ -605,6 +605,7 @@ Short explanation of each option: *option-list*
'ambiwidth' 'ambw' what to do with Unicode chars of ambiguous width 'ambiwidth' 'ambw' what to do with Unicode chars of ambiguous width
'antialias' 'anti' Mac OS X: use smooth, antialiased fonts 'antialias' 'anti' Mac OS X: use smooth, antialiased fonts
'autochdir' 'acd' change directory to the file in the current window '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 'arabic' 'arab' for Arabic as a default second language
'arabicshape' 'arshape' do shaping for Arabic characters 'arabicshape' 'arshape' do shaping for Arabic characters
'autoindent' 'ai' take indent for new line from previous line 'autoindent' 'ai' take indent for new line from previous line

View File

@@ -266,6 +266,8 @@ if exists("+autochdir")
call <SID>AddOption("autochdir", gettext("change to directory of file in buffer")) call <SID>AddOption("autochdir", gettext("change to directory of file in buffer"))
call <SID>BinOptionG("acd", &acd) call <SID>BinOptionG("acd", &acd)
endif 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>AddOption("wrapscan", gettext("search commands wrap around the end of the buffer"))
call <SID>BinOptionG("ws", &ws) call <SID>BinOptionG("ws", &ws)
call <SID>AddOption("incsearch", gettext("show match for partly typed search command")) call <SID>AddOption("incsearch", gettext("show match for partly typed search command"))

View File

@@ -2005,7 +2005,8 @@ hex2nr(int c)
return c - '0'; 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. * Convert two hex characters to a byte.
* Return -1 if one of the characters is not hex. * Return -1 if one of the characters is not hex.

View File

@@ -1147,6 +1147,12 @@
# define FEAT_SYN_HL # define FEAT_SYN_HL
#endif #endif
/*
* +autoshelldir 'autoshelldir' option.
*/
#if defined(FEAT_TERMINAL)
# define FEAT_AUTOSHELLDIR
#endif
/* /*
* +textprop and +popupwin Text PROPerties and POPUP windows * +textprop and +popupwin Text PROPerties and POPUP windows
*/ */

View File

@@ -383,6 +383,9 @@ EXTERN char_u *p_ambw; // 'ambiwidth'
#ifdef FEAT_AUTOCHDIR #ifdef FEAT_AUTOCHDIR
EXTERN int p_acd; // 'autochdir' EXTERN int p_acd; // 'autochdir'
#endif #endif
#ifdef FEAT_AUTOSHELLDIR
EXTERN int p_asd; // 'autoshelldir'
#endif
EXTERN int p_ai; // 'autoindent' EXTERN int p_ai; // 'autoindent'
EXTERN int p_bin; // 'binary' EXTERN int p_bin; // 'binary'
EXTERN int p_bomb; // 'bomb' EXTERN int p_bomb; // 'bomb'

View File

@@ -370,6 +370,15 @@ static struct vimoption options[] =
#else #else
(char_u *)NULL, PV_NONE, (char_u *)NULL, PV_NONE,
{(char_u *)0L, (char_u *)0L} {(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 #endif
SCTX_INIT}, SCTX_INIT},
{"autoindent", "ai", P_BOOL|P_VI_DEF, {"autoindent", "ai", P_BOOL|P_VI_DEF,

View File

@@ -4292,6 +4292,73 @@ handle_call_command(term_T *term, channel_T *channel, listitem_T *item)
ch_log(channel, "Calling function %s failed", func); ch_log(channel, "Calling function %s failed", func);
} }
/*
* 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. * Called by libvterm when it cannot recognize an OSC sequence.
* We recognize a terminal API command. * We recognize a terminal API command.
@@ -4306,7 +4373,13 @@ parse_osc(int command, VTermStringFragment frag, void *user)
: term->tl_job->jv_channel; : term->tl_job->jv_channel;
garray_T *gap = &term->tl_osc_buf; 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) if (command != 51)
return 0; return 0;

View File

@@ -92,6 +92,14 @@ func CheckLinux()
endif endif
endfunc 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. " Command to check that making screendumps is supported.
" Caller must source screendump.vim " Caller must source screendump.vim
command CheckScreendump call CheckScreendump() command CheckScreendump call CheckScreendump()

View File

@@ -475,6 +475,35 @@ func Test_term_mouse()
call delete('Xbuf') call delete('Xbuf')
endfunc 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 " Test for modeless selection in a terminal
func Test_term_modeless_selection() func Test_term_modeless_selection()
CheckUnix CheckUnix

View File

@@ -750,6 +750,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
2675,
/**/ /**/
2674, 2674,
/**/ /**/