From 54272e86b3a28a3f140074477710fd951098cde9 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Wed, 17 Jul 2019 00:10:12 -0400 Subject: [PATCH] [interactive] Initial implementation of PROMPT_COMMAND (#414) - Location information is wrong - PROMPT_COMMAND=';' gives a traceback pointing to ~/.local/oil/oshrc instead of [ interactive ] or [ PROMPT_COMMAND ] - Don't let command change status Addresses https://github.com/oilshell/oil/issues/400 --- core/main_loop.py | 20 +++++++++++++++++++- spec/interactive.test.sh | 16 +++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/core/main_loop.py b/core/main_loop.py index cfae324a0a..907bd08ea5 100644 --- a/core/main_loop.py +++ b/core/main_loop.py @@ -18,9 +18,9 @@ command_t, command, parse_result__EmptyLine, parse_result__Eof, parse_result__Node ) +from _devbuild.gen.runtime_asdl import value_e, arg_vector from core import ui from core import util -#from core.util import log from typing import Any, Optional, List, TYPE_CHECKING if TYPE_CHECKING: @@ -31,6 +31,23 @@ #from osh.cmd_exec import Executor +def _ExecutePromptCommand(ex): + # type: (Any) -> None + prompt_var = ex.mem.GetVar('PROMPT_COMMAND') + # Undefined, Array, or AssociativeArray + if prompt_var.tag != value_e.Str: + return + command = prompt_var.s + + # save this so PROMPT_COMMAND can't set $? + ex.mem.PushStatusFrame() + arg_vec = arg_vector(['PROMPT_COMMAND', command], [0, 0]) + try: + ex._Eval(arg_vec) + finally: + ex.mem.PopStatusFrame() + + def Interactive(opts, ex, c_parser, display, errfmt): # type: (Any, Any, CommandParser, Any, ErrorFormatter) -> Any status = 0 @@ -42,6 +59,7 @@ def Interactive(opts, ex, c_parser, display, errfmt): # it appears in all branches. while True: # ONLY EXECUTES ONCE + _ExecutePromptCommand(ex) try: # may raise HistoryError or ParseError result = c_parser.ParseInteractiveLine() diff --git a/spec/interactive.test.sh b/spec/interactive.test.sh index 9e3fb6d458..ee3c693797 100755 --- a/spec/interactive.test.sh +++ b/spec/interactive.test.sh @@ -20,7 +20,11 @@ one #### fatal errors continue # NOTE: tried here doc, but sys.stdin.isatty() fails. Could we fake it? -$SH -i -c ' +case "$SH" in + *bash) FLAGS='--noprofile --norc';; + *osh) FLAGS='--rcfile /dev/null';; +esac +$SH $FLAGS -i -c ' echo $(( 1 / 0 )) echo one exit 42 @@ -51,3 +55,13 @@ RCFILE ## N-I dash status: 2 ## N-I mksh status: 1 +#### interactive shell runs PROMPT_COMMAND after each command +TEST_CASE='PROMPT_COMMAND="echo hi"' +case $SH in + *bash) echo "$TEST_CASE" | $SH --noprofile --norc -i;; + *osh) $SH --rcfile /dev/null -i -c "$TEST_CASE";; + *) $SH -i -c "$TEST_CASE";; +esac +## STDOUT: +hi +## N-I dash/mksh stdout-json: ""