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:
Kovid Goyal
2017-12-21 11:29:21 +05:30
parent 448ffe01c3
commit c5acd94456
6 changed files with 78 additions and 34 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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'})

View File

@@ -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

View File

@@ -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

View File

@@ -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: