Redigera

Dela via


Tutorial: Opening a tab or pane in the same directory in Windows Terminal

Typically, the "new tab" and "split pane" actions will always open a new tab/pane in whatever the startingDirectory is for that profile. However, on other platforms, it's common for new tabs to automatically use the working directory of the current tab as the starting directory for a new tab. This allows the user to quickly multitask in a single directory.

Unfortunately, on Windows, it's tricky to determine what the current working directory ("CWD") for a process is. Even if we were able to look it up, not all applications actually set their CWD as they navigate. Notably, Windows PowerShell doesn't change its CWD as you cd around the file system! Duplicating the CWD of PowerShell automatically would almost always be wrong.

Fortunately, there's a workaround. Applications can emit a special escape sequence (specifically the "OSC 9;9" format) to manually tell the Terminal what the CWD should be.

In this tutorial, you learn how to:

  • Configure the shell to tell the Terminal about its current working directory
  • Use the duplicateTab action to open a tab with the same CWD
  • Use the splitPane action to open a pane with the same CWD
  • Using the tab context menu to open tabs or panes with the same CWD

Configure your shell

To tell the Terminal what the CWD is, you'll need to modify your shell to emit an escape sequence as you navigate the OS. Fortunately, most shells have a mechanism for configuring the "prompt", which is run after every command. This is the perfect place to add such output.

Windows

Command Prompt: cmd.exe

cmd uses the %PROMPT% environment variable to configure the prompt. You can easily prepend the prompt with the command to set the CWD with the following command:

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

This will append $e]9;9;$P$e\ to your current prompt. When cmd evaluates this prompt, it'll replace

  • the $e with the escape character
  • the $p with the current working directory

Note that the above command will only work for the current cmd.exe session. To set the value permanently, AFTER running the above command, you'll want to run

setx PROMPT "%PROMPT%"

PowerShell: powershell.exe or pwsh.exe

If you've never changed your PowerShell prompt before, you should check out about_Prompts first.

Add the following to your PowerShell profile:

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 with posh-git

If you're using posh-git, then that will already modify your prompt. In that case, you'll want to only add the necessary output to the already modified prompt. The following example is a lightly modified version of this example from the ConEmu docs:

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 with Starship

If you're using Starship, then that will already modify your prompt. In that case, you'll want to only add the necessary output to the already modified prompt.

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

Windows Subsystem for Linux distributions primarily use BASH as the command line shell.

bash

Add the following line to the end of your .bash_profile config file:

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

The PROMPT_COMMAND variable in bash tells bash what command to run before displaying the prompt. The printf statement is what we're using to append the sequence for setting the working directory with the Terminal. The $(wslpath -w "$PWD") bit will invoke the wslpath executable to convert the current directory into its Windows-like path. The ${PROMPT_COMMAND:+"$PROMPT_COMMAND; "} bit is some bash magic to make sure we append this command to any existing command (if you've already set PROMPT_COMMAND somewhere else.)

zsh

Add the following lines to the end of your .zshrc file:

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

The precmd_functions hook tells zsh what commands to run before displaying the prompt. The printf statement is what we're using to append the sequence for setting the working directory with the Terminal. The $(wslpath -w "$PWD") bit will invoke the wslpath executable to convert the current directory into its Windows-like path. Using precmd_functions+= make sure we append the keep_current_path function to any existing function already defined for this hook.

Fish

If you're using Fish shell, add the following lines to the end of your config file located at ~/.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

This function will be called whenever the current path is changed to confirm the current session is opened by Windows Terminal (verifying $WT_SESSION) and sending Operating System Command (OSC 9;9;), with the Windows equivalent path (wslpath -w) of current path.

MINGW

For MINGW, Git Bash and Cygwin, you need to modify the PROMPT_COMMAND for WSL: replace wslpath with cygpath.

Add the following line to the end of your .bashrc file:

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

Note

Don't see your favorite shell here? If you figure it out, feel free to open a PR to contribute a solution for your preferred shell!

Using actions to duplicate the path

Once you've got the shell configured to tell the Terminal what the current directory is, opening a new tab or pane with that path is easy.

Open a new tab with duplicateTab

To open a new tab with the same path (and profile) as the currently active terminal, use the "Duplicate Tab" action. This is bound by default to Ctrl+Shift+D, as follows:

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

(see duplicateTab) for more details.

Open a new pane with splitPane

To open a new pane with the same path (and profile) as the currently active terminal, use the "Duplicate Pane" action. This is NOT bound by default. The simplest form of this action is:

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

(see splitPane) for more details.

Using the menu to duplicate the path

the above actions are also available on the tab context menu, under the entries "Duplicate Tab" and "Split Pane".

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