This commit is contained in:
Kovid Goyal 2022-03-04 20:37:05 +05:30
commit 75224e1661
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 87 additions and 29 deletions

View File

@ -71,21 +71,66 @@ def setup_bash_env(env: Dict[str, str], argv: List[str]) -> None:
inject = {'1'} inject = {'1'}
posix_env = rcfile = '' posix_env = rcfile = ''
remove_args = set() 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)): for i in range(1, len(argv)):
arg = argv[i] arg = argv[i]
if arg == '--posix': if expecting_file_arg:
inject.add('posix') file_arg_set = True
posix_env = env.get('ENV', '') break
remove_args.add(i) if expecting_option_arg:
elif arg == '--norc': expecting_option_arg = False
inject.add('no-rc') continue
remove_args.add(i) if arg in ('-', '--'):
elif arg == '--noprofile': if not expecting_file_arg:
inject.add('no-profile') expecting_file_arg = True
remove_args.add(i) continue
elif arg in ('--rcfile', '--init-file') and i + 1 < len(argv): elif len(arg) > 1 and arg[1] != '-' and (arg[0] == '-' or arg.startswith('+O')):
rcfile = argv[i+1] expecting_multi_chars_opt = False
remove_args |= {i, i+1} 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['ENV'] = os.path.join(shell_integration_dir, 'bash', 'kitty.bash')
env['KITTY_BASH_INJECT'] = ' '.join(inject) env['KITTY_BASH_INJECT'] = ' '.join(inject)
if posix_env: if posix_env:

View File

@ -307,17 +307,23 @@ PS1="{ps1}"
setup_bash_env(ans, argv) setup_bash_env(ans, argv)
for x in {'profile', 'bash.bashrc', '.bash_profile', '.bash_login', '.profile', '.bashrc', 'rcfile'} - excluded: 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: 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['KITTY_BASH_ETC_LOCATION'] = home_dir
ans['PS1'] = 'PROMPT $ ' ans['PS1'] = 'PROMPT $ '
return ans return ans
def run_test(argv, *expected, excluded=()): 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) as pty: 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: 'PROMPT $' in pty.screen_contents()) pty.wait_till(lambda: wait_string in pty.screen_contents())
q = pty.screen_contents() q = pty.screen_contents()
for x in expected: 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', 'bash.bashrc', '.bashrc')
run_test('bash --rcfile rcfile', 'bash.bashrc', 'rcfile') run_test('bash --rcfile rcfile', 'bash.bashrc', 'rcfile')
@ -327,3 +333,9 @@ PS1="{ps1}"
run_test('bash --noprofile -l') run_test('bash --noprofile -l')
run_test('bash -l', 'profile', '.bash_login', excluded=('.bash_profile',)) run_test('bash -l', 'profile', '.bash_login', excluded=('.bash_profile',))
run_test('bash -l', 'profile', '.profile', excluded=('.bash_profile', '.bash_login')) 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')

View File

@ -28,25 +28,26 @@ _ksi_main() {
builtin printf "\eP@kitty-print|%s\e\\" "${b//\\n}" builtin printf "\eP@kitty-print|%s\e\\" "${b//\\n}"
} }
_ksi_safe_source() {
if [[ -f "$1" && -r "$1" ]]; then
builtin source "$1";
builtin return 0;
fi
builtin return 1;
}
if [[ -n "$KITTY_BASH_INJECT" ]]; then if [[ -n "$KITTY_BASH_INJECT" ]]; then
builtin unset ENV; builtin unset ENV;
if [[ -z "$HOME" ]]; then HOME=~; fi if [[ -z "$HOME" ]]; then HOME=~; fi
if [[ -z "$KITTY_BASH_ETC_LOCATION" ]]; then KITTY_BASH_ETC_LOCATION="/etc"; fi if [[ -z "$KITTY_BASH_ETC_LOCATION" ]]; then KITTY_BASH_ETC_LOCATION="/etc"; fi
_ksi_safe_source() {
if [[ -f "$1" && -r "$1" ]]; then
builtin source "$1";
builtin return 0;
fi
builtin return 1;
}
if [[ "$KITTY_BASH_INJECT" == *"posix"* ]]; then if [[ "$KITTY_BASH_INJECT" == *"posix"* ]]; then
_ksi_safe_source "$KITTY_BASH_POSIX_ENV" && builtin export ENV="$KITTY_BASH_POSIX_ENV"; _ksi_safe_source "$KITTY_BASH_POSIX_ENV" && builtin export ENV="$KITTY_BASH_POSIX_ENV";
else else
builtin set +o posix; builtin set +o posix;
if [[ -n "$KITTY_BASH_UNEXPORT_HISTFILE" ]]; then if [[ -n "$KITTY_BASH_UNEXPORT_HISTFILE" ]]; then
export -n HISTFILE; builtin export -n HISTFILE;
unset KITTY_BASH_UNEXPORT_HISTFILE; builtin unset KITTY_BASH_UNEXPORT_HISTFILE;
fi fi
# See run_startup_files() in shell.c in the Bash source code # See run_startup_files() in shell.c in the Bash source code
@ -70,8 +71,8 @@ _ksi_main() {
builtin unset KITTY_BASH_POSIX_ENV; builtin unset KITTY_BASH_POSIX_ENV;
builtin unset KITTY_BASH_INJECT; builtin unset KITTY_BASH_INJECT;
builtin unset KITTY_BASH_ETC_LOCATION; builtin unset KITTY_BASH_ETC_LOCATION;
builtin unset -f _ksi_safe_source
fi fi
builtin unset -f _ksi_safe_source
_ksi_set_mark() { _ksi_set_mark() {
_ksi_prompt["${1}_mark"]="\[\e]133;k;${1}_kitty\a\]" _ksi_prompt["${1}_mark"]="\[\e]133;k;${1}_kitty\a\]"