mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-28 11:11:47 +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:
|
if dpi_changed:
|
||||||
self.on_dpi_change(os_window_id)
|
self.on_dpi_change(os_window_id)
|
||||||
|
|
||||||
def new_os_window(self, *args):
|
def _new_os_window(self, args, cwd_from=None):
|
||||||
sw = self.args_to_special_window(args) if args else None
|
sw = self.args_to_special_window(args, cwd_from) if args else None
|
||||||
startup_session = create_session(self.opts, special_window=sw)
|
startup_session = create_session(self.opts, special_window=sw, cwd_from=cwd_from)
|
||||||
self.add_os_window(startup_session)
|
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):
|
def add_child(self, window):
|
||||||
self.child_monitor.add_child(window.id, window.child.pid, window.child.child_fd, window.screen)
|
self.child_monitor.add_child(window.id, window.child.pid, window.child.child_fd, window.screen)
|
||||||
self.window_id_map[window.id] = window
|
self.window_id_map[window.id] = window
|
||||||
@@ -357,7 +365,7 @@ class Boss:
|
|||||||
if tm is not None:
|
if tm is not None:
|
||||||
tm.next_tab(-1)
|
tm.next_tab(-1)
|
||||||
|
|
||||||
def args_to_special_window(self, args):
|
def args_to_special_window(self, args, cwd_from=None):
|
||||||
args = list(args)
|
args = list(args)
|
||||||
stdin = None
|
stdin = None
|
||||||
w = self.active_window
|
w = self.active_window
|
||||||
@@ -383,23 +391,39 @@ class Boss:
|
|||||||
if not arg:
|
if not arg:
|
||||||
continue
|
continue
|
||||||
cmd.append(arg)
|
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
|
special_window = None
|
||||||
if args:
|
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
|
tm = self.active_tab_manager
|
||||||
if tm is not None:
|
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
|
tab = self.active_tab
|
||||||
if tab is not None:
|
if tab is not None:
|
||||||
if args:
|
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:
|
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):
|
def move_tab_forward(self):
|
||||||
tm = self.active_tab_manager
|
tm = self.active_tab_manager
|
||||||
|
|||||||
@@ -8,7 +8,13 @@ import sys
|
|||||||
|
|
||||||
import kitty.fast_data_types as fast_data_types
|
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):
|
def remove_cloexec(fd):
|
||||||
@@ -20,8 +26,14 @@ class Child:
|
|||||||
child_fd = pid = None
|
child_fd = pid = None
|
||||||
forked = False
|
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
|
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.cwd = os.path.abspath(os.path.expandvars(os.path.expanduser(cwd or os.getcwd())))
|
||||||
self.opts = opts
|
self.opts = opts
|
||||||
self.stdin = stdin
|
self.stdin = stdin
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ def parse_shortcut(sc):
|
|||||||
|
|
||||||
|
|
||||||
KeyAction = namedtuple('KeyAction', 'func args')
|
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):
|
def parse_key_action(action):
|
||||||
@@ -350,7 +350,9 @@ with open(
|
|||||||
defaults = parse_config(f.read().decode('utf-8').splitlines(), check_keys=False)
|
defaults = parse_config(f.read().decode('utf-8').splitlines(), check_keys=False)
|
||||||
Options = namedtuple('Defaults', ','.join(defaults.keys()))
|
Options = namedtuple('Defaults', ','.join(defaults.keys()))
|
||||||
defaults = Options(**defaults)
|
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'})
|
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+8 eighth_window
|
||||||
map ctrl+shift+9 ninth_window
|
map ctrl+shift+9 ninth_window
|
||||||
map ctrl+shift+0 tenth_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
|
# 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
|
# 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)
|
# 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.
|
# 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
|
# 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
|
# Tab management
|
||||||
@@ -301,7 +307,7 @@ map ctrl+shift+, move_tab_backward
|
|||||||
# map ctrl+alt+2 goto_tab 2
|
# map ctrl+alt+2 goto_tab 2
|
||||||
|
|
||||||
# Just as with new_window above, you can also pass the name of arbitrary
|
# 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
|
# Miscellaneous
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ def parse_session(raw, opts):
|
|||||||
return ans
|
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:
|
if args and args.session:
|
||||||
with open(args.session) as f:
|
with open(args.session) as f:
|
||||||
return parse_session(f.read(), opts)
|
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
|
ans.tabs[-1].layout = current_layout
|
||||||
if special_window is None:
|
if special_window is None:
|
||||||
cmd = args.args if args and args.args else [shell_path]
|
cmd = args.args if args and args.args else [shell_path]
|
||||||
|
from kitty.tabs import SpecialWindow
|
||||||
if getattr(args, 'title', None):
|
if getattr(args, 'title', None):
|
||||||
from kitty.tabs import SpecialWindow
|
ans.add_window(SpecialWindow(cmd, override_title=args.title, cwd_from=cwd_from))
|
||||||
ans.add_window(SpecialWindow(cmd, override_title=args.title))
|
|
||||||
else:
|
else:
|
||||||
ans.add_window(cmd)
|
ans.add_window(SpecialWindow(cmd, cwd_from=cwd_from))
|
||||||
else:
|
else:
|
||||||
ans.add_special_window(special_window)
|
ans.add_special_window(special_window)
|
||||||
return ans
|
return ans
|
||||||
|
|||||||
@@ -22,16 +22,16 @@ from .utils import color_as_int
|
|||||||
from .window import Window, calculate_gl_geometry
|
from .window import Window, calculate_gl_geometry
|
||||||
|
|
||||||
TabbarData = namedtuple('TabbarData', 'title is_active is_last')
|
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):
|
def SpecialWindow(cmd, stdin=None, override_title=None, cwd_from=None):
|
||||||
return SpecialWindowInstance(cmd, stdin, override_title)
|
return SpecialWindowInstance(cmd, stdin, override_title, cwd_from)
|
||||||
|
|
||||||
|
|
||||||
class Tab: # {{{
|
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.tab_manager_ref = weakref.ref(tab_manager)
|
||||||
self.os_window_id = tab_manager.os_window_id
|
self.os_window_id = tab_manager.os_window_id
|
||||||
self.id = add_tab(self.os_window_id)
|
self.id = add_tab(self.os_window_id)
|
||||||
@@ -50,7 +50,7 @@ class Tab: # {{{
|
|||||||
sl = self.enabled_layouts[0]
|
sl = self.enabled_layouts[0]
|
||||||
self.current_layout = all_layouts[sl](self.os_window_id, self.opts, self.borders.border_width, self.windows)
|
self.current_layout = all_layouts[sl](self.os_window_id, self.opts, self.borders.border_width, self.windows)
|
||||||
if special_window is None:
|
if special_window is None:
|
||||||
self.new_window()
|
self.new_window(cwd_from=cwd_from)
|
||||||
else:
|
else:
|
||||||
self.new_special_window(special_window)
|
self.new_special_window(special_window)
|
||||||
else:
|
else:
|
||||||
@@ -109,7 +109,7 @@ class Tab: # {{{
|
|||||||
w.set_visible_in_layout(i, True)
|
w.set_visible_in_layout(i, True)
|
||||||
self.relayout()
|
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 cmd is None:
|
||||||
if use_shell:
|
if use_shell:
|
||||||
cmd = [shell_path]
|
cmd = [shell_path]
|
||||||
@@ -122,12 +122,12 @@ class Tab: # {{{
|
|||||||
except Exception:
|
except Exception:
|
||||||
import traceback
|
import traceback
|
||||||
traceback.print_exc()
|
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()
|
ans.fork()
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
def new_window(self, use_shell=True, cmd=None, stdin=None, override_title=None):
|
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)
|
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)
|
window = Window(self, child, self.opts, self.args, override_title=override_title)
|
||||||
# Must add child before laying out so that resize_pty succeeds
|
# Must add child before laying out so that resize_pty succeeds
|
||||||
get_boss().add_child(window)
|
get_boss().add_child(window)
|
||||||
@@ -401,10 +401,10 @@ class TabManager: # {{{
|
|||||||
def title_changed(self, new_title):
|
def title_changed(self, new_title):
|
||||||
self.update_tab_bar()
|
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
|
needs_resize = len(self.tabs) == 1
|
||||||
idx = len(self.tabs)
|
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._set_active_tab(idx)
|
||||||
self.update_tab_bar()
|
self.update_tab_bar()
|
||||||
if needs_resize:
|
if needs_resize:
|
||||||
|
|||||||
Reference in New Issue
Block a user