blob: 1e742371ef56fe9577c0a1a510c8e97f3ee6a7fc [file] [log] [blame]
David K. Bainbridge528b3182017-01-23 08:51:59 -08001package vtclean
2
3import (
4 "bytes"
5 "regexp"
6 "strconv"
7)
8
9// see regex.txt for a slightly separated version of this regex
10var vt100re = regexp.MustCompile(`^\033([\[\]]([\d\?]+)?(;[\d\?]+)*)?(.)`)
11var vt100exc = regexp.MustCompile(`^\033(\[[^a-zA-Z0-9@\?]+|[\(\)]).`)
12
13func Clean(line string, color bool) string {
14 var edit = newLineEdit(len(line))
15 lineb := []byte(line)
16
17 hadColor := false
18 for i := 0; i < len(lineb); {
19 c := lineb[i]
20 switch c {
21 case '\b':
22 edit.Move(-1)
23 case '\033':
24 // set terminal title
25 if bytes.HasPrefix(lineb[i:], []byte("\x1b]0;")) {
26 pos := bytes.Index(lineb[i:], []byte("\a"))
27 if pos != -1 {
28 i += pos + 1
29 continue
30 }
31 }
32 if m := vt100exc.Find(lineb[i:]); m != nil {
33 i += len(m)
34 } else if m := vt100re.FindSubmatch(lineb[i:]); m != nil {
35 i += len(m[0])
36 num := string(m[2])
37 n, err := strconv.Atoi(num)
38 if err != nil || n > 10000 {
39 n = 1
40 }
41 switch m[4][0] {
42 case 'm':
43 if color {
44 hadColor = true
45 edit.Vt100(m[0])
46 }
47 case '@':
48 edit.Insert(bytes.Repeat([]byte{' '}, n))
49 case 'C':
50 edit.Move(n)
51 case 'D':
52 edit.Move(-n)
53 case 'P':
54 edit.Delete(n)
55 case 'K':
56 switch num {
57 case "", "0":
58 edit.ClearRight()
59 case "1":
60 edit.ClearLeft()
61 case "2":
62 edit.Clear()
63 }
64 }
65 } else {
66 i += 1
67 }
68 continue
69 default:
70 if c == '\n' || c >= ' ' {
71 edit.Write([]byte{c})
72 }
73 }
74 i += 1
75 }
76 out := edit.Bytes()
77 if hadColor {
78 out = append(out, []byte("\033[0m")...)
79 }
80 return string(out)
81}