教程:在 Windows 终端的同一目录中打开选项卡或窗格

通常,无论 startingDirectory 对该配置文件来说内容如何,“新建选项卡”和“拆分窗格”操作总是会打开新的选项卡/窗格。 但是在其他平台上,新选项卡通常会自动使用当前选项卡的工作目录作为新选项卡的起始目录。这样,用户就可在单个目录中快速进行多项操作。

遗憾的是,在 Windows 上,很难确定进程的当前工作目录 (CWD) 是什么。 即使我们能查找它,也并非所有应用程序都在导航时实际设置其 CWD。 特别要注意的是,Windows PowerShell 不会像你围绕文件系统进行 cd 操作一样更改其 CWD! 自动复制 PowerShell 的 CWD 几乎总是错误的。

幸运的是,有一种解决方法。 应用程序可发出一个特殊的转义序列来手动告诉终端 CWD 应该是什么。

在本教程中,你将了解如何执行以下操作:

  • 配置 shell,告诉终端它是当前工作目录
  • 使用 duplicateTab 操作打开具有相同 CWD 的选项卡
  • 使用 splitPane 操作打开具有相同 CWD 的窗格
  • 使用选项卡上下文菜单打开具有相同 CWD 的选项卡或窗格

配置 shell

若要告诉终端什么是 CWD,需要修改 shell,以便在浏览操作系统时发出转义序列。 幸运的是,大多数 shell 都有一种用于配置“提示符”的机制,该机制在每个命令之后运行。 这是添加此类输出的理想位置。

Windows

命令提示:cmd.exe

cmd 使用 %PROMPT% 环境变量来配置提示符。 可通过以下命令在提示符后面轻松追加命令来设置 CWD:

set PROMPT=$e]9;9;$P$e\%PROMPT%

这会将 $e]9;9;$P$e\ 追加到当前提示符下。 当 cmd 计算此提示符时,它会进行以下替换

  • $e 替换为转义字符
  • $p 替换为当前工作目录

请注意,上述命令仅适用于当前 cmd.exe 会话。 若要永久设置值,在运行上述命令后需要运行

setx PROMPT "%PROMPT%"

PowerShell:powershell.exepwsh.exe

如果你之前从未更改过 PowerShell 提示符,则应先查看 about_Prompts

将以下内容添加到 PowerShell 配置文件

function prompt {
  $loc = $executionContext.SessionState.Path.CurrentLocation;

  $out = ""
  if ($loc.Provider.Name -eq "FileSystem") {
    $out += "$([char]27)]9;9;`"$($loc.ProviderPath)`"$([char]27)\"
  }
  $out += "PS $loc$('>' * ($nestedPromptLevel + 1)) ";
  return $out
}

PowerShell 与 posh-git

如果使用的是 posh-git,则这将已经修改你的提示符。 在这种情况下,只需将所需的输出添加到已修改的提示符即可。 以下示例是 ConEmu 文档中的此示例稍作修改后的版本:

function prompt
{
  $loc = Get-Location

  $prompt = & $GitPromptScriptBlock

  $prompt += "$([char]27)]9;12$([char]7)"
  if ($loc.Provider.Name -eq "FileSystem")
  {
    $prompt += "$([char]27)]9;9;`"$($loc.ProviderPath)`"$([char]27)\"
  }

  $prompt
}

PowerShell 与 Starship

如果使用的是 Starship,则这将已经修改你的提示符。 在这种情况下,只需将所需的输出添加到已修改的提示符即可。

function Invoke-Starship-PreCommand {
  $loc = $executionContext.SessionState.Path.CurrentLocation;
  $prompt = "$([char]27)]9;12$([char]7)"
  if ($loc.Provider.Name -eq "FileSystem")
  {
    $prompt += "$([char]27)]9;9;`"$($loc.ProviderPath)`"$([char]27)\"
  }
  $host.ui.Write($prompt)
}

WSL

适用于 Linux 的 Windows 子系统发行版主要使用 BASH 作为命令行 shell。

bash

将以下行添加到 .bash_profile 配置文件的末尾:

PROMPT_COMMAND=${PROMPT_COMMAND:+"$PROMPT_COMMAND; "}'printf "\e]9;9;%s\e\\" "$(wslpath -w "$PWD")"'

bash 中的 PROMPT_COMMAND 变量会告诉 bash 在显示提示符之前要运行哪个命令。 在 printf 语句中,我们将追加序列来使用终端设置工作目录。 $(wslpath -w "$PWD") 位将调用 wslpath 可执行文件,将当前目录转换为其类似 Windows 的路径。 ${PROMPT_COMMAND:+"$PROMPT_COMMAND; "} 位是某种 bash magic,用于确保我们将此命令追加到任何现有命令(如果你已在其他位置设置 PROMPT_COMMAND。)

zsh

将以下行添加到 .zshrc 文件的末尾:

keep_current_path() {
  printf "\e]9;9;%s\e\\" "$(wslpath -w "$PWD")"
}
precmd_functions+=(keep_current_path)

precmd_functions 挂钩会指示 zsh 在显示提示之前要运行哪些命令。 在 printf 语句中,我们将追加序列来使用终端设置工作目录。 $(wslpath -w "$PWD") 位将调用 wslpath 可执行文件,将当前目录转换为其类似 Windows 的路径。 使用 precmd_functions+= 确保我们将 keep_current_path 函数附加到已为此挂钩定义的任何现有函数中。

Fish

如果使用的是 Fish shell,则将以下行添加到位于 ~/.config/fish/config.fish 的配置文件的末尾:

function storePathForWindowsTerminal --on-variable PWD
    if test -n "$WT_SESSION"
      printf "\e]9;9;%s\e\\" (wslpath -w "$PWD")
    end
end

每当更改当前路径以确认当前会话已由 Windows 终端打开(验证 $WT_SESSION)并发送操作系统命令 (OSC 9;9;) 时,都会使用当前路径的 Windows 等效路径 (wslpath -w) 调用此函数。

MINGW

对于 MINGW、Git Bash 和 Cygwin,需要修改 WSL 的 PROMPT_COMMAND:将 wslpath 替换为 cygpath

将以下行添加到 .bashrc 文件的末尾:

PROMPT_COMMAND=${PROMPT_COMMAND:+"$PROMPT_COMMAND; "}'printf "\e]9;9;%s\e\\" "`cygpath -w "$PWD" -C ANSI`"'

注意

没有在这里看到你喜欢的 shell? 如果你已清楚,可随意打开 PR,为你喜欢的 shell 提供一个解决方案!

使用操作复制路径

配置 shell 来告知终端哪一个是当前目录后,就能轻松打开使用此路径的新选项卡或窗格。

使用 duplicateTab 打开新选项卡

若要打开路径(和配置文件)与当前活跃终端相同的新选项卡,请使用“复制选项卡”操作。 默认情况下,快捷方式为 Ctrl+Shift+D,如下所示:

        { "command": "duplicateTab", "keys": "ctrl+shift+d" },

有关更多详细信息,请参阅 duplicateTab

使用 splitPane 打开新窗格

若要打开路径(和配置文件)与当前活跃终端相同的新窗格,请使用“复制窗格”操作。 默认情况下,不限制此操作。 此操作最简单的形式是:

        { "command": { "action": "splitPane", "splitMode": "duplicate" } },

有关更多详细信息,请参阅 splitPane

使用菜单复制路径

也可在选项卡上下文菜单上的“复制选项卡”和“拆分窗格”条目下执行上述操作。

Image duplicate-tab-same-cwdImage split-pane-same-cwd