@@ -7,7 +7,7 @@ pub const Chunker = struct {
77 };
88 }
99
10- pub fn next (self : * Chunker ) ? [] const u8 {
10+ pub fn next (self : * Chunker , display : * Display ) ? TextElement {
1111 if (self .data .len == 0 ) {
1212 return null ;
1313 }
@@ -24,7 +24,7 @@ pub const Chunker = struct {
2424 }
2525 self .data .ptr += 1 ;
2626 self .data .len -= 1 ;
27- return cr ;
27+ return .{ . text = cr , . width = 0 , . font = display . font . default , . texture = undefined } ;
2828 }
2929 if (! is_whitespace (self .data [0 ])) {
3030 break ;
@@ -35,24 +35,29 @@ pub const Chunker = struct {
3535
3636 var end : usize = 0 ;
3737 while (self .data .len > end ) {
38- if (self .data [end ] == '\\ ' and self .data .len > end + 1 and self .data [end + 1 ] == 'n' ) {
38+ const c = self .data [end ];
39+ if (c == '\\ ' and self .data .len > end + 1 and self .data [end + 1 ] == 'n' ) {
3940 if (end == 0 ) {
4041 self .data .ptr += 2 ;
4142 self .data .len -= 2 ;
42- return cr ;
43+ return .{ . text = cr , . width = 0 , . font = display . font . default , . texture = undefined } ;
4344 }
4445 break ;
4546 }
46- if (is_whitespace_or_eol (self .data [end ])) {
47- break ;
48- }
47+ if (is_whitespace_or_eol (c )) break ;
4948 end += 1 ;
5049 }
5150
5251 const token = self .data [0.. end ];
5352 self .data .ptr += end ;
5453 self .data .len -= end ;
55- return token ;
54+
55+ return .{
56+ .text = token ,
57+ .font = guess_language (token , display ),
58+ .width = 0 ,
59+ .texture = undefined ,
60+ };
5661 }
5762};
5863
@@ -70,73 +75,144 @@ pub inline fn is_eol(c: u8) bool {
7075 return c == '\n ' or c == '\r ' or c == 0 ;
7176}
7277
73- const eql = @import ("std" ).mem .eql ;
74- const std = @import ("std" );
75- const unicode = @import ("std" ).unicode ;
76- const expect = std .testing .expect ;
77- const expectEqualDeep = std .testing .expectEqualDeep ;
78- const expectEqual = std .testing .expectEqual ;
79- const expectEqualStrings = std .testing .expectEqualStrings ;
78+ pub fn guess_language (word : []const u8 , display : * Display ) * Font {
79+ var lang = Lang .unknown ;
80+ var v = Utf8View .init (word ) catch {
81+ return display .font .default ;
82+ };
83+ var it = v .iterator ();
84+ while (it .nextCodepoint ()) | c | {
85+ // Grouping characters are not meaningful for detecting language
86+ if (c == '{' or c == '}' or c == '[' or c == ']' ) continue ;
87+
88+ var x = Lang .unknown ;
89+ if (is_greek_letter (c )) {
90+ x = .greek ;
91+ } else if (is_english_letter (c )) {
92+ x = .english ;
93+ } else if (c == ' ' or c == '\n ' or c == '\t ' or c == '"' or c == '\' ' ) {
94+ continue ;
95+ } else if (is_greek_punctuation (c )) {
96+ continue ;
97+ } else if (is_english_punctuation (c )) {
98+ if (lang == .greek ) return display .font .default ;
99+ continue ;
100+ } else {
101+ return display .font .default ;
102+ }
103+ if (lang == .unknown ) {
104+ lang = x ;
105+ continue ;
106+ }
107+ if (lang != x ) {
108+ warn ("Mixed language. Detection failed. {s}" , .{word });
109+ return display .font .default ;
110+ }
111+ }
112+ //debug(" chunk {t} {s}", .{ lang, word });
113+ return switch (lang ) {
114+ .english = > display .font .english ,
115+ .greek = > display .font .greek ,
116+ else = > display .font .default ,
117+ };
118+ }
119+
120+ pub inline fn is_english_punctuation (c : u21 ) bool {
121+ return (c == '.' or c == '?' or c == ',' or c == '"' or c == '\' ' or c == '!' or c == '/' or c == '\u{2018} ' or c == '\u{2019} ' or c == '(' or c == ')' or c == ';' or c == '-' );
122+ }
123+
124+ pub inline fn is_greek_punctuation (c : u21 ) bool {
125+ return (c == '.' or c == ';' or c == ',' or c == '"' or c == '!' or c == '·' or c == '«' or c == '»' );
126+ }
127+
128+ pub inline fn is_english_letter (c : u21 ) bool {
129+ return (c >= 'A' and c <= 'Z' ) or (c >= 'a' and c <= 'z' ) or (c >= '0' and c <= '9' );
130+ }
131+
132+ pub inline fn is_greek_letter (c : u21 ) bool {
133+ return (c >= '\u{0370} ' and c <= '\u{03FF} ' ) or (c >= '\u{1f00} ' and c <= '\u{1ffF} ' );
134+ }
80135
81136test "read_chunks" {
82137 var data = Chunker .init ("the fish" );
83- try expectEqualStrings ("the" , data .next ().? );
84- try expectEqualStrings ("fish" , data .next ().? );
138+ try expectEqualStrings ("the" , data .next ().? . text );
139+ try expectEqualStrings ("fish" , data .next ().? . text );
85140 try expectEqual (null , data .next ());
86141
87142 data = Chunker .init ("" );
88143 try expectEqual (null , data .next ());
89144
90145 data = Chunker .init ("τίς βλέπει" );
91- try expectEqualStrings ("τίς" , data .next ().? );
92- try expectEqualStrings ("βλέπει" , data .next ().? );
146+ try expectEqualStrings ("τίς" , data .next ().? . text );
147+ try expectEqualStrings ("βλέπει" , data .next ().? . text );
93148 try expectEqual (null , data .next ());
94149
95150 data = Chunker .init ("God, god." );
96- try expectEqualStrings ("God," , data .next ().? );
97- try expectEqualStrings ("god." , data .next ().? );
151+ try expectEqualStrings ("God," , data .next ().? . text );
152+ try expectEqualStrings ("god." , data .next ().? . text );
98153 try expectEqual (null , data .next ());
99154
100155 data = Chunker .init ("fish\n cat\n " );
101- try expectEqualStrings ("fish" , data .next ().? );
102- try expectEqualStrings ("\n " , data .next ().? );
103- try expectEqualStrings ("cat" , data .next ().? );
104- try expectEqualStrings ("\n " , data .next ().? );
156+ try expectEqualStrings ("fish" , data .next ().? . text );
157+ try expectEqualStrings ("\n " , data .next ().? . text );
158+ try expectEqualStrings ("cat" , data .next ().? . text );
159+ try expectEqualStrings ("\n " , data .next ().? . text );
105160 try expectEqual (null , data .next ());
106161
107162 data = Chunker .init (" 'fish' \n [cat] \n " );
108- try expectEqualStrings ("'fish'" , data .next ().? );
109- try expectEqualStrings ("\n " , data .next ().? );
110- try expectEqualStrings ("[cat]" , data .next ().? );
111- try expectEqualStrings ("\n " , data .next ().? );
163+ try expectEqualStrings ("'fish'" , data .next ().? . text );
164+ try expectEqualStrings ("\n " , data .next ().? . text );
165+ try expectEqualStrings ("[cat]" , data .next ().? . text );
166+ try expectEqualStrings ("\n " , data .next ().? . text );
112167 try expectEqual (null , data .next ());
113168
114169 data = Chunker .init ("fish\n\n cat" );
115- try expectEqualStrings ("fish" , data .next ().? );
116- try expectEqualStrings ("\n " , data .next ().? );
117- try expectEqualStrings ("\n " , data .next ().? );
118- try expectEqualStrings ("cat" , data .next ().? );
170+ try expectEqualStrings ("fish" , data .next ().? . text );
171+ try expectEqualStrings ("\n " , data .next ().? . text );
172+ try expectEqualStrings ("\n " , data .next ().? . text );
173+ try expectEqualStrings ("cat" , data .next ().? . text );
119174 try expectEqual (null , data .next ());
120175
121176 data = Chunker .init ("fish\r \n\n \r cat" );
122- try expectEqualStrings ("fish" , data .next ().? );
123- try expectEqualStrings ("\n " , data .next ().? );
124- try expectEqualStrings ("\n " , data .next ().? );
125- try expectEqualStrings ("cat" , data .next ().? );
177+ try expectEqualStrings ("fish" , data .next ().? . text );
178+ try expectEqualStrings ("\n " , data .next ().? . text );
179+ try expectEqualStrings ("\n " , data .next ().? . text );
180+ try expectEqualStrings ("cat" , data .next ().? . text );
126181 try expectEqual (null , data .next ());
127182
128183 data = Chunker .init ("\\ ncat" );
129- try expectEqualStrings ("\n " , data .next ().? );
130- try expectEqualStrings ("cat" , data .next ().? );
184+ try expectEqualStrings ("\n " , data .next ().? . text );
185+ try expectEqualStrings ("cat" , data .next ().? . text );
131186 try expectEqual (null , data .next ());
132187
133188 data = Chunker .init ("fish\\ cat" );
134- try expectEqualStrings ("fish\\ cat" , data .next ().? );
189+ try expectEqualStrings ("fish\\ cat" , data .next ().? . text );
135190 try expectEqual (null , data .next ());
136191
137192 data = Chunker .init ("fish\\ ncat" );
138- try expectEqualStrings ("fish" , data .next ().? );
139- try expectEqualStrings ("\n " , data .next ().? );
140- try expectEqualStrings ("cat" , data .next ().? );
193+ try expectEqualStrings ("fish" , data .next ().? . text );
194+ try expectEqualStrings ("\n " , data .next ().? . text );
195+ try expectEqualStrings ("cat" , data .next ().? . text );
141196 try expectEqual (null , data .next ());
142197}
198+
199+ const eql = @import ("std" ).mem .eql ;
200+ const std = @import ("std" );
201+ const unicode = @import ("std" ).unicode ;
202+ const Utf8View = std .unicode .Utf8View ;
203+
204+ const praxis = @import ("praxis" );
205+ const Lang = praxis .Lang ;
206+
207+ const TextElement = @import ("element.zig" ).TextElement ;
208+
209+ const engine = @import ("engine.zig" );
210+ const Display = engine .Display ;
211+ const Font = engine .Font ;
212+ const debug = engine .debug ;
213+ const warn = engine .warn ;
214+
215+ const expect = std .testing .expect ;
216+ const expectEqualDeep = std .testing .expectEqualDeep ;
217+ const expectEqual = std .testing .expectEqual ;
218+ const expectEqualStrings = std .testing .expectEqualStrings ;
0 commit comments