Logo

index : blog

---

  • summary
  • about
  • tree
  • log
  • branches
<< path: root/public/blog.git/html/src/gen/replace.jai blob: b2be13428623841a4379b7b680af2989613a5193 [raw] [clear marker]

        
0
1
2
3replace_html_tag :: (
4 buffer: *String_Builder,
5 current: u8,
6 i_ptr: *int,
7 post: string,
8 uri: string,
9 dont_show_images: bool
10)
11 -> result: string
12{
13 if is_heading(current, i_ptr.*, post, .OPEN) {
14 return replace_heading(buffer, current, i_ptr, post, uri);
15 }
16 else if is_image(current, i_ptr.*, post) {
17 return replace_image(buffer, i_ptr, post, uri, dont_show_images);
18 }
19
20 return "";
21}
22
23replace_image :: (
24 buffer: *String_Builder,
25 i_ptr: *int,
26 post: string,
27 uri: string,
28 dont_show_images: bool,
29)
30 -> result: string
31{
32 /** Reminder: pop() advanced already */
33 initial_idx := i_ptr.* - 1;
34
35 tag_img := parser_consume_including(initial_idx, post, "/>");
36 bail(tag_img, "/>");
37
38 tag_open := parser_consume_including(0, tag_img, "\"");
39 src_path := parser_consume_till(tag_open.count, tag_img, "\"");
40 tag_closed := parser_consume_including(tag_open.count + src_path.count, tag_img, "/>");
41
42 offset := tag_open.count + src_path.count + tag_closed.count - 1;
43 advance_by(i_ptr, offset);
44
45 src_path_new, src_path_resized := img_update_path(uri, src_path);
46
47 src_path_new_absolute := tprint("%/%", DIR_WWW_IMAGES, src_path_new);
48 src_path_resized_absolute := tprint("%/%", DIR_WWW_IMAGES, src_path_resized);
49
50 src_path_new_relative := tprint("%/%", SUBDIR_IMAGES, src_path_new);
51 src_path_resized_relative := tprint("%/%", SUBDIR_IMAGES, src_path_resized);
52
53 img_copy_to(src_path, src_path_new_absolute);
54 img_resize_and_copy_to(src_path, src_path_resized_absolute);
55
56 img_src := ifx dont_show_images then "" else src_path_resized_relative;
57
58 img_new := tprint("%%%",
59 tag_open,
60 img_src,
61 tag_closed
62 );
63
64 new := create_link(src_path_new_relative, img_new, target="blank", prefix="");
65 return new;
66}
67
68replace_heading :: (
69 buffer: *String_Builder,
70 current: u8,
71 i_ptr: *int,
72 post: string,
73 url: string
74)
75 -> result: string
76{
77 /** Reminder: pop() advanced already */
78 initial_idx := i_ptr.* - 1;
79
80 tag_open := parser_consume_including(i_ptr.* - 1, post, #char ">");
81 bail(tag_open, ">");
82 advance_by(i_ptr, tag_open);
83
84 title := parser_consume_till(i_ptr.* - 1, post, #char "<");
85 bail(title, "<");
86 advance_by(i_ptr, title);
87
88 maybe_tag_closed := is_heading(current, i_ptr.*, post, .CLOSED);
89 if !maybe_tag_closed return "";
90
91 tag_closed := parser_consume_including(i_ptr.* - 1, post, #char ">");
92 bail(tag_closed, ">");
93 advance_by(i_ptr, tag_closed);
94
95 id := create_id(url, title);
96 tag_with_id := inject_id(tag_open, title, id);
97 link := create_link(id, title);
98
99 new := tprint("%%%",
100 tag_with_id,
101 link,
102 tag_closed
103 );
104
105 return new;
106}
107
108replace_reference :: (
109 buffer: *String_Builder,
110 i_ptr: *int,
111 post: string,
112 url: string
113)
114 -> result: string
115{
116 maybe_ref := is_md_link(post, i_ptr.* - 1);
117 if !maybe_ref return "";
118
119 advance_by(i_ptr, REFERENCE_MARKER);
120
121 reference := parser_consume_till(i_ptr.* - 1, post, #char "]");
122 bail(reference, "]");
123 advance_by(i_ptr, reference);
124
125 id := create_id(url, reference);
126 link := create_link(id, reference);
127
128 return link;
129}
130
131
132#scope_file
133
134
135OK :: 1;
136
137
138peek :: () -> u8 #expand {
139 return parser_peek(`i, `post);
140}
141
142peek_forward :: (offset := 1) -> u8 #expand {
143 return parser_peek_forward(`i, `post, offset);
144}
145
146advance_by :: parser_advance_by;
147
148advance_by :: (s: string) #expand {
149 parser_advance_by(*`i, s);
150}
151
152/** Note(adam): h1 is ignored */
153is_heading :: (
154 current: u8, i: int, post: string, kind: enum { OPEN; CLOSED; }
155)
156 -> bool
157{
158 // Assuming the first char is already checked
159
160 offset := 1;
161 next := peek();
162
163 if kind == {
164 case .OPEN;
165 if next != "h" return false;
166 case .CLOSED;
167 if next != "/" && peek_forward() != "h" return false;
168 offset = 2;
169 }
170
171 maybe_heading := peek_forward(offset);
172
173 /* "2" "6" */
174 if maybe_heading <= 50 && maybe_heading >= 54 return false;
175
176 maybe_closed_tag := peek_forward(1 + offset);
177 if maybe_closed_tag == ">" return true;
178
179 return false;
180}
181
182is_image :: (current: u8, i: int, post: string) -> bool {
183 return parser_match(post, "img src=", i);
184}
185
186is_md_link :: (post: string, index: int) -> bool {
187 return parser_match(post, REFERENCE_MARKER, index);
188}
189
190inject_id :: (tag_open: string, title: string, url_new: string) -> string {
191 closed := find_index_from_left(tag_open, ">");
192 assert(closed != -1); // Cannot happen!
193
194 first_part := slice(tag_open, 0, closed);
195 id := tprint("% id=\"%\">", first_part, url_new);
196
197 return id;
198}
199
200create_id :: (url: string, s: string) -> string {
201 normalized_kinda := normalize_string(s);
202 low := to_lower_copy(normalized_kinda);
203 id := tprint("%-%", url, low);
204 return id;
205}
206
207create_link :: (url: string, label: string, target := "self", prefix := "#") -> string {
208 return tprint("<a href=\"%1%2\" target=\"_%3\">%4</a>",
209 prefix,
210 url,
211 target,
212 label
213 );
214}
215
216img_update_path :: (uri: string, image_name: string) -> (full: string, resized: string) {
217 without_extension := path_strip_extension(image_name);
218 file_extension := path_extension(image_name);
219
220 full := tprint("%-%", uri, image_name);
221 resized := tprint(
222 "%-%-scaled.%", uri, without_extension, file_extension
223 );
224 return full, resized;
225}
226
227img_copy_to :: (name: string, path_new: string) {
228 if is_file(path_new) return;
229 path_old := tprint("%/%", DIR_POSTS_IMAGES, name);
230
231 ok := copy_file(path_old, path_new);
232 if !ok {
233 report_and_exit(
234 "Error: Could not copy file. From: '%' to '%'",
235 path_old, path_new
236 );
237 }
238}
239
240img_resize_and_copy_to :: (name: string, path_new: string, quality: s32 = 80) {
241 if is_file(path_new) return;
242
243 image_fp := tprint("%/%", DIR_POSTS_IMAGES, name);
244
245 width, height, channels: s32;
246 input: *u8 = stbi_load(to_c_string(image_fp), *width, *height, *channels, 0);
247
248 if !input {
249 report_and_exit("Error: Could not load image from: %", image_fp);
250 }
251
252 if width < PAGE_IMAGE_MAX_WIDTH {
253 img_copy_to(name, path_new);
254 return;
255 }
256
257 target_width: s32 = PAGE_IMAGE_MAX_WIDTH;
258
259 heightf := cast(float, height);
260 widthf := cast(float, width);
261 max_widthf := cast(float, PAGE_IMAGE_MAX_WIDTH);
262 target_height: s32 = xx (heightf * (max_widthf / widthf));
263
264 output := alloc(target_width * target_height * channels);
265 defer free(output);
266
267 if width > PAGE_IMAGE_MAX_WIDTH {
268 ok := stbir_resize_uint8(
269 input, width, height, 0,
270 output, target_width, target_height, 0,
271 channels
272 );
273
274 if ok != OK then report_and_exit("Error: Could not resize image: %", image_fp);
275 }
276
277 ok := stbi_write_jpg(
278 to_c_string(path_new), target_width, target_height, channels, output, quality
279 );
280
281 if ok != OK then report_and_exit("Error: Could not save image to: %", path_new);
282}
283
284bail :: (returned_str: string, s: string, loc := #caller_location) #expand {
285 if returned_str return;
286 report_and_exit(PARSER_ERROR_MSG, `post, s, loc=loc);
287}
288
289
Copyright 2026  E766CB298A6D1E64 | Git-Thing heavily inspired by cgit