When resolving scrollback pager if it is not present in system PATH try using shell PATH

This commit is contained in:
Kovid Goyal
2020-02-03 08:03:35 +05:30
parent f9e8a4050c
commit 3b36470e84
5 changed files with 80 additions and 71 deletions

View File

@@ -10,7 +10,7 @@ from contextlib import contextmanager, suppress
from .borders import load_borders_program
from .boss import Boss
from .child import set_default_env, openpty, remove_blocking
from .child import set_default_env
from .cli import create_opts, parse_args
from .config import cached_values_for, initial_window_size_func
from .constants import (
@@ -18,15 +18,15 @@ from .constants import (
is_wayland, kitty_exe, logo_data_file
)
from .fast_data_types import (
GLFW_IBEAM_CURSOR, create_os_window, free_font_data,
glfw_init, glfw_terminate, load_png_data, set_custom_cursor,
set_default_window_icon, set_options
GLFW_IBEAM_CURSOR, create_os_window, free_font_data, glfw_init,
glfw_terminate, load_png_data, set_custom_cursor, set_default_window_icon,
set_options
)
from .fonts.box_drawing import set_scale
from .fonts.render import set_font_family
from .utils import (
detach, log_error, single_instance, startup_notification_handler,
unix_socket_paths
detach, log_error, read_shell_environment, single_instance,
startup_notification_handler, unix_socket_paths
)
from .window import load_shader_programs
@@ -200,55 +200,6 @@ def macos_cmdline(argv_args):
return ans
def read_shell_environment(opts=None):
if not hasattr(read_shell_environment, 'ans'):
ans = read_shell_environment.ans = {}
import subprocess
from .session import resolved_shell
shell = resolved_shell(opts)
master, slave = openpty()
remove_blocking(master)
try:
p = subprocess.Popen(shell + ['-l', '-c', 'env'], stdout=slave, stdin=slave, stderr=slave, start_new_session=True, close_fds=True)
except FileNotFoundError:
log_error('Could not find shell to read environment')
return ans
with os.fdopen(master, 'rb') as stdout, os.fdopen(slave, 'wb'):
raw = b''
from subprocess import TimeoutExpired
from time import monotonic
start_time = monotonic()
while monotonic() - start_time < 1.5:
try:
ret = p.wait(0.01)
except TimeoutExpired:
ret = None
with suppress(Exception):
raw += stdout.read()
if ret is not None:
break
if p.returncode is None:
log_error('Timed out waiting for shell to quit while reading shell environment')
p.kill()
elif p.returncode == 0:
while True:
try:
x = stdout.read()
except Exception:
break
if not x:
break
raw += x
raw = raw.decode('utf-8', 'replace')
for line in raw.splitlines():
k, v = line.partition('=')[::2]
if k and v:
ans[k] = v
else:
log_error('Failed to run shell to read its environment')
return read_shell_environment.ans
def get_editor_from_env(shell_env):
for var in ('VISUAL', 'EDITOR'):
editor = shell_env.get(var)

View File

@@ -7,9 +7,9 @@ import sys
from collections import namedtuple
from .config_data import to_layout_names
from .constants import kitty_exe, shell_path
from .constants import kitty_exe
from .layout import all_layouts
from .utils import log_error
from .utils import log_error, resolved_shell
WindowSizeOpts = namedtuple(
'WindowSizeOpts', 'initial_window_width initial_window_height window_margin_width window_padding_width remember_window_size')
@@ -74,15 +74,6 @@ class Session:
self.tabs[-1].cwd = val
def resolved_shell(opts=None):
ans = getattr(opts, 'shell', '.')
if ans == '.':
ans = [shell_path]
else:
ans = shlex.split(ans)
return ans
def parse_session(raw, opts, default_title=None):
def finalize_session(ans):

View File

@@ -16,9 +16,8 @@ from .fast_data_types import (
x11_window_id
)
from .layout import create_layout_object_for, evict_cached_layouts
from .session import resolved_shell
from .tab_bar import TabBar, TabBarData
from .utils import log_error
from .utils import log_error, resolved_shell
from .window import Window
SpecialWindowInstance = namedtuple('SpecialWindow', 'cmd stdin override_title cwd_from cwd overlay_for env')

View File

@@ -10,11 +10,11 @@ import os
import re
import string
import sys
from time import monotonic
from contextlib import suppress
from time import monotonic
from .constants import (
appname, is_macos, is_wayland, supports_primary_selection
appname, is_macos, is_wayland, shell_path, supports_primary_selection
)
from .rgb import Color, to_color
@@ -452,3 +452,62 @@ def func_name(f):
if hasattr(f, 'func') and hasattr(f.func, '__name__'):
return f.func.__name__
return str(f)
def resolved_shell(opts=None):
ans = getattr(opts, 'shell', '.')
if ans == '.':
ans = [shell_path]
else:
import shlex
ans = shlex.split(ans)
return ans
def read_shell_environment(opts=None):
if not hasattr(read_shell_environment, 'ans'):
from .child import openpty, remove_blocking
ans = read_shell_environment.ans = {}
import subprocess
shell = resolved_shell(opts)
master, slave = openpty()
remove_blocking(master)
try:
p = subprocess.Popen(shell + ['-l', '-c', 'env'], stdout=slave, stdin=slave, stderr=slave, start_new_session=True, close_fds=True)
except FileNotFoundError:
log_error('Could not find shell to read environment')
return ans
with os.fdopen(master, 'rb') as stdout, os.fdopen(slave, 'wb'):
raw = b''
from subprocess import TimeoutExpired
from time import monotonic
start_time = monotonic()
while monotonic() - start_time < 1.5:
try:
ret = p.wait(0.01)
except TimeoutExpired:
ret = None
with suppress(Exception):
raw += stdout.read()
if ret is not None:
break
if p.returncode is None:
log_error('Timed out waiting for shell to quit while reading shell environment')
p.kill()
elif p.returncode == 0:
while True:
try:
x = stdout.read()
except Exception:
break
if not x:
break
raw += x
raw = raw.decode('utf-8', 'replace')
for line in raw.splitlines():
k, v = line.partition('=')[::2]
if k and v:
ans[k] = v
else:
log_error('Failed to run shell to read its environment')
return read_shell_environment.ans

View File

@@ -29,7 +29,8 @@ from .rgb import to_color
from .terminfo import get_capabilities
from .utils import (
color_as_int, get_primary_selection, load_shaders, open_cmd, open_url,
parse_color_set, sanitize_title, set_primary_selection
parse_color_set, read_shell_environment, sanitize_title,
set_primary_selection
)
@@ -541,6 +542,14 @@ class Window:
text = self.as_text(as_ansi=True, add_history=True, add_wrap_markers=True)
data = self.pipe_data(text, has_wrap_markers=True)
cmd = [x.replace('INPUT_LINE_NUMBER', str(data['input_line_number'])) for x in self.opts.scrollback_pager]
import shutil
exe = shutil.which(cmd[0])
if not os.path.isabs(cmd[0]) and not exe:
env = read_shell_environment(self.opts)
if env and 'PATH' in env:
exe = shutil.which(cmd[0], path=env['PATH'])
if exe:
cmd[0] = exe
get_boss().display_scrollback(self, data['text'], cmd)
def paste_bytes(self, text):