Skip to content

Instantly share code, notes, and snippets.

@DanSM-5
Last active March 5, 2025 03:59
Show Gist options
  • Save DanSM-5/a5cc247419c7deff7a622570fe1d0e3e to your computer and use it in GitHub Desktop.
Save DanSM-5/a5cc247419c7deff7a622570fe1d0e3e to your computer and use it in GitHub Desktop.
Edit current command in editor like bash C-x C-e (ctrl-x ctrl-e) for bash, zsh and powershell
# For windows powershell and pwsh
Set-PSReadLineKeyHandler -Chord 'ctrl+o,ctrl+e' -ScriptBlock {
$line = $cursor = $proc = $null
$editorArgs = @()
# Change this as you prefer
$editor = if ($env:EDITOR) { $env:EDITOR }
else { 'vim' }
try {
$tmpf = New-TemporaryFile
$tmp_file = $tmpf.FullName.Replace('.tmp', '.ps1')
Move-Item $tmpf.FullName $tmp_file
# Get current content
[Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref] $line, [ref] $cursor)
# If (n)vim, start at last line
if ( $editor -Like '*vim' ) {
$editorArgs += '+'
}
# Add current content of prompt to buffer
$line = $line.Replace("`r", "").Trim()
[System.IO.File]::WriteAllLines($tmp_file, $line, [System.Text.UTF8Encoding]($false))
$editorArgs += $tmp_file
# Start editor and wait for it to close
$proc = Start-Process $editor -NoNewWindow -PassThru -ArgumentList $editorArgs
$proc.WaitForExit()
$proc = $null
# Clean prompt
[Microsoft.PowerShell.PSConsoleReadLine]::RevertLine()
$content = (Get-Content -Path $tmp_file -Raw -Encoding UTF8).Replace("`r","").Replace("`t", " ").Trim()
[Microsoft.PowerShell.PSConsoleReadLine]::Insert($content)
# Uncomment if you want to auto run on close
# [Microsoft.PowerShell.PSConsoleReadLine]::AcceptLine()
} finally {
# Cleanup
$proc = $null
if (Test-Path -Path $tmpf.FullName -PathType Leaf -ErrorAction SilentlyContinue) {
Remove-Item -Force $tmpf.FullName
}
Remove-Item -Force $tmp_file -ErrorAction SilentlyContinue
}
}
# Bash
# Credits: https://unix.stackexchange.com/a/684760
# Difference with built-in one is that it won't run the
# command when closing the editor. If you want auto run
# behavior, you're already set.
__edit_command_no_execute () {
local editor="${EDITOR:-vim}"
local tmpf="$(mktemp)"
printf '%s\n' "$READLINE_LINE" >| "$tmpf"
"$editor" "$tmpf"
READLINE_LINE="$(cat "$tmpf")" # Needed cat for issus on git bash but you can try just `<"$tmpf"`
READLINE_POINT="${#READLINE_LINE}"
rm -f "$tmpf" &> /dev/null
}
bind -m emacs -x '"\C-o\C-e":__edit_command_no_execute'
bind -m vi -x '"\C-o\C-e":__edit_command_no_execute'
bind -m vi-insert -x '"\C-o\C-e":__edit_command_no_execute'
# Zsh
# Credits: https://gist.github.com/raven-rock/4fc8152f91eedf663755b65432f48ce5
autoload -U edit-command-line
zle -N edit-command-line
bindkey '^x^e' edit-command-line
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment