package vtclean import ( "bytes" "regexp" "strconv" ) // see regex.txt for a slightly separated version of this regex var vt100re = regexp.MustCompile(`^\033([\[\]]([\d\?]+)?(;[\d\?]+)*)?(.)`) var vt100exc = regexp.MustCompile(`^\033(\[[^a-zA-Z0-9@\?]+|[\(\)]).`) // this is to handle the RGB escape generated by `tput initc 1 500 500 500` var vt100long = regexp.MustCompile(`^\033](\d+);([^\033]+)\033\\`) func Clean(line string, color bool) string { var edit = newLineEdit(len(line)) lineb := []byte(line) hadColor := false for i := 0; i < len(lineb); { c := lineb[i] switch c { case '\b': edit.Move(-1) case '\033': // set terminal title if bytes.HasPrefix(lineb[i:], []byte("\x1b]0;")) { pos := bytes.Index(lineb[i:], []byte("\a")) if pos != -1 { i += pos + 1 continue } } if m := vt100long.Find(lineb[i:]); m != nil { i += len(m) } else if m := vt100exc.Find(lineb[i:]); m != nil { i += len(m) } else if m := vt100re.FindSubmatch(lineb[i:]); m != nil { i += len(m[0]) num := string(m[2]) n, err := strconv.Atoi(num) if err != nil || n > 10000 { n = 1 } switch m[4][0] { case 'm': if color { hadColor = true edit.Vt100(m[0]) } case '@': edit.Insert(bytes.Repeat([]byte{' '}, n)) case 'G': edit.MoveAbs(n) case 'C': edit.Move(n) case 'D': edit.Move(-n) case 'P': edit.Delete(n) case 'K': switch num { case "", "0": edit.ClearRight() case "1": edit.ClearLeft() case "2": edit.Clear() } } } else { i += 1 } continue default: if c == '\n' || c >= ' ' { edit.Write([]byte{c}) } } i += 1 } out := edit.Bytes() if hadColor { out = append(out, []byte("\033[0m")...) } return string(out) }