diff src/terminal.c @ 24268:9257f3980f4a v8.2.2675

patch 8.2.2675: directory change in a terminal window shell is not followed Commit: https://github.com/vim/vim/commit/8b9abfd86c736ed3f298dfa8b50a962c118b3983 Author: Bram Moolenaar <Bram@vim.org> Date: Mon Mar 29 20:49:05 2021 +0200 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 https://github.com/vim/vim/issues/6290)
author Bram Moolenaar <Bram@vim.org>
date Mon, 29 Mar 2021 21:00:03 +0200
parents d9afd9008910
children 7a4cc4d3a40a
line wrap: on
line diff
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -4293,6 +4293,73 @@ handle_call_command(term_T *term, channe
 }
 
 /*
+ * 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, VTermStringFragme
 						    : 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;