| ... | @@ -760,17 +760,6 @@ fn writeEscaped(out: anytype, input: []const u8) !void { | ... | @@ -760,17 +760,6 @@ fn writeEscaped(out: anytype, input: []const u8) !void { |
| 760 | //#define VT_BOLD "\x1b[0;1m" | 760 | //#define VT_BOLD "\x1b[0;1m" |
| 761 | //#define VT_RESET "\x1b[0m" | 761 | //#define VT_RESET "\x1b[0m" |
| 762 | | 762 | |
| 763 | const TermState = enum { | | |
| 764 | Start, | | |
| 765 | Escape, | | |
| 766 | LBracket, | | |
| 767 | Number, | | |
| 768 | AfterNumber, | | |
| 769 | Arg, | | |
| 770 | ArgNumber, | | |
| 771 | ExpectEnd, | | |
| 772 | }; | | |
| 773 | | | |
| 774 | test "term color" { | 763 | test "term color" { |
| 775 | const input_bytes = "A\x1b[32;1mgreen\x1b[0mB"; | 764 | const input_bytes = "A\x1b[32;1mgreen\x1b[0mB"; |
| 776 | const result = try termColor(std.testing.allocator, input_bytes); | 765 | const result = try termColor(std.testing.allocator, input_bytes); |
| ... | @@ -787,61 +776,80 @@ fn termColor(allocator: Allocator, input: []const u8) ![]u8 { | ... | @@ -787,61 +776,80 @@ fn termColor(allocator: Allocator, input: []const u8) ![]u8 { |
| 787 | var first_number: usize = undefined; | 776 | var first_number: usize = undefined; |
| 788 | var second_number: usize = undefined; | 777 | var second_number: usize = undefined; |
| 789 | var i: usize = 0; | 778 | var i: usize = 0; |
| 790 | var state = TermState.Start; | 779 | var state: enum { |
| | 780 | start, |
| | 781 | escape, |
| | 782 | lbracket, |
| | 783 | number, |
| | 784 | after_number, |
| | 785 | arg, |
| | 786 | arg_number, |
| | 787 | expect_end, |
| | 788 | } = .start; |
| | 789 | var last_new_line: usize = 0; |
| 791 | var open_span_count: usize = 0; | 790 | var open_span_count: usize = 0; |
| 792 | while (i < input.len) : (i += 1) { | 791 | while (i < input.len) : (i += 1) { |
| 793 | const c = input[i]; | 792 | const c = input[i]; |
| 794 | switch (state) { | 793 | switch (state) { |
| 795 | TermState.Start => switch (c) { | 794 | .start => switch (c) { |
| 796 | '\x1b' => state = TermState.Escape, | 795 | '\x1b' => state = .escape, |
| | 796 | '\n' => { |
| | 797 | try out.writeByte(c); |
| | 798 | last_new_line = buf.items.len; |
| | 799 | }, |
| 797 | else => try out.writeByte(c), | 800 | else => try out.writeByte(c), |
| 798 | }, | 801 | }, |
| 799 | TermState.Escape => switch (c) { | 802 | .escape => switch (c) { |
| 800 | '[' => state = TermState.LBracket, | 803 | '[' => state = .lbracket, |
| 801 | else => return error.UnsupportedEscape, | 804 | else => return error.UnsupportedEscape, |
| 802 | }, | 805 | }, |
| 803 | TermState.LBracket => switch (c) { | 806 | .lbracket => switch (c) { |
| 804 | '0'...'9' => { | 807 | '0'...'9' => { |
| 805 | number_start_index = i; | 808 | number_start_index = i; |
| 806 | state = TermState.Number; | 809 | state = .number; |
| 807 | }, | 810 | }, |
| 808 | else => return error.UnsupportedEscape, | 811 | else => return error.UnsupportedEscape, |
| 809 | }, | 812 | }, |
| 810 | TermState.Number => switch (c) { | 813 | .number => switch (c) { |
| 811 | '0'...'9' => {}, | 814 | '0'...'9' => {}, |
| 812 | else => { | 815 | else => { |
| 813 | first_number = std.fmt.parseInt(usize, input[number_start_index..i], 10) catch unreachable; | 816 | first_number = std.fmt.parseInt(usize, input[number_start_index..i], 10) catch unreachable; |
| 814 | second_number = 0; | 817 | second_number = 0; |
| 815 | state = TermState.AfterNumber; | 818 | state = .after_number; |
| 816 | i -= 1; | 819 | i -= 1; |
| 817 | }, | 820 | }, |
| 818 | }, | 821 | }, |
| 819 | | 822 | |
| 820 | TermState.AfterNumber => switch (c) { | 823 | .after_number => switch (c) { |
| 821 | ';' => state = TermState.Arg, | 824 | ';' => state = .arg, |
| | 825 | 'D' => state = .start, |
| | 826 | 'K' => { |
| | 827 | buf.items.len = last_new_line; |
| | 828 | state = .start; |
| | 829 | }, |
| 822 | else => { | 830 | else => { |
| 823 | state = TermState.ExpectEnd; | 831 | state = .expect_end; |
| 824 | i -= 1; | 832 | i -= 1; |
| 825 | }, | 833 | }, |
| 826 | }, | 834 | }, |
| 827 | TermState.Arg => switch (c) { | 835 | .arg => switch (c) { |
| 828 | '0'...'9' => { | 836 | '0'...'9' => { |
| 829 | number_start_index = i; | 837 | number_start_index = i; |
| 830 | state = TermState.ArgNumber; | 838 | state = .arg_number; |
| 831 | }, | 839 | }, |
| 832 | else => return error.UnsupportedEscape, | 840 | else => return error.UnsupportedEscape, |
| 833 | }, | 841 | }, |
| 834 | TermState.ArgNumber => switch (c) { | 842 | .arg_number => switch (c) { |
| 835 | '0'...'9' => {}, | 843 | '0'...'9' => {}, |
| 836 | else => { | 844 | else => { |
| 837 | second_number = std.fmt.parseInt(usize, input[number_start_index..i], 10) catch unreachable; | 845 | second_number = std.fmt.parseInt(usize, input[number_start_index..i], 10) catch unreachable; |
| 838 | state = TermState.ExpectEnd; | 846 | state = .expect_end; |
| 839 | i -= 1; | 847 | i -= 1; |
| 840 | }, | 848 | }, |
| 841 | }, | 849 | }, |
| 842 | TermState.ExpectEnd => switch (c) { | 850 | .expect_end => switch (c) { |
| 843 | 'm' => { | 851 | 'm' => { |
| 844 | state = TermState.Start; | 852 | state = .start; |
| 845 | while (open_span_count != 0) : (open_span_count -= 1) { | 853 | while (open_span_count != 0) : (open_span_count -= 1) { |
| 846 | try out.writeAll("</span>"); | 854 | try out.writeAll("</span>"); |
| 847 | } | 855 | } |