def _SpansToParts(s, spans): # type: (str, List[Span]) -> List[str] """Helper for SplitForWordEval.""" parts = [] # type: List[mylib.BufWriter] start_index = 0 # If the last span was black, and we get a backslash, set join_next to merge # two black spans. join_next = False last_span_was_black = False for span_type, end_index in spans: if span_type == span_e.Black: if len(parts) and join_next: parts[-1].write(s[start_index:end_index]) join_next = False else: buf = mylib.BufWriter() buf.write(s[start_index:end_index]) parts.append(buf) last_span_was_black = True elif span_type == span_e.Backslash: if last_span_was_black: join_next = True last_span_was_black = False else: last_span_was_black = False start_index = end_index result = [buf.getvalue() for buf in parts] return result
def _AppendParts(s, spans, max_results, join_next, parts): # type: (str, List[Tuple[span_t, int]], int, bool, List[mylib.BufWriter]) -> Tuple[bool, bool] """ Append to 'parts', for the 'read' builtin. Similar to _SpansToParts in osh/split.py Args: s: The original string spans: List of (span, end_index) max_results: the maximum number of parts we want join_next: Whether to join the next span to the previous part. This happens in two cases: - when we have '\ ' - and when we have more spans # than max_results. """ start_index = 0 # If the last span was black, and we get a backslash, set join_next to merge # two black spans. last_span_was_black = False for span_type, end_index in spans: if span_type == span_e.Black: if join_next and parts: parts[-1].write(s[start_index:end_index]) join_next = False else: buf = mylib.BufWriter() buf.write(s[start_index:end_index]) parts.append(buf) last_span_was_black = True elif span_type == span_e.Delim: if join_next: parts[-1].write(s[start_index:end_index]) join_next = False last_span_was_black = False elif span_type == span_e.Backslash: if last_span_was_black: join_next = True last_span_was_black = False if max_results and len(parts) >= max_results: join_next = True start_index = end_index done = True if len(spans): #log('%s %s', s, spans) #log('%s', spans[-1]) last_span_type, _ = spans[-1] if last_span_type == span_e.Backslash: done = False #log('PARTS %s', parts) return done, join_next
def _RichTraceBegin(self, punct): # type: (str) -> Optional[mylib.BufWriter] """For the stack printed by xtrace_rich""" if not self.exec_opts.xtrace() or not self.exec_opts.xtrace_rich(): return None prefix = self._EvalPS4(punct) buf = mylib.BufWriter() buf.write(prefix) return buf
def __repr__(self): # type: () -> str # TODO: Break this circular dependency. from asdl import format as fmt ast_f = fmt.TextOutput(mylib.BufWriter()) # No color by default. tree = self.PrettyTree() fmt.PrintTree(tree, ast_f) s, _ = ast_f.GetRaw() return s
def _ShTraceBegin(self): # type: () -> Optional[mylib.BufWriter] if not self.exec_opts.xtrace() or not self.exec_opts.xtrace_details(): return None # Note: bash repeats the + for command sub, eval, source. Other shells # don't do it. Leave this out for now. prefix = self._EvalPS4('+') buf = mylib.BufWriter() buf.write(prefix) return buf
def _GetSplitter(self, ifs=None): # type: (str) -> IfsSplitter """Based on the current stack frame, get the splitter.""" if ifs is None: val = self.mem.GetVar('IFS') UP_val = val with tagswitch(val) as case: if case(value_e.Undef): ifs = DEFAULT_IFS elif case(value_e.Str): val = cast(value__Str, UP_val) ifs = val.s else: # TODO: Raise proper error raise AssertionError("IFS shouldn't be an array") try: sp = self.splitters[ifs] except KeyError: # Figure out what kind of splitter we should instantiate. ifs_whitespace = mylib.BufWriter() ifs_other = mylib.BufWriter() for c in ifs: if c in ' \t\n': # Happens to be the same as DEFAULT_IFS ifs_whitespace.write(c) else: # TODO: \ not supported ifs_other.write(c) sp = IfsSplitter(ifs_whitespace.getvalue(), ifs_other.getvalue()) # NOTE: Technically, we could make the key more precise. IFS=$' \t' is # the same as IFS=$'\t '. But most programs probably don't do that, and # everything should work in any case. self.splitters[ifs] = sp return sp
def OnControlFlow(self, keyword, arg): # type: (str, int) -> None # This is NOT affected by xtrace_rich or xtrace_details. Works in both. if not self.exec_opts.xtrace(): return prefix = self._EvalPS4('+') buf = mylib.BufWriter() buf.write(prefix) buf.write(keyword) if arg != 0: buf.write(' ') buf.write(str(arg)) buf.write('\n') self.f.write(buf.getvalue())
def NewTempBuffer(self): # type: () -> AnsiOutput return AnsiOutput(mylib.BufWriter())
def NewTempBuffer(self): # type: () -> HtmlOutput return HtmlOutput(mylib.BufWriter())
def NewTempBuffer(self): # type: () -> TextOutput return TextOutput(mylib.BufWriter())