mirror of
https://github.com/kovidgoyal/kitty.git
synced 2024-09-21 11:39:57 +03:00
Shell integration: Fix running bash non-interactively
In POSIX mode, bash does not perform ENV with non-interactive shell, so the mode cannot be recovered. Check the arguments and do not change the execution environment.
This commit is contained in:
parent
c8313409ff
commit
d236b34fd4
@ -71,21 +71,66 @@ def setup_bash_env(env: Dict[str, str], argv: List[str]) -> None:
|
||||
inject = {'1'}
|
||||
posix_env = rcfile = ''
|
||||
remove_args = set()
|
||||
|
||||
expecting_multi_chars_opt = True
|
||||
expecting_option_arg = False
|
||||
interactive_opt = False
|
||||
expecting_file_arg = False
|
||||
file_arg_set = False
|
||||
|
||||
for i in range(1, len(argv)):
|
||||
arg = argv[i]
|
||||
if arg == '--posix':
|
||||
inject.add('posix')
|
||||
posix_env = env.get('ENV', '')
|
||||
remove_args.add(i)
|
||||
elif arg == '--norc':
|
||||
inject.add('no-rc')
|
||||
remove_args.add(i)
|
||||
elif arg == '--noprofile':
|
||||
inject.add('no-profile')
|
||||
remove_args.add(i)
|
||||
elif arg in ('--rcfile', '--init-file') and i + 1 < len(argv):
|
||||
rcfile = argv[i+1]
|
||||
remove_args |= {i, i+1}
|
||||
if expecting_file_arg:
|
||||
file_arg_set = True
|
||||
break
|
||||
if expecting_option_arg:
|
||||
expecting_option_arg = False
|
||||
continue
|
||||
if arg in ('-', '--'):
|
||||
if not expecting_file_arg:
|
||||
expecting_file_arg = True
|
||||
continue
|
||||
elif len(arg) > 1 and arg[1] != '-' and (arg[0] == '-' or arg.startswith('+O')):
|
||||
expecting_multi_chars_opt = False
|
||||
options = arg.lstrip('-+')
|
||||
# shopt option
|
||||
if 'O' in options:
|
||||
t = options.split('O', maxsplit=1)
|
||||
if not t[1]:
|
||||
expecting_option_arg = True
|
||||
options = t[0]
|
||||
# command string
|
||||
if 'c' in options:
|
||||
# non-interactive shell
|
||||
# also skip `bash -ic` interactive mode with command string
|
||||
return
|
||||
# read from stdin and follow with args
|
||||
if 's' in options:
|
||||
break
|
||||
# interactive option
|
||||
if 'i' in options:
|
||||
interactive_opt = True
|
||||
elif arg.startswith('--') and expecting_multi_chars_opt:
|
||||
if arg == '--posix':
|
||||
inject.add('posix')
|
||||
posix_env = env.get('ENV', '')
|
||||
remove_args.add(i)
|
||||
elif arg == '--norc':
|
||||
inject.add('no-rc')
|
||||
remove_args.add(i)
|
||||
elif arg == '--noprofile':
|
||||
inject.add('no-profile')
|
||||
remove_args.add(i)
|
||||
elif arg in ('--rcfile', '--init-file') and i + 1 < len(argv):
|
||||
expecting_option_arg = True
|
||||
rcfile = argv[i+1]
|
||||
remove_args |= {i, i+1}
|
||||
else:
|
||||
file_arg_set = True
|
||||
break
|
||||
if file_arg_set and not interactive_opt:
|
||||
# non-interactive shell
|
||||
return
|
||||
env['ENV'] = os.path.join(shell_integration_dir, 'bash', 'kitty.bash')
|
||||
env['KITTY_BASH_INJECT'] = ' '.join(inject)
|
||||
if posix_env:
|
||||
|
@ -307,17 +307,23 @@ def setup_env(excluded, argv, home_dir, rc='', shell='bash'):
|
||||
setup_bash_env(ans, argv)
|
||||
for x in {'profile', 'bash.bashrc', '.bash_profile', '.bash_login', '.profile', '.bashrc', 'rcfile'} - excluded:
|
||||
with open(os.path.join(home_dir, x), 'w') as f:
|
||||
print(f'echo {x}', file=f)
|
||||
if x == '.bashrc' and rc:
|
||||
print(rc, file=f)
|
||||
else:
|
||||
print(f'echo [{x}]', file=f)
|
||||
ans['KITTY_BASH_ETC_LOCATION'] = home_dir
|
||||
ans['PS1'] = 'PROMPT $ '
|
||||
return ans
|
||||
|
||||
def run_test(argv, *expected, excluded=()):
|
||||
with self.subTest(argv=argv), self.run_shell(shell='bash', setup_env=partial(setup_env, set(excluded)), cmd=argv) as pty:
|
||||
pty.wait_till(lambda: 'PROMPT $' in pty.screen_contents())
|
||||
def run_test(argv, *expected, excluded=(), rc='', wait_string='PROMPT $', assert_not_in=False):
|
||||
with self.subTest(argv=argv), self.run_shell(shell='bash', setup_env=partial(setup_env, set(excluded)), cmd=argv, rc=rc) as pty:
|
||||
pty.wait_till(lambda: wait_string in pty.screen_contents())
|
||||
q = pty.screen_contents()
|
||||
for x in expected:
|
||||
self.assertIn(x, q)
|
||||
if assert_not_in:
|
||||
self.assertNotIn(f'[{x}]', q)
|
||||
else:
|
||||
self.assertIn(f'[{x}]', q)
|
||||
|
||||
run_test('bash', 'bash.bashrc', '.bashrc')
|
||||
run_test('bash --rcfile rcfile', 'bash.bashrc', 'rcfile')
|
||||
@ -327,3 +333,9 @@ def run_test(argv, *expected, excluded=()):
|
||||
run_test('bash --noprofile -l')
|
||||
run_test('bash -l', 'profile', '.bash_login', excluded=('.bash_profile',))
|
||||
run_test('bash -l', 'profile', '.profile', excluded=('.bash_profile', '.bash_login'))
|
||||
|
||||
# test argument parsing and non-interactive shell
|
||||
run_test('bash -s arg1 --rcfile rcfile', 'rcfile', rc='echo ok;read', wait_string='ok', assert_not_in=True)
|
||||
run_test('bash +O login_shell -ic "echo ok;read"', 'bash.bashrc', excluded=('.bash_profile'), wait_string='ok', assert_not_in=True)
|
||||
run_test('bash -l .bashrc', 'profile', rc='echo ok;read', wait_string='ok', assert_not_in=True)
|
||||
run_test('bash -il -- .bashrc', 'profile', rc='echo ok;read', wait_string='ok')
|
||||
|
Loading…
Reference in New Issue
Block a user