-
-
Save codebykyle/b241e723ddd495aac4eaad9b8aa7c6bc to your computer and use it in GitHub Desktop.
using namespace System.Collections.Generic | |
# Encapsulate an arbitrary command | |
class PaneCommand { | |
[string]$Command | |
PaneCommand() { | |
$this.Command = ""; | |
} | |
PaneCommand([string]$command) { | |
$this.Command = $command | |
} | |
[string]GetCommand() { | |
return $this.Command | |
} | |
[string]ToString() { | |
return $this.GetCommand(); | |
} | |
} | |
# A proxy for Split Pane which takes in a command to run inside the pane | |
class Pane : PaneCommand { | |
[string]$ProfileName; | |
[string]$Orientation | |
[decimal]$Size; | |
Pane([string]$command) : base($command) { | |
$this.Orientation = ''; | |
$this.ProfileName = "Windows Powershell" | |
$this.Size = 0.5; | |
} | |
Pane([string]$command, [string]$orientation) : base($command) { | |
$this.Orientation = $orientation; | |
$this.ProfileName = "Windows Powershell" | |
$this.Size = 0.5; | |
} | |
Pane([string]$command, [string]$orientation, [decimal]$size) : base($command) { | |
$this.Orientation = $orientation; | |
$this.ProfileName = "Windows Powershell" | |
$this.size = $size; | |
} | |
Pane([string]$ProfileName, [string]$command, [string]$orientation, [decimal]$size) : base($command) { | |
$this.Orientation = $orientation; | |
$this.ProfileName = $ProfileName; | |
$this.size = $size; | |
} | |
[string]GetCommand() { | |
return 'split-pane --size {0} {1} -p "{2}" -c {3}' -f $this.Size, $this.Orientation, $this.ProfileName, $this.Command | |
} | |
} | |
class TargetPane : PaneCommand { | |
[int]$SelectedIndex; | |
TargetPane([int]$index) { | |
$this.SelectedIndex = $index; | |
} | |
[string]GetCommand() { | |
return "focus-pane --target={0}" -f $this.SelectedIndex; | |
} | |
} | |
class MoveFocus : PaneCommand { | |
[string]$direction; | |
MoveFocus([string]$direction) { | |
$this.direction = $direction; | |
} | |
[string]GetCommand() { | |
return 'move-focus --direction {0}' -f $this.direction; | |
} | |
} | |
class PaneManager : PaneCommand { | |
[string]$InitialCommand; | |
[List[PaneCommand]]$PaneCommands; | |
[string]$ProfileName; | |
[string]$DefaultOrientation; | |
[double]$DefaultSize; | |
PaneManager() { | |
$this.PaneCommands = [List[PaneCommand]]::new(); | |
$this.ProfileName = "Microsoft Powershell"; | |
$this.DefaultOrientation = '-H'; | |
$this.DefaultSize = 0.5; | |
$this.InitialCommand = "--maximized" | |
} | |
PaneManager([string]$ProfileName) { | |
$this.ProfileName = $ProfileName; | |
$this.DefaultOrientation = '-H'; | |
$this.DefaultSize = 0.5; | |
} | |
[PaneManager]SetInitialCommand([string]$command) { | |
$this.InitialCommand = $command; | |
return $this; | |
} | |
[PaneManager]SetProfileName([string]$name) { | |
$this.ProfileName = $name; | |
return $this; | |
} | |
[PaneManager]SetDefaultOrientation([string]$orientation) { | |
$this.DefaultOrientation = $orientation; | |
return $this; | |
} | |
[PaneManager]SetDefaultSize([double]$size) { | |
$this.DefaultSize = $size; | |
return $this; | |
} | |
[PaneManager]SetOptions([string]$name, [string]$orientation, [double]$size) { | |
return $this.SetProfileName($name) | |
.SetDefaultOrientation($orientation) | |
.SetDefaultSize($size); | |
} | |
[PaneManager]AddPane([PaneManager]$manager) { | |
$manager.SetInitialCommand(''); | |
$this.AddCommand($manager); | |
return $this; | |
} | |
[PaneManager]AddCommand([PaneCommand]$command) { | |
$this.PaneCommands.Add($command); | |
return $this; | |
} | |
[PaneManager]AddPane([string]$command, [string]$orientation, [decimal]$size) { | |
$newPane = $this.MakePane( | |
$this.ProfileName, | |
$command, | |
$orientation, | |
$size | |
); | |
$this.AddCommand($newPane); | |
return $this; | |
} | |
[Pane]MakePane($ProfileName, $command, $orientation, $size) { | |
$newPane = [Pane]::new($ProfileName, $command, $orientation, $size); | |
return $newPane; | |
} | |
[PaneManager]TargetPane([int]$index) { | |
$targetCommand = [TargetPane]::new($index) | |
$this.AddCommand($targetCommand) | |
return $this; | |
} | |
[PaneManager]MoveFocus([string]$direction) { | |
$targetCommand = [MoveFocus]::new($direction) | |
$this.AddCommand($targetCommand) | |
return $this; | |
} | |
[int]GetPaneCount() { | |
$count = 0; | |
foreach ($command in $this.PaneCommands) | |
{ | |
if ($command -is [PaneManager]) { | |
$count += $command.GetPaneCount(); | |
} elseif ($command -is [PaneCommand]) { | |
$count += 1; | |
} | |
} | |
return $count; | |
} | |
[string]GetCommand() { | |
$joinedCommands = $this.PaneCommands -join "; "; | |
if ($joinedCommands -eq "") { | |
return $this.InitialCommand; | |
} | |
$finalCommand = if ($this.InitialCommand -ne "") { "{0}; {1}" -f $this.InitialCommand, $joinedCommands} else { $joinedCommands }; | |
return $finalCommand | |
} | |
} | |
# Your script here; see Gist comments |
Hello everyone. Thank you for all the stars and the support. I have added some functionality to this. I added a fluent interface, support for different types of consoles, and nested windows.
Usage
Copy the above script into a file. Configure your script at the bottom to layout your panes, and then run the script.
The way this script works is by constructing a command to start Windows Terminal. We have a PaneManager class that makes adding repetitive commands a little easier. You can either use this script to generate a command for you, or run this directly through wt.
The following examples assume you have pasted the above script into a file, and you are editing, the very bottom of the file
Basic Usage
To get started, you need to instantiate a PaneManager class, which you can do so like this:
$paneManager = ([PaneManager]::new());
You also need to give the Pane Manager an initial script to run. This will run in the first window, before any splits are done. For example, to create a simple, single-pane SSH connection, you can run:
$paneManagerClass = [PaneManager]::new();
$paneManagerClass.SetInitialCommand("powershell ssh [email protected]");
start wt $paneManagerClass;
This will result in a single pane, running the command you specified:
To split a window, we can add a Pane. We need to tell it the direction to split on, and how big it should be. To add another SSH connection with a 50/50 split:
$paneManagerClass = [PaneManager]::new();
$paneManagerClass.SetInitialCommand("powershell ssh [email protected]");
$paneManagerClass.AddPane("powershell ssh [email protected]", '-V', 0.5);
start wt $paneManagerClass;
The second argument, '-V', means that we want to split the current pane, vertically. You can use '-H' if you want to split a pane horizontally.
You don't always have to override the initial command. Not specifying it will (currently) default to --maximized
, which will maximize the current window, and open a local powershell window in the current directory.
If I want one panel for my local computer on top, and two SSH connections, I can use the following:
$paneManagerClass = [PaneManager]::new();
$paneManagerClass.AddPane("powershell ssh [email protected]", '-H', 0.5);
$paneManagerClass.AddPane("powershell ssh [email protected]", '-V', 0.5);
start wt $paneManagerClass;
Because we did not override the initial command, a default powershell window was already made. We split it in half horizontally, then split that in half vertically.
Targeting a specific pane
You will find, that if you follow this pattern long enough, you end up with a really nice Fibonacci sequence. This is because every time you add a new panel, it will cut the current box you are on, with relative size. Because of this, you can target a specific pane to cut either by its position, or its index.
$paneManagerClass = [PaneManager]::new();
$paneManagerClass.AddPane("powershell ssh [email protected]", '-V', 0.5);
$paneManagerClass.AddPane("powershell ssh [email protected]", '-H', 0.5);
$paneManagerClass.TargetPane(1);
$paneManagerClass.AddPane("powershell ssh [email protected]", '-V', 0.5);
start wt $paneManagerClass;
results in:
You can also target a specific panel by using direction, for example, if you want to move to the "left":
$paneManagerClass = [PaneManager]::new();
$paneManagerClass.AddPane("powershell ssh [email protected]", '-V', 0.5);
$paneManagerClass.AddPane("powershell ssh [email protected]", '-H', 0.5);
$paneManagerClass.MoveFocus("left");
$paneManagerClass.AddPane("powershell ssh [email protected]", '-V', 0.5);
start wt $paneManagerClass;
Different Profiles and Settings
You can launch WSL or Command Line, or other Windows Terminals profiles by using the settings on the Pane Manager class. Set the Profile, and all windows added after that will use that profile.
$paneManagerClass = [PaneManager]::new();
$paneManagerClass.AddPane("powershell ssh [email protected]", '-V', 0.5);
$paneManagerClass.AddPane("powershell ssh [email protected]", '-H', 0.5);
$paneManagerClass.SetProfileName("Ubuntu-20.04")
$paneManagerClass.AddPane("", '-V', 0.5);
start wt $paneManagerClass;
Fluent Interface
This now supports a fluent interface. Rather than having to declare each command, line by line, you can chain together commands. Please note the location of the .
in the following code. Its position is important.
$paneManagerClass = ([PaneManager]::new()).
AddPane("powershell ssh [email protected]", '-V', 0.5).
AddPane("powershell ssh [email protected]", '-H', 0.5).
MoveFocus("left").
AddPane("powershell ssh [email protected]", '-V', 0.5);
start wt $paneManagerClass;
Nesting Panels
You can nest panels, although, its a little wonky. You should utilize the targeting for this to provide a decent result. You can use relative positioning with the MoveFocus
command listed above.
$rbpRow1 = ([PaneManager]::new()).
AddPane("powershell connect_rbp01", '-H', 0.75).
AddPane("powershell connect_rbp02", '-V', 0.5);
$rbpRow2 = ([PaneManager]::new()).
MoveFocus("left").
AddPane("powershell connect_rbp03", '-H', 0.66).
MoveFocus("right").
AddPane("powershell connect_rbp04", '-H', 0.66);
$rbpRow3 = ([PaneManager]::new()).
MoveFocus("left").
AddPane("powershell connect_rbp05", '-H', 0.5).
MoveFocus("right").
AddPane("powershell connect_rbp06", '-H', 0.5);
$piManagers = ([PaneManager])::new().
AddPane($rbpRow1).
AddPane($rbpRow2).
AddPane($rbpRow3)
start wt $piManagers
Debugging & Generating
You may not want this giant block of functions and classes in your script. The Pane Manager is eventually being converted down to a command. You can use this script to generate a command, and save that to a file, or run it from a terminal. All you need to do is output the PaneManager as a string:
$rbpRow1 = ([PaneManager]::new()).
AddPane("powershell connect_rbp01", '-H', 0.75).
AddPane("powershell connect_rbp02", '-V', 0.5);
$rbpRow2 = ([PaneManager]::new()).
MoveFocus("left").
AddPane("powershell connect_rbp03", '-H', 0.66).
MoveFocus("right").
AddPane("powershell connect_rbp04", '-H', 0.66);
$rbpRow3 = ([PaneManager]::new()).
MoveFocus("left").
AddPane("powershell connect_rbp05", '-H', 0.5).
MoveFocus("right").
AddPane("powershell connect_rbp06", '-H', 0.5);
$piManagers = ([PaneManager])::new().
AddPane($rbpRow1).
AddPane($rbpRow2).
AddPane($rbpRow3)
echo $piManagers.ToString()
produces:
--maximized; split-pane --size 0.75 -H -p "Microsoft Powershell" -c powershell connect_rbp01; split-pane --size 0.5 -V -p "Microsoft Powershell" -c powershell connect_rbp02; move-focus --direction left; split-pane --size 0.66 -H -p "Microsoft Powershell" -c powershell connect_rbp03; move-focus --direction right; split-pane --size 0.66 -H -p "Microsoft Powershell" -c powershell connect_rbp04; move-focus --direction left; split-pane --size 0.5 -H -p "Microsoft Powershell" -c powershell connect_rbp05; move-focus --direction right; split-pane --size 0.5 -H -p "Microsoft Powershell" -c powershell connect_rbp06
Full Example Usage
$rbpRow1 = ([PaneManager]::new()).
AddPane("powershell connect_rbp01", '-H', 0.75).
AddPane("powershell connect_rbp02", '-V', 0.5);
$rbpRow2 = ([PaneManager]::new()).
MoveFocus("left").
AddPane("powershell connect_rbp03", '-H', 0.66).
MoveFocus("right").
AddPane("powershell connect_rbp04", '-H', 0.66);
$rbpRow3 = ([PaneManager]::new()).
MoveFocus("left").
AddPane("powershell connect_rbp05", '-H', 0.5).
MoveFocus("right").
AddPane("powershell connect_rbp06", '-H', 0.5);
$piManagers = ([PaneManager])::new().
AddPane($rbpRow1).
AddPane($rbpRow2).
AddPane($rbpRow3)
$topRow = ([PaneManager]::new()).
SetInitialCommand("--maximized powershell").
AddPane("powershell connect_office", '-V', 0.75);
$bottomRow = ([PaneManager]::new()).
AddPane("kubectl proxy", '-H', 0.1).
TargetPane(1).
AddPane($piManagers);
$paneManager = ([PaneManager]::new()).
AddPane($topRow).
TargetPane(0).
AddPane($bottomRow);
echo $paneManager.ToString();
start wt $paneManager;
Which generates:
--maximized; split-pane --size 0.75 -V -p "Microsoft Powershell" -c powershell connect_office; focus-pane --target=0; split-pane --size 0.1 -H -p "Microsoft Powershell" -c kubectl proxy; focus-pane --target=1; split-pane --size 0.75 -H -p "Microsoft Powershell" -c powershell connect_rbp01; split-pane --size 0.5 -V -p "Microsoft Powershell" -c powershell connect_rbp02; move-focus --direction left; split-pane --size 0.66 -H -p "Microsoft Powershell" -c powershell connect_rbp03; move-focus --direction right; split-pane --size 0.66 -H -p "Microsoft Powershell" -c powershell connect_rbp04; move-focus --direction left; split-pane --size 0.5 -H -p "Microsoft Powershell" -c powershell connect_rbp05; move-focus --direction right; split-pane --size 0.5 -H -p "Microsoft Powershell" -c powershell connect_rbp06
Please let me know if you have any questions
For those using non US-EN locales, specifically where the thousands separator is "." instead of ",", use the following code bit as a work around:
$culture = [System.Globalization.CultureInfo]::CreateSpecificCulture("en-US") $culture.NumberFormat.NumberDecimalSeparator = "." $culture.NumberFormat.NumberGroupSeparator = "," [System.Threading.Thread]::CurrentThread.CurrentCulture = $culture
Thanks for your work, now I can make my workflow automatically.
Thanks buddy i use this:
Set-Alias -Name t -Value tabRenameFN
function tabRenameFN {
$culture = [System.Globalization.CultureInfo]::CreateSpecificCulture("en-US")
$culture.NumberFormat.NumberDecimalSeparator = "."
$culture.NumberFormat.NumberGroupSeparator = ","
[System.Threading.Thread]::CurrentThread.CurrentCulture = $culture
$paneManagerClass = ([PaneManager]::new()).
AddPane("powershell", '-H', 0.3).
AddPane("powershell", '-V', 0.5).
MoveFocus("up");
start wt $paneManagerClass;
}
running t command and enjoy.
This is a windows terminal launcher that is used to automatically layout and SSH into many servers. I have individual scripts for connecting to each server. Eg, 'connect_rbp01' is a powershell script with an SSH command:
ssh [email protected]
The following is the result of this file:
