def EvalPrompt(self, UP_val): # type: (value_t) -> str """Perform the two evaluations that bash does. Used by $PS1 and ${x@P}.""" if UP_val.tag_() != value_e.Str: return self.default_prompt # no evaluation necessary val = cast(value__Str, UP_val) # Parse backslash escapes (cached) tokens = self.tokens_cache.get(val.s) if tokens is None: tokens = match.Ps1Tokens(val.s) self.tokens_cache[val.s] = tokens # Replace values. ps1_str = self._ReplaceBackslashCodes(tokens) # Parse it like a double-quoted word (cached). TODO: This could be done on # mem.SetValue(), so we get the error earlier. # NOTE: This is copied from the PS4 logic in Tracer. ps1_word = self.parse_cache.get(ps1_str) if ps1_word is None: w_parser = self.parse_ctx.MakeWordParserForPlugin(ps1_str) try: ps1_word = w_parser.ReadForPlugin() except error.Parse as e: ps1_word = word_.ErrorWord("<ERROR: Can't parse PS1: %s>" % e.UserErrorString()) self.parse_cache[ps1_str] = ps1_word # Evaluate, e.g. "${debian_chroot}\u" -> '\u' val2 = self.word_ev.EvalForPlugin(ps1_word) return val2.s
def EvalPrompt(self, val): # type: (value_t) -> str """Perform the two evaluations that bash does. Used by $PS1 and ${x@P}.""" if val.tag != value_e.Str: return self.default_prompt # no evaluation necessary # Parse backslash escapes (cached) try: tokens = self.tokens_cache[val.s] except KeyError: tokens = list(match.PS1_LEXER.Tokens(val.s)) self.tokens_cache[val.s] = tokens # Replace values. ps1_str = self._ReplaceBackslashCodes(tokens) # Parse it like a double-quoted word (cached). TODO: This could be done on # mem.SetVar(), so we get the error earlier. # NOTE: This is copied from the PS4 logic in Tracer. try: ps1_word = self.parse_cache[ps1_str] except KeyError: w_parser = self.parse_ctx.MakeWordParserForPlugin(ps1_str) try: ps1_word = w_parser.ReadForPlugin() except util.ParseError as e: ps1_word = word_.ErrorWord("<ERROR: Can't parse PS1: %s>", e) self.parse_cache[ps1_str] = ps1_word # Evaluate, e.g. "${debian_chroot}\u" -> '\u' val2 = self.ex.word_ev.EvalForPlugin(ps1_word) return val2.s
def _EvalPS4(self): # type: () -> Tuple[str, str] """For set -x.""" first_char = '+' ps4 = ' ' # default val = self.mem.GetVar('PS4') if val.tag_() == value_e.Str: s = cast(value__Str, val).s if s: first_char = s[0] ps4 = s[1:] # NOTE: This cache is slightly broken because aliases are mutable! I think # that is more or less harmless though. try: ps4_word = self.parse_cache[ps4] except KeyError: # We have to parse this at runtime. PS4 should usually remain constant. w_parser = self.parse_ctx.MakeWordParserForPlugin(ps4) try: ps4_word = w_parser.ReadForPlugin() except error.Parse as e: ps4_word = word_.ErrorWord("<ERROR: Can't parse PS4: %s>" % e.UserErrorString()) self.parse_cache[ps4] = ps4_word #print(ps4_word) # TODO: Repeat first character according process stack depth. Where is # that stored? In the executor itself? It should be stored along with # the PID. Need some kind of ShellProcessState or something. # # We should come up with a better mechanism. Something like $PROC_INDENT # and $OIL_XTRACE_PREFIX. # Prevent infinite loop when PS4 has command sub! assert self.exec_opts.xtrace( ) # We shouldn't call this unless it's on! self.mutable_opts.set_xtrace(False) try: prefix = self.word_ev.EvalForPlugin(ps4_word) finally: self.mutable_opts.set_xtrace(True) return first_char, prefix.s
def _EvalPS4(self, punct): # type: (str) -> str """The prefix of each line.""" val = self.mem.GetValue('PS4') if val.tag_() == value_e.Str: ps4 = cast(value__Str, val).s else: ps4 = '' # NOTE: This cache is slightly broken because aliases are mutable! I think # that is more or less harmless though. ps4_word = self.parse_cache.get(ps4) if ps4_word is None: # We have to parse this at runtime. PS4 should usually remain constant. w_parser = self.parse_ctx.MakeWordParserForPlugin(ps4) try: ps4_word = w_parser.ReadForPlugin() except error.Parse as e: ps4_word = word_.ErrorWord("<ERROR: Can't parse PS4: %s>" % e.UserErrorString()) self.parse_cache[ps4] = ps4_word # Mutate objects to save allocations if self.exec_opts.xtrace_rich(): self.val_indent.s = self.indents[self.ind] else: self.val_indent.s = '' self.val_punct.s = punct # Prevent infinite loop when PS4 has command sub! assert self.exec_opts.xtrace() # We shouldn't call this unless it's on # TODO: Remove allocation for [] ? with state.ctx_Option(self.mutable_opts, [option_i.xtrace], False): with state.ctx_Temp(self.mem): self.mem.SetValue(self.lval_indent, self.val_indent, scope_e.LocalOnly) self.mem.SetValue(self.lval_punct, self.val_punct, scope_e.LocalOnly) self.mem.SetValue(self.lval_pid_str, self.val_pid_str, scope_e.LocalOnly) prefix = self.word_ev.EvalForPlugin(ps4_word) return prefix.s