wezterm
wezterm copied to clipboard
Dropdown/Guake/Visor/hotkey terminal feature
Is your feature request related to a problem? Please describe. The so-called "dropdown" terminal window can be activated or deactivated by a single keystroke. Many terminal emulators have integrated this feature, for example, KDE's yakuake, quake style guake in Gnome, tilda. Also iTerm2 could set to this mode by enable a system wide hotkey in config.
And here's a short video shows how this feature works in xfce-terminal.
This is a so important feature for terminal emulator that there is even an independent project to help people to get it.
Describe the solution you'd like A new key assignment:
keys = {
# press F1 to popup or hide wezterm window
{key="F1", mods="", action="ToggleDropdown"}
}
Related:
- https://github.com/wez/wezterm/issues/1443
- https://github.com/wez/wezterm/issues/1308
any news about this?
If there was news it would be here, and mentioned in the ChangeLog
Bump, I'm really waiting for this feature too
Folks, I have limited time for hacking on things that I don't or won't use. This is one of those features. I spend my available time how I want to spend it because it is my time, not yours! If you thumbs-down a simple statement about where you would find information about progress, you are showing a level of entitlement that simply demotivates me from wanting to work on it. "Bump" comments are in a similar category.
If you'd like to see this implemented, by all means thumb-up the original post at the top; that's useful when it comes to triaging issues because I can see a simple counter without having to scan the issues.
Keep in mind that there is only one of me and I'm doing this for fun. When you are toxic and entitled you make this not fun and I'd rather do something else with my time.
If you're really motivated to see this feature get implemented, this is open source and I'd love to help shepherd a contributor through a PR.
working linux XOrg setup:
~/.config/wezterm/wezterm.lua
local wezterm = require 'wezterm';
wezterm.on("format-window-title", function(tab, pane, tabs, panes, config)
local zoomed = ""
if tab.active_pane.is_zoomed then
zoomed = "[Z] "
end
local index = ""
if #tabs > 1 then
index = string.format("[%d/%d] ", tab.tab_index + 1, #tabs)
end
return "wm_wezterm: " .. zoomed .. index .. tab.active_pane.title
end)
/any/location/script.sh
#!/usr/bin/env bash
TERMINAL_BIN="${1}"
NAME_WINDOW_SEARCH="${2}"
function toggle() {
local WINDOW_ID=$(xdotool search --name "${NAME_WINDOW_SEARCH}")
if [[ ${#WINDOW_ID} -gt 0 ]]; then
xprop -id "${WINDOW_ID}" | grep _NET_WM_STATE_FOCUSED 1>/dev/null
if [[ $? -eq 0 ]]; then
# echo "Focused->Hidden"
xdotool windowminimize "${WINDOW_ID}"
else
# echo "Hidden/Unfocused->Focused"
xdotool windowactivate "${WINDOW_ID}"
fi
else
sh -c "${TERMINAL_BIN}" &
fi
}
toggle
I am using KDE, so I created a global shortcut which executes script.sh "wezterm" "wm_wezterm"
every time the keyboard shortcut is pressed.
Bump, I'm really waiting for this feature too
sadly, it doesn't look like it will be implemented any time soon 😢 I'm sticking with Yakuake or Guake on Linux and Windows Terminal which has a dropdown mode.
@beckend neat! Have you experimented with wezterm start --class
to set a different window class? That might help you avoid needing to change the window title
--class hello
, Tried it now, the --class seems not to work, rather I have no idea what it does.
wmctrl -l
...
0x0180001d -1 workstation-1.localdomain.internal Plasma
0x06e00003 0 N/A wmctrl -l ~
I always get N/A on wezterm, that is why I had to use the title functionality and enforce a consistent title to match. This is the output as expected from the title callback:
wmctrl -l
0x05e00003 0 N/A wm_wezterm: wmctrl -l ~
Probably something wrong wih wmctrl
? I was able to get the classname with both xdotool
and xprop
. Manipulating the window with xdo
using the class name worked too.
So here is how I handle this... I use wezterm as a status bar/drop down/quake console.
This script launches my wezterms with specific class names and specific configurations bspterm
this script is used like this
-
wezbar collapse
to collapse the bar -
wezbar expand
to expand it to about 40% (see the script) -
wezbar runline
focuses the bar without expanding to use it as a run/launcher
example keybindings for wezbar to expand/collapse/runline/launch etc...
##---------- Keybindings for bspwm ----------##
# Terminal (wez)
super + Return
bspterm
# Terminal (wezbar)
super + shift + Return
bspterm -f
# Terminal (wez fullscreen'd)
super + t
bspterm -s
super + alt + b
~/.local/bin/wezbar collapse
super + alt + n
~/.local/bin/wezbar expand
super + alt + r
~/.local/bin/wezbar runline
super + M
~/.local/bin/wezmodal zsh
super + S
bspterm -m
super + V
~/.local/bin/wezmodal fzf-clipcat
bspwmrc snippet for the rules applied....
bspc rule -a wezterm desktop='^1' follow=on focus=on
bspc rule -a wezbar desktop='^1' rectangle=1920x40+0+0 manage=off state=floating border=off
bspc rule -a wezssh desktop='^3' rectangle=1884x982+16+16
bspc rule -a wezdebug desktop='^7' rectangle=1884x982+16+16
# bspc rule -a wezmodal state=floating manage=off
bspc rule -a wezmodal rectangle=800x600+500+300 border=off follow=on sticky=on focus=on center=on state=floating
and my wezterm configs (beware it is a fucking mess because i haven't cleaned it and im always hacking on shit) .config/wezterm
but it works
This is my Swaywm solution to toggle wezterm visibility by pressing F1
~/.config/sway/config
set {
$term_id quake_term
$term wezterm start --class $term_id
$t_pos border none, move position center, resize set width 100 ppt height 100 ppt
}
for_window {
[app_id=$term_id] {
move to scratchpad;
[app_id=$term_id] scratchpad show;
$t_pos
}
}
bindsym --to-code {
# Scratchpad bindsym
## Main terminal
F1 exec swaymsg [app_id=$term_id] scratchpad show || exec $term , $t_pos
}
exec $term
tdrop also works. My wezterm has a unix domain configured
-- in ~/.config/wezterm/wezterm.lua
unix_domains = {
{
name = 'dropdown',
}
},
, and it'll be connected to it when it was triggered by a hotkey handled by sxhkd.
# in ~/.config/sxhkd/sxhkdrc
F11
tdrop -mat -w -4 -h -38 --pre-unmap-hook='wmctrl -ir $wid -b remove,maximized_vert; xdotool windowsize $wid $width 10%' --class 'wezterm.dropdown' -f 'connect dropdown --class wezterm.dropdown' wezterm
F12
tdrop -mat -w -4 -h 45% --pre-unmap-hook='wmctrl -ir $wid -b remove,maximized_vert; xdotool windowsize $wid $width 10%' --class 'wezterm.dropdown' -f 'connect dropdown --class wezterm.dropdown' wezterm
I have the --pre-unmap-hook
arg since tdrop doesn't seem to work nicely with a snapping behavior and/or maximize/unmaximize behavior of the WM I use, so you may be able to just do tdrop -mat -w -4 -h -38 --class 'wezterm.dropdown' -f 'connect dropdown --class wezterm.dropdown' wezterm
instead.
Found a solution for mac, but not perfect.
Open Automator
app, create a Quick Action
task, with no input, and applying for all Applications.
Drag AppleScript
to work flow and edit it like this:
tell application "WezTerm"
activate
end tell
Save and give it a unique name like activate_wezterm
. Generally this will add a service item for all apps under their service menu.
Then, open System Preferences
, click Keyboard
, then click Shortcuts
.
Select App Shortcuts on the left, click the Add
(+) button. In the Menu Title field, type activate_wezterm
or the name you choose before, set a shortcut for it and all done.
To hide the front most window is similar and I just omit the procedure here.
Cons:
- The global shortcut could be conflict with some application's internal settings, e.g. Firefox has F2 as
edit html
, which will override our setting if we set F2 as a global shortcut. - The global shortcut has a significant delay compared to iTerm2's toggle hotkey. I guess about 200-300ms. (I'm using 2021 MBP, M1Max)
@halfelf, thank you for the workaround.
I followed the steps you described and after I press the shortcut keys, it switches me to an already openned WezTerm window or it will open a new one. In my case I configured WezTerm to open only on a specific virtual desktop, this means the shortcut will just switch to desktop 2 where the terminal is running.
This behaviour is different from the one described in this issue. Am I doing something wrong?
Thanks!
@danielnbalasoiu I believe you're on the right track. I haven't tested it on a virtual desktop yet, and indeed I have seen some people talked about activate
command has a strange behavior when I trying to solve this problem.
You could try this script or another one to focus on a window. And this may help locate desktop.
If there are any yabai
, skhd
, and fish
shell users on macOS - I wrote this quick script to quickly show and hide WezTerm (not quite Quake style as it still follows the tiling structure but you can customize it from here).
It uses an extra space as a hidden one (I use only 3 spaces, so 4 is hidden for me).
#!/usr/bin/env fish
set hidden_space 4
function main -a app
set window (yabai -m query --windows | jq --arg app $app '.[] | select(.app==$app)')
set is_visible (echo $window | jq '."is-visible"')
set id (echo $window | jq '.id')
if test -z "$is_visible"
osascript \
-e "on run (argv)" \
-e "tell application (item 1 of argv) to activate" \
-e "end" \
-- "$app"
else if $is_visible
yabai -m window $id --space $hidden_space
echo "$app hidden"
else
yabai -m window $id --space mouse && yabai -m window --focus $id
echo "$app revealed"
end
end
main $argv
and then in skhdrc:
alt - return: ~/.config/scripts/dropdown.fish WezTerm
As a temporary workaround on macOS, I highly recommend using hammerspoon.
This will allow you to target any app with a key combination and either spawn it or show it.
Something as easy as this:
hs.hotkey.bind({"shift", "alt", "ctrl"}, "A", function()
hs.application.launchOrFocus("Wezterm")
end)
I haven't tried that yet, but I'm sure you could use some launch arguments for position and name to spawn a separate Wezterm entity.
@cd-a Thanks a lot! Hammerspoon responses keystroke much faster than my poor applescript.
For a classic dropdown behavior, I have this conf and tested:
hs.hotkey.bind({}, "F2", function()
wez = hs.application.find("Wezterm")
if wez then
if wez:isFrontmost() then
wez:hide()
else
wez:activate()
end
end
end)
+1. Guake is the best at the moment with the tmux like splits, gui configurator, and quake functionality but it's. so. slow.
For anyone using Karabiner, here's a complex modification config using ctrl+esc
{
"title": "Quake-style Hotkey Window for Wezterm",
"rules": [
{
"description": "Launch/show Wezterm if it is not in foreground",
"manipulators": [
{
"type": "basic",
"from": {
"key_code": "escape",
"modifiers": {
"mandatory": ["control"]
}
},
"to": [
{
"shell_command": "open '/Applications/WezTerm.app'"
}
],
"conditions": [
{
"type": "frontmost_application_unless",
"bundle_identifiers": ["^com\\.github\\.wez\\.wezterm$"]
}
]
}
]
},
{
"description": "Minimize Wezterm if it is in foreground",
"manipulators": [
{
"type": "basic",
"from": {
"key_code": "escape",
"modifiers": {
"mandatory": ["control"]
}
},
"to": [
{
"key_code": "h",
"modifiers": ["command"]
}
],
"conditions": [
{
"type": "frontmost_application_if",
"bundle_identifiers": ["^com\\.github\\.wez\\.wezterm$"]
}
]
}
]
}
]
}
Thank you to everyone for offering creative workarounds. Thank you @wez for creating this cool app!
In Windows, script of AutoHotKey will works like Quake Mode. I tested below script on AutoHotKey v2+:
#SingleInstance Force
#Warn
; Load a few environment variables
userprofile := EnvGet("USERPROFILE")
; read config file
configFile := userprofile . "\.QuakeLikeConsole.ini"
LoadConfig()
; Tray icon customization
A_IconTip := "Quake Like Console (key: " . key . ")"
Tray:= A_TrayMenu
Tray.Delete() ; remove standard Menu items
Tray.Add("Quake Like Console", Dummy)
Tray.Add("") ; separator
Tray.Add("&Suspend", ToggleSuspend)
Tray.Add("&Open config file", OpenConfig)
Tray.Add("") ; separator
Tray.Add("E&xit", ButtonExit)
Return
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Handle Hotkey events
ToggleConsole(ThisHotkey)
{
dim := GetActiveMonitorDimention()
;MsgBox( "monIndex: " . dim.index . " x: " . dim.x . " y: " . dim.y . " width: " . dim.width . " height: " . dim.height)
DetectHiddenWindows(true)
local hwnd_id := WinExist(windowMatcher)
if (hwnd_id != 0) {
DetectHiddenWindows(false)
if WinActive() {
WinHide()
} else {
DetectHiddenWindows(true)
; show window on top of monitor with your mouse cursor.
; window size set to width (1.0 * monitor pixel width) x height (heightRatio * monitor pixel height)
WinMove(dim.x, dim.y, dim.width, dim.height * Float(heightRatio), hwnd_id)
WinShow()
WinActivate()
}
} else {
Try {
Run(command, workingDir) ; see http://ahkscript.org/docs/commands/Run.htm
} Catch Error as e {
TrayTip("Could not execute command", command, 3)
Throw e
}
}
Return
}
GetActiveMonitorDimention()
{
dim := {index: 0, x: 0, y: 0, width: 0, height: 0}
CoordMode("Mouse", "Screen")
MouseGetPos(&x, &y)
local count := MonitorGetCount()
Loop count {
MonitorGet(A_Index, &Left, &Top, &Right, &Bottom)
if (x >= Left) && (x <= Right) && (y <= Bottom) && (y >= Top) {
dim.index := A_Index
dim.x := Left
dim.y := Top
dim.width := Abs(Right - Left)
dim.height := Abs(Top - Bottom)
}
} Until (dim.width > 0)
return dim
}
LoadConfig() {
global key, configFile, command, heightRatio, workingDir, windowMatcher, userprofile
Try {
Hotkey(key, "Toggle")
}
command := IniRead(configFile, "Settings", "command", A_Space)
if (command = "") {
command := userprofile . "\wezterm\wezterm-gui.exe"
IniWrite(command, configFile, "Settings", "command")
}
workingDir := IniRead(configFile, "Settings", "workingDir", A_Space)
if (workingDir = "") {
workingDir := userprofile
IniWrite(workingDir, configFile, "Settings", "workingDir")
}
windowMatcher := IniRead(configFile, "Settings", "windowMatcher", A_Space)
if (windowMatcher = "") {
windowMatcher := "ahk_exe wezterm-gui.exe"
IniWrite(windowMatcher, configFile, "Settings", "windowMatcher")
}
key := IniRead(configFile, "Settings", "key", A_Space)
if (key = "") {
key := "^;"
IniWrite(key, configFile, "Settings", "key")
}
heightRatio := IniRead(configFile, "Settings", "heightRatio", A_Space)
if (heightRatio = "") {
heightRatio := "0.6"
IniWrite(heightRatio, configFile, "Settings", "heightRatio")
}
IniWrite("see https://www.autohotkey.com/docs/Hotkeys.htm", configFile, "Help", "key")
IniWrite("see " . website, configFile, "Help", "windowMatcher")
; keyboard key (or key-combination) to toggle the console
Try {
Hotkey(key, ToggleConsole)
} Catch Error {
TrayTip("Invalid key", "using default: <C-;>", 3)
key := "^;"
IniWrite("^;", configFile, "Settings", "key")
Hotkey(key, ToggleConsole)
}
}
ButtonExit(A_ThisMenuItem, A_ThisMenuItemPos, MyMenu)
{
ExitApp()
Return
}
ToggleSuspend(A_ThisMenuItem, A_ThisMenuItemPos, MyMenu)
{
Suspend(-1)
Tray.ToggleCheck("&Suspend")
Return
}
OpenConfig(A_ThisMenuItem, A_ThisMenuItemPos, MyMenu)
{
RunWait(configFile)
LoadConfig()
Reload()
Return
}
Dummy(A_ThisMenuItem, A_ThisMenuItemPos, MyMenu)
{
Return
}
limitation: window will appear in primary monitor at first call.
Note: this script load configuration from %USERPROFILE%\.QuakeLikeConsole.ini
.
please configuration for your wezterm-gui.exe
installation path and hot key (default is set to <C-;>
)
For the ones interested. Using AutoHotKeys v2 in windows 10 this works for me:
#SingleInstance Force
#`::ToggleApp()
ToggleApp() {
AppClass := "org.wezfurlong.wezterm"
ifWinActive, ahk_class %AppClass%
{
WinMinimize, ahk_class %AppClass%
}
else
{
WinActivate, ahk_class %AppClass%
}
IfWinNotExist, ahk_class %AppClass%
{
Run, "C:\Program Files\WezTerm\wezterm-gui.exe" ; Replace with the actual path to your application
}
return
}
Someone has a script that works with Plasma Wayland? 😅
Someone has a script that works with Plasma Wayland? 😅
You can use mine. Works with KWin5 on Wayland. https://github.com/Xinkai/kwin-wezterm-toggle
I got annoyed and whipped something together over my holiday break.
Qurop. While I intend for it to be an all-purpose solution for creating dropdown windows, I've only been testing it with Wezterm. It's very much v0.1.0 and has only been tested on KDE w/Xorg. It's close enough to my Yakuake config that I don't miss it anymore. I'd happily accept additional PRs to shore it up for additional DE's and even Wayland.
This is the AutoHotkey script I'm using. Nothing fancy, but supports Windows virtual desktops:
; Show/hide wezterm
^AppsKey::
if (WinActive("ahk_class org.wezfurlong.wezterm") = "0x0")
{
; Hide and show window to make sure it opens on the current
; desktop. Otherwise it will open on the desktop where it was
; minimized and focus will be moved to that desktop.
WinHide, ahk_class org.wezfurlong.wezterm
WinShow, ahk_class org.wezfurlong.wezterm
WinActivate, ahk_class org.wezfurlong.wezterm
}
else
{
WinMinimize, ahk_class org.wezfurlong.wezterm
; "Deactivate" wezterm by activating the taskbar so that the next
; hotkey press for wezterm will activate wezterm again instead of
; trying to minimize it.
WinActivate, ahk_class Shell_TrayWnd
}
return
this is good
I spent some time using hammerspoon to complete a script. You can try it out, and I think the effect is pretty good. I can continue to optimize it. It performs well on macos when Stage Manager is off.(if stage manager is on,maybe wezterm could become a floating window, then the effect would be better,)
hs.hotkey.bind({ "Alt" }, "`", function()
wez = hs.application.find("Wezterm")
if wez then
if wez:isFrontmost() then
wez:hide()
else
local nowspace = hs.spaces.focusedSpace()
local screen = hs.screen.mainScreen()
wez_window = wez:mainWindow()
hs.spaces.moveWindowToSpace(wez_window, nowspace)
local max = screen:fullFrame()
local f = wez_window:frame()
f.x = max.x
f.y = max.y
f.w = max.w
f.h = max.h * 0.55
hs.timer.doAfter(0.2, function()
wez_window:setFrame(f)
end)
wez_window:focus()
end
end
end)