gitstack

grindlemire/go-tui code browser

3.3 KB Go 145 lines 2026-02-16 · f2a23ec raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package tuigen

import (
	"testing"
)

func TestLexer_UnicodeSymbols(t *testing.T) {
	type tc struct {
		source   string
		expected []TokenType
	}

	tests := map[string]tc{
		"arrow symbols in text": {
			source: `<span>Use ↑/↓ to navigate</span>`,
			expected: []TokenType{
				TokenLAngle, TokenIdent, TokenRAngle, // <span>
				TokenIdent, TokenSymbol, TokenSlash, TokenSymbol, TokenIdent, TokenIdent, // Use ↑/↓ to navigate
				TokenLAngleSlash, TokenIdent, TokenRAngle, // </span>
				TokenEOF,
			},
		},
		"various unicode arrows": {
			source: `<div>← → ↑ ↓</div>`,
			expected: []TokenType{
				TokenLAngle, TokenIdent, TokenRAngle, // <div>
				TokenSymbol, TokenSymbol, TokenSymbol, TokenSymbol, // ← → ↑ ↓
				TokenLAngleSlash, TokenIdent, TokenRAngle, // </div>
				TokenEOF,
			},
		},
		"emoji in text": {
			source: `<span>Hello 👋 World 🌍</span>`,
			expected: []TokenType{
				TokenLAngle, TokenIdent, TokenRAngle, // <span>
				TokenIdent, TokenSymbol, TokenIdent, TokenSymbol, // Hello 👋 World 🌍
				TokenLAngleSlash, TokenIdent, TokenRAngle, // </span>
				TokenEOF,
			},
		},
		"mixed unicode and ascii": {
			source: `<span>Count: 5 ↑</span>`,
			expected: []TokenType{
				TokenLAngle, TokenIdent, TokenRAngle, // <span>
				TokenIdent, TokenColon, TokenInt, TokenSymbol, // Count: 5 ↑
				TokenLAngleSlash, TokenIdent, TokenRAngle, // </span>
				TokenEOF,
			},
		},
	}

	for name, tt := range tests {
		t.Run(name, func(t *testing.T) {
			lexer := NewLexer("test.gsx", tt.source)

			var tokens []TokenType
			for {
				tok := lexer.Next()
				tokens = append(tokens, tok.Type)
				if tok.Type == TokenEOF {
					break
				}
			}

			if len(tokens) != len(tt.expected) {
				t.Errorf("expected %d tokens, got %d", len(tt.expected), len(tokens))
				t.Logf("expected: %v", tt.expected)
				t.Logf("got:      %v", tokens)
				return
			}

			for i, expected := range tt.expected {
				if tokens[i] != expected {
					t.Errorf("token %d: expected %s, got %s", i, expected, tokens[i])
				}
			}

			// Check for errors
			if lexer.Errors().HasErrors() {
				t.Errorf("unexpected lexer errors: %v", lexer.Errors())
			}
		})
	}
}

func TestParser_UnicodeTextContent(t *testing.T) {
	type tc struct {
		source      string
		expectError bool
	}

	tests := map[string]tc{
		"arrows in span text": {
			source: `package test
templ Test() {
	<span>Use ↑/↓ to navigate</span>
}`,
			expectError: false,
		},
		"arrows in attribute string": {
			source: `package test
templ Test() {
	<span text="Use ↑/↓ to navigate"></span>
}`,
			expectError: false,
		},
		"emoji in text": {
			source: `package test
templ Test() {
	<div>
		<span>Hello 👋</span>
		<span>World 🌍</span>
	</div>
}`,
			expectError: false,
		},
		"unicode in multiple elements": {
			source: `package test
templ Test() {
	<div>
		<span>← Previous</span>
		<span>Next →</span>
	</div>
}`,
			expectError: false,
		},
	}

	for name, tt := range tests {
		t.Run(name, func(t *testing.T) {
			lexer := NewLexer("test.gsx", tt.source)
			parser := NewParser(lexer)
			_, _ = parser.ParseFile()

			hasErrors := parser.Errors().HasErrors()
			if hasErrors != tt.expectError {
				if tt.expectError {
					t.Errorf("expected errors but got none")
				} else {
					t.Errorf("unexpected errors: %v", parser.Errors())
				}
			}
		})
	}
}