Start work on a unified interface for launching processes
This commit is contained in:
parent
a649eb2a48
commit
6aa82d82ad
@ -1006,14 +1006,20 @@ class Boss:
|
||||
def _new_window(self, args, cwd_from=None):
|
||||
tab = self.active_tab
|
||||
if tab is not None:
|
||||
allow_remote_control = False
|
||||
location = None
|
||||
if args and args[0].startswith('!'):
|
||||
location = args[0][1:].lower()
|
||||
args = args[1:]
|
||||
if args and args[0] == '@':
|
||||
args = args[1:]
|
||||
allow_remote_control = True
|
||||
if args:
|
||||
return tab.new_special_window(self.args_to_special_window(args, cwd_from=cwd_from), location=location)
|
||||
return tab.new_special_window(
|
||||
self.args_to_special_window(args, cwd_from=cwd_from),
|
||||
location=location, allow_remote_control=allow_remote_control)
|
||||
else:
|
||||
return tab.new_window(cwd_from=cwd_from, location=location)
|
||||
return tab.new_window(cwd_from=cwd_from, location=location, allow_remote_control=allow_remote_control)
|
||||
|
||||
def new_window(self, *args):
|
||||
self._new_window(args)
|
||||
@ -1025,6 +1031,11 @@ class Boss:
|
||||
cwd_from = w.child.pid_for_cwd if w is not None else None
|
||||
self._new_window(args, cwd_from=cwd_from)
|
||||
|
||||
def launch(self, *args):
|
||||
from kitty.launch import parse_launch_args, launch
|
||||
opts, args = parse_launch_args(args)
|
||||
launch(self, opts, args)
|
||||
|
||||
def move_tab_forward(self):
|
||||
tm = self.active_tab_manager
|
||||
if tm is not None:
|
||||
|
||||
@ -160,12 +160,8 @@ class Child:
|
||||
child_fd = pid = None
|
||||
forked = False
|
||||
|
||||
def __init__(self, argv, cwd, opts, stdin=None, env=None, cwd_from=None):
|
||||
self.allow_remote_control = False
|
||||
if argv and argv[0] == '@':
|
||||
self.allow_remote_control = True
|
||||
if len(argv) > 1:
|
||||
argv = argv[1:]
|
||||
def __init__(self, argv, cwd, opts, stdin=None, env=None, cwd_from=None, allow_remote_control=False):
|
||||
self.allow_remote_control = allow_remote_control
|
||||
self.argv = argv
|
||||
if cwd_from is not None:
|
||||
try:
|
||||
@ -271,6 +267,13 @@ class Child:
|
||||
except Exception:
|
||||
return list(self.argv)
|
||||
|
||||
@property
|
||||
def foreground_cmdline(self):
|
||||
try:
|
||||
return cmdline_of_process(self.pid_for_cwd) or self.cmdline
|
||||
except Exception:
|
||||
return self.cmdline
|
||||
|
||||
@property
|
||||
def environ(self):
|
||||
try:
|
||||
@ -296,3 +299,14 @@ class Child:
|
||||
def foreground_cwd(self):
|
||||
with suppress(Exception):
|
||||
return cwd_of_process(self.pid_for_cwd) or None
|
||||
|
||||
@property
|
||||
def foreground_environ(self):
|
||||
try:
|
||||
return environ_of_process(self.pid_for_cwd)
|
||||
except Exception:
|
||||
try:
|
||||
return environ_of_process(self.pid)
|
||||
except Exception:
|
||||
pass
|
||||
return {}
|
||||
|
||||
@ -50,7 +50,8 @@ func_with_args, args_funcs = key_func()
|
||||
|
||||
@func_with_args(
|
||||
'pass_selection_to_program', 'new_window', 'new_tab', 'new_os_window',
|
||||
'new_window_with_cwd', 'new_tab_with_cwd', 'new_os_window_with_cwd'
|
||||
'new_window_with_cwd', 'new_tab_with_cwd', 'new_os_window_with_cwd',
|
||||
'launch'
|
||||
)
|
||||
def shlex_parse(func, rest):
|
||||
return func, to_cmdline(rest)
|
||||
|
||||
140
kitty/launch.py
Normal file
140
kitty/launch.py
Normal file
@ -0,0 +1,140 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=utf-8
|
||||
# License: GPLv3 Copyright: 2019, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
|
||||
from kitty.cli import parse_args
|
||||
|
||||
|
||||
def options_spec():
|
||||
if not hasattr(options_spec, 'ans'):
|
||||
OPTIONS = '''
|
||||
--window-title --title
|
||||
The title to set for the new window. By default, title is controlled by the
|
||||
child process.
|
||||
|
||||
|
||||
--tab-title
|
||||
The title for the new tab if launching in a new tab. By default, the title
|
||||
of the actie window in the tab is used as the tab title.
|
||||
|
||||
|
||||
--type
|
||||
type=choices
|
||||
default=window
|
||||
choices=window,tab,os-window
|
||||
Where to launch the child process, in a new kitty window in the current tab,
|
||||
a new tab, or a new OS window.
|
||||
|
||||
|
||||
--cwd
|
||||
The working directory for the newly launched child. Use the special value
|
||||
:code:`current` to use the working directory of the currently active window.
|
||||
|
||||
|
||||
--env
|
||||
type=list
|
||||
Environment variables to set in the child process. Can be specified multiple
|
||||
times to set different environment variables.
|
||||
Syntax: :italic:`name=value`.
|
||||
|
||||
|
||||
--copy-colors
|
||||
type=bool-set
|
||||
Set the colors of the newly created window to be the same as the colors in the
|
||||
currently active window.
|
||||
|
||||
|
||||
--copy-cmdline
|
||||
type=bool-set
|
||||
Ignore any specified command line and instead use the command line from the
|
||||
currently active window.
|
||||
|
||||
|
||||
--copy-env
|
||||
type=bool-set
|
||||
Copy the environment variables from the currently active window into the
|
||||
newly launched child process.
|
||||
|
||||
|
||||
--location
|
||||
type=choices
|
||||
default=last
|
||||
choices=first,neighbor,last
|
||||
Where to place the newly created window when it is added to a tab which
|
||||
already has existing windows in it.
|
||||
|
||||
|
||||
--allow-remote-control
|
||||
type=bool-set
|
||||
Programs running in this window can control kitty (if remote control is
|
||||
enabled). Note that any program with the right level of permissions can still
|
||||
write to the pipes of any other program on the same computer and therefore can
|
||||
control kitty. It can, however, be useful to block programs running on other
|
||||
computers (for example, over ssh) or as other users.
|
||||
|
||||
|
||||
'''
|
||||
options_spec.ans = OPTIONS
|
||||
return options_spec.ans
|
||||
|
||||
|
||||
def parse_launch_args(args):
|
||||
args = list(args or ())
|
||||
try:
|
||||
opts, args = parse_args(args=args, ospec=options_spec)
|
||||
except SystemExit as e:
|
||||
raise ValueError from e
|
||||
return opts, args
|
||||
|
||||
|
||||
def get_env(opts, active_child):
|
||||
env = {}
|
||||
if opts.copy_env and active_child:
|
||||
env.update(active_child.foreground_environ)
|
||||
for x in opts.env:
|
||||
parts = x.split('=', 1)
|
||||
if len(parts) == 2:
|
||||
env[parts[0]] = parts[1]
|
||||
return env
|
||||
|
||||
|
||||
def launch(boss, opts, args):
|
||||
if opts.type == 'tab':
|
||||
tm = boss.active_tab_manager
|
||||
tab = tm.new_tab(empty_tab=True)
|
||||
if opts.tab_title:
|
||||
tab.set_title(opts.tab_title)
|
||||
elif opts.type == 'os-window':
|
||||
oswid = boss.add_os_window()
|
||||
tm = boss.os_window_map[oswid]
|
||||
tab = tm.new_tab(empty_tab=True)
|
||||
if opts.tab_title:
|
||||
tab.set_title(opts.tab_title)
|
||||
else:
|
||||
tab = boss.active_tab
|
||||
active = boss.active_window_for_cwd
|
||||
active_child = getattr(active, 'child', None)
|
||||
kw = {
|
||||
'env': get_env(opts, active_child) or None,
|
||||
'allow_remote_control': opts.allow_remote_control
|
||||
}
|
||||
if opts.cwd:
|
||||
if opts.cwd == 'current':
|
||||
if active_child:
|
||||
kw['cwd_from'] = active_child.pid_for_cwd
|
||||
else:
|
||||
kw['cwd'] = opts.cwd
|
||||
if opts.location != 'last':
|
||||
kw['location'] = opts.location
|
||||
if opts.window_title:
|
||||
kw['override_title'] = opts.window_title
|
||||
if opts.copy_colors and active:
|
||||
kw['copy_colors_from'] = active
|
||||
cmd = args or None
|
||||
if opts.copy_cmdline and active_child:
|
||||
cmd = active_child.foreground_cmdline
|
||||
if cmd:
|
||||
kw['cmd'] = cmd
|
||||
|
||||
return tab.new_window(**kw)
|
||||
@ -236,7 +236,7 @@ class Tab: # {{{
|
||||
if self.current_layout.remove_all_biases():
|
||||
self.relayout()
|
||||
|
||||
def launch_child(self, use_shell=False, cmd=None, stdin=None, cwd_from=None, cwd=None, env=None):
|
||||
def launch_child(self, use_shell=False, cmd=None, stdin=None, cwd_from=None, cwd=None, env=None, allow_remote_control=False):
|
||||
if cmd is None:
|
||||
if use_shell:
|
||||
cmd = resolved_shell(self.opts)
|
||||
@ -252,7 +252,7 @@ class Tab: # {{{
|
||||
except Exception:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
ans = Child(cmd, cwd or self.cwd, self.opts, stdin, fenv, cwd_from)
|
||||
ans = Child(cmd, cwd or self.cwd, self.opts, stdin, fenv, cwd_from, allow_remote_control=allow_remote_control)
|
||||
ans.fork()
|
||||
return ans
|
||||
|
||||
@ -263,9 +263,10 @@ class Tab: # {{{
|
||||
def new_window(
|
||||
self, use_shell=True, cmd=None, stdin=None, override_title=None,
|
||||
cwd_from=None, cwd=None, overlay_for=None, env=None, location=None,
|
||||
copy_colors_from=None
|
||||
copy_colors_from=None, allow_remote_control=False
|
||||
):
|
||||
child = self.launch_child(use_shell=use_shell, cmd=cmd, stdin=stdin, cwd_from=cwd_from, cwd=cwd, env=env)
|
||||
child = self.launch_child(
|
||||
use_shell=use_shell, cmd=cmd, stdin=stdin, cwd_from=cwd_from, cwd=cwd, env=env, allow_remote_control=allow_remote_control)
|
||||
window = Window(self, child, self.opts, self.args, override_title=override_title, copy_colors_from=copy_colors_from)
|
||||
if overlay_for is not None:
|
||||
overlaid = next(w for w in self.windows if w.id == overlay_for)
|
||||
@ -276,8 +277,8 @@ class Tab: # {{{
|
||||
self._add_window(window, location=location)
|
||||
return window
|
||||
|
||||
def new_special_window(self, special_window, location=None, copy_colors_from=None):
|
||||
return self.new_window(False, *special_window, location=location, copy_colors_from=copy_colors_from)
|
||||
def new_special_window(self, special_window, location=None, copy_colors_from=None, allow_remote_control=False):
|
||||
return self.new_window(False, *special_window, location=location, copy_colors_from=copy_colors_from, allow_remote_control=allow_remote_control)
|
||||
|
||||
def close_window(self):
|
||||
if self.windows:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user