mirror of
https://github.com/kovidgoyal/kitty
synced 2026-06-08 22:28:24 +02:00
Add new actions to open tabs/windows with the working directory set to the working directory of the current window
Fixes #237
This commit is contained in:
@@ -94,11 +94,19 @@ class Boss:
|
||||
if dpi_changed:
|
||||
self.on_dpi_change(os_window_id)
|
||||
|
||||
def new_os_window(self, *args):
|
||||
sw = self.args_to_special_window(args) if args else None
|
||||
startup_session = create_session(self.opts, special_window=sw)
|
||||
def _new_os_window(self, args, cwd_from=None):
|
||||
sw = self.args_to_special_window(args, cwd_from) if args else None
|
||||
startup_session = create_session(self.opts, special_window=sw, cwd_from=cwd_from)
|
||||
self.add_os_window(startup_session)
|
||||
|
||||
def new_os_window(self, *args):
|
||||
self._new_os_window(args)
|
||||
|
||||
def new_os_window_with_cwd(self, *args):
|
||||
w = self.active_window
|
||||
cwd_from = w.child.pid if w is not None else None
|
||||
self._new_os_window(args, cwd_from)
|
||||
|
||||
def add_child(self, window):
|
||||
self.child_monitor.add_child(window.id, window.child.pid, window.child.child_fd, window.screen)
|
||||
self.window_id_map[window.id] = window
|
||||
@@ -357,7 +365,7 @@ class Boss:
|
||||
if tm is not None:
|
||||
tm.next_tab(-1)
|
||||
|
||||
def args_to_special_window(self, args):
|
||||
def args_to_special_window(self, args, cwd_from=None):
|
||||
args = list(args)
|
||||
stdin = None
|
||||
w = self.active_window
|
||||
@@ -383,23 +391,39 @@ class Boss:
|
||||
if not arg:
|
||||
continue
|
||||
cmd.append(arg)
|
||||
return SpecialWindow(cmd, stdin)
|
||||
return SpecialWindow(cmd, stdin, cwd_from=cwd_from)
|
||||
|
||||
def new_tab(self, *args):
|
||||
def _new_tab(self, args, cwd_from=None):
|
||||
special_window = None
|
||||
if args:
|
||||
special_window = self.args_to_special_window(args)
|
||||
special_window = self.args_to_special_window(args, cwd_from=cwd_from)
|
||||
tm = self.active_tab_manager
|
||||
if tm is not None:
|
||||
tm.new_tab(special_window=special_window)
|
||||
tm.new_tab(special_window=special_window, cwd_from=cwd_from)
|
||||
|
||||
def new_window(self, *args):
|
||||
def new_tab(self, *args):
|
||||
self._new_tab(args)
|
||||
|
||||
def new_tab_with_cwd(self, *args):
|
||||
w = self.active_window
|
||||
cwd_from = w.child.pid if w is not None else None
|
||||
self._new_tab(args, cwd_from=cwd_from)
|
||||
|
||||
def _new_window(self, args, cwd_from=None):
|
||||
tab = self.active_tab
|
||||
if tab is not None:
|
||||
if args:
|
||||
tab.new_special_window(self.args_to_special_window(args))
|
||||
tab.new_special_window(self.args_to_special_window(args, cwd_from=cwd_from))
|
||||
else:
|
||||
tab.new_window()
|
||||
tab.new_window(cwd_from=cwd_from)
|
||||
|
||||
def new_window(self, *args):
|
||||
self._new_window(args)
|
||||
|
||||
def new_window_with_cwd(self, *args):
|
||||
w = self.active_window
|
||||
cwd_from = w.child.pid if w is not None else None
|
||||
self._new_window(args, cwd_from=cwd_from)
|
||||
|
||||
def move_tab_forward(self):
|
||||
tm = self.active_tab_manager
|
||||
|
||||
@@ -8,7 +8,13 @@ import sys
|
||||
|
||||
import kitty.fast_data_types as fast_data_types
|
||||
|
||||
from .constants import terminfo_dir
|
||||
from .constants import terminfo_dir, is_macos
|
||||
|
||||
|
||||
def cwd_of_process(pid):
|
||||
if is_macos:
|
||||
raise NotImplementedError('getting cwd of child processes not implemented')
|
||||
return os.readlink('/proc/{}/cwd'.format(pid))
|
||||
|
||||
|
||||
def remove_cloexec(fd):
|
||||
@@ -20,8 +26,14 @@ class Child:
|
||||
child_fd = pid = None
|
||||
forked = False
|
||||
|
||||
def __init__(self, argv, cwd, opts, stdin=None, env=None):
|
||||
def __init__(self, argv, cwd, opts, stdin=None, env=None, cwd_from=None):
|
||||
self.argv = argv
|
||||
if cwd_from is not None:
|
||||
try:
|
||||
cwd = cwd_of_process(cwd_from)
|
||||
except Exception:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
self.cwd = os.path.abspath(os.path.expandvars(os.path.expanduser(cwd or os.getcwd())))
|
||||
self.opts = opts
|
||||
self.stdin = stdin
|
||||
|
||||
@@ -94,7 +94,7 @@ def parse_shortcut(sc):
|
||||
|
||||
|
||||
KeyAction = namedtuple('KeyAction', 'func args')
|
||||
shlex_actions = {'pass_selection_to_program', 'new_window', 'new_tab'}
|
||||
shlex_actions = {'pass_selection_to_program', 'new_window', 'new_tab', 'new_os_window', 'new_window_with_cwd', 'new_tab_with_cwd', 'new_os_window_with_cwd'}
|
||||
|
||||
|
||||
def parse_key_action(action):
|
||||
@@ -350,7 +350,9 @@ with open(
|
||||
defaults = parse_config(f.read().decode('utf-8').splitlines(), check_keys=False)
|
||||
Options = namedtuple('Defaults', ','.join(defaults.keys()))
|
||||
defaults = Options(**defaults)
|
||||
actions = frozenset(a.func for a in defaults.keymap.values()) | frozenset({'combine', 'send_text', 'goto_tab'})
|
||||
actions = frozenset(a.func for a in defaults.keymap.values()) | frozenset(
|
||||
'combine send_text goto_tab new_tab_with_cwd new_window_with_cwd new_os_window_with_cwd'.split()
|
||||
)
|
||||
no_op_actions = frozenset({'noop', 'no-op', 'no_op'})
|
||||
|
||||
|
||||
|
||||
@@ -278,14 +278,20 @@ map ctrl+shift+7 seventh_window
|
||||
map ctrl+shift+8 eighth_window
|
||||
map ctrl+shift+9 ninth_window
|
||||
map ctrl+shift+0 tenth_window
|
||||
# You can also open a new window running an arbitrary program, for example:
|
||||
# You can open a new window running an arbitrary program, for example:
|
||||
# map ctrl+shift+y new_window mutt
|
||||
# You can also pass the current selection to the new program by using the @selection placeholder
|
||||
#
|
||||
# You can pass the current selection to the new program by using the @selection placeholder
|
||||
# map ctrl+shift+y new_window less @selection
|
||||
# Finally, you can even send the contents of the current screen + history buffer as stdin using
|
||||
#
|
||||
# You can even send the contents of the current screen + history buffer as stdin using
|
||||
# the placeholders @text (which is the plain text) and @ansi (which includes text styling escape codes)
|
||||
# For example, the following command opens the scrollback buffer in less in a new window.
|
||||
# map ctrl+shift+y new_window @ansi less +G -R
|
||||
#
|
||||
# You can open a new window with the current working directory set to the
|
||||
# working directory of the current window using
|
||||
# map ctrl+alt+enter new_window_with_cwd
|
||||
|
||||
|
||||
# Tab management
|
||||
@@ -301,7 +307,7 @@ map ctrl+shift+, move_tab_backward
|
||||
# map ctrl+alt+2 goto_tab 2
|
||||
|
||||
# Just as with new_window above, you can also pass the name of arbitrary
|
||||
# commands to run when using new_tab.
|
||||
# commands to run when using new_tab and use new_tab_with_cwd.
|
||||
|
||||
|
||||
# Miscellaneous
|
||||
|
||||
@@ -85,7 +85,7 @@ def parse_session(raw, opts):
|
||||
return ans
|
||||
|
||||
|
||||
def create_session(opts, args=None, special_window=None):
|
||||
def create_session(opts, args=None, special_window=None, cwd_from=None):
|
||||
if args and args.session:
|
||||
with open(args.session) as f:
|
||||
return parse_session(f.read(), opts)
|
||||
@@ -100,11 +100,11 @@ def create_session(opts, args=None, special_window=None):
|
||||
ans.tabs[-1].layout = current_layout
|
||||
if special_window is None:
|
||||
cmd = args.args if args and args.args else [shell_path]
|
||||
from kitty.tabs import SpecialWindow
|
||||
if getattr(args, 'title', None):
|
||||
from kitty.tabs import SpecialWindow
|
||||
ans.add_window(SpecialWindow(cmd, override_title=args.title))
|
||||
ans.add_window(SpecialWindow(cmd, override_title=args.title, cwd_from=cwd_from))
|
||||
else:
|
||||
ans.add_window(cmd)
|
||||
ans.add_window(SpecialWindow(cmd, cwd_from=cwd_from))
|
||||
else:
|
||||
ans.add_special_window(special_window)
|
||||
return ans
|
||||
|
||||
@@ -22,16 +22,16 @@ from .utils import color_as_int
|
||||
from .window import Window, calculate_gl_geometry
|
||||
|
||||
TabbarData = namedtuple('TabbarData', 'title is_active is_last')
|
||||
SpecialWindowInstance = namedtuple('SpecialWindow', 'cmd stdin override_title')
|
||||
SpecialWindowInstance = namedtuple('SpecialWindow', 'cmd stdin override_title cwd_from')
|
||||
|
||||
|
||||
def SpecialWindow(cmd, stdin=None, override_title=None):
|
||||
return SpecialWindowInstance(cmd, stdin, override_title)
|
||||
def SpecialWindow(cmd, stdin=None, override_title=None, cwd_from=None):
|
||||
return SpecialWindowInstance(cmd, stdin, override_title, cwd_from)
|
||||
|
||||
|
||||
class Tab: # {{{
|
||||
|
||||
def __init__(self, tab_manager, session_tab=None, special_window=None):
|
||||
def __init__(self, tab_manager, session_tab=None, special_window=None, cwd_from=None):
|
||||
self.tab_manager_ref = weakref.ref(tab_manager)
|
||||
self.os_window_id = tab_manager.os_window_id
|
||||
self.id = add_tab(self.os_window_id)
|
||||
@@ -50,7 +50,7 @@ class Tab: # {{{
|
||||
sl = self.enabled_layouts[0]
|
||||
self.current_layout = all_layouts[sl](self.os_window_id, self.opts, self.borders.border_width, self.windows)
|
||||
if special_window is None:
|
||||
self.new_window()
|
||||
self.new_window(cwd_from=cwd_from)
|
||||
else:
|
||||
self.new_special_window(special_window)
|
||||
else:
|
||||
@@ -109,7 +109,7 @@ class Tab: # {{{
|
||||
w.set_visible_in_layout(i, True)
|
||||
self.relayout()
|
||||
|
||||
def launch_child(self, use_shell=False, cmd=None, stdin=None):
|
||||
def launch_child(self, use_shell=False, cmd=None, stdin=None, cwd_from=None):
|
||||
if cmd is None:
|
||||
if use_shell:
|
||||
cmd = [shell_path]
|
||||
@@ -122,12 +122,12 @@ class Tab: # {{{
|
||||
except Exception:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
ans = Child(cmd, self.cwd, self.opts, stdin, env)
|
||||
ans = Child(cmd, self.cwd, self.opts, stdin, env, cwd_from)
|
||||
ans.fork()
|
||||
return ans
|
||||
|
||||
def new_window(self, use_shell=True, cmd=None, stdin=None, override_title=None):
|
||||
child = self.launch_child(use_shell=use_shell, cmd=cmd, stdin=stdin)
|
||||
def new_window(self, use_shell=True, cmd=None, stdin=None, override_title=None, cwd_from=None):
|
||||
child = self.launch_child(use_shell=use_shell, cmd=cmd, stdin=stdin, cwd_from=cwd_from)
|
||||
window = Window(self, child, self.opts, self.args, override_title=override_title)
|
||||
# Must add child before laying out so that resize_pty succeeds
|
||||
get_boss().add_child(window)
|
||||
@@ -401,10 +401,10 @@ class TabManager: # {{{
|
||||
def title_changed(self, new_title):
|
||||
self.update_tab_bar()
|
||||
|
||||
def new_tab(self, special_window=None):
|
||||
def new_tab(self, special_window=None, cwd_from=None):
|
||||
needs_resize = len(self.tabs) == 1
|
||||
idx = len(self.tabs)
|
||||
self._add_tab(Tab(self, special_window=special_window))
|
||||
self._add_tab(Tab(self, special_window=special_window, cwd_from=cwd_from))
|
||||
self._set_active_tab(idx)
|
||||
self.update_tab_bar()
|
||||
if needs_resize:
|
||||
|
||||
Reference in New Issue
Block a user