module main import time import math import os import veb pub fn (mut app App) running_since() string { duration := time.now().unix() - app.started_at seconds_in_hour := 60 * 60 days := int(math.floor(f64(duration) / f64(seconds_in_hour * 24))) hours := int(math.fmod(math.floor(f64(duration) / f64(seconds_in_hour)), 24)) minutes := int(math.floor(f64(duration) / 60.0)) % 60 seconds := duration % 60 return '${days} days ${hours} hours ${minutes} minutes and ${seconds} seconds' } pub fn (mut ctx Context) make_path(branch_name string, i int) string { if i == 0 { return ctx.path_split[..i + 1].join('/') } mut s := ctx.path_split[0] s += '/tree/${branch_name}/' s += ctx.path_split[1..i + 1].join('/') return s } fn create_directory_if_not_exists(path string) { if !os.exists(path) { os.mkdir(path) or { panic('cannot create ${path} directory') } } } fn calculate_pages(count int, per_page int) int { if count == 0 { return 0 } return int(math.ceil(f32(count) / f32(per_page))) - 1 } fn generate_prev_next_pages(page int) (int, int) { prev_page := if page > 0 { page - 1 } else { 0 } next_page := page + 1 return prev_page, next_page } fn check_first_page(page int) bool { return page == 0 } fn check_last_page(total int, offset int, per_page int) bool { return (total - offset) < per_page } const is_dev = true fn css2(s string) veb.RawHtml { if is_dev { return '' } else { return '' } } fn minify_pr_files_html(mut ctx Context) bool { if ctx.res.body.len == 0 { return true } minified := strip_intertag_whitespace(ctx.res.body) if minified.len != ctx.res.body.len { ctx.res.body = minified ctx.res.header.set(.content_length, ctx.res.body.len.str()) } return true } fn strip_intertag_whitespace(s string) string { mut out := []u8{cap: s.len} mut i := 0 mut preserve_whitespace_depth := 0 for i < s.len { ch := s[i] if ch == `<` { tag_end := html_tag_end(s, i) if tag_end == -1 { out << ch i++ continue } tag_name, closing, self_closing := html_tag_info(s, i, tag_end) compact_tag := compact_html_tag(s, i, tag_end) for k := 0; k < compact_tag.len; k++ { out << compact_tag[k] } if preserves_html_whitespace(tag_name) { if closing { if preserve_whitespace_depth > 0 { preserve_whitespace_depth-- } } else if !self_closing { preserve_whitespace_depth++ } } i = tag_end + 1 continue } if is_html_space(ch) { mut j := i + 1 mut has_indentation := ch != ` ` for j < s.len && is_html_space(s[j]) { if s[j] != ` ` { has_indentation = true } j++ } prev_is_tag_end := out.len > 0 && out[out.len - 1] == `>` next_is_tag_start := j < s.len && s[j] == `<` should_strip := preserve_whitespace_depth == 0 && ((prev_is_tag_end && next_is_tag_start) || (has_indentation && (prev_is_tag_end || next_is_tag_start))) if should_strip { i = j continue } if preserve_whitespace_depth == 0 && has_indentation { out << ` ` } else { for k := i; k < j; k++ { out << s[k] } } i = j continue } out << ch i++ } return out.bytestr() } fn compact_html_tag(s string, start int, end int) string { mut out := []u8{cap: end - start + 1} mut i := start for i <= end { ch := s[i] if ch == `"` || ch == `'` { quote := ch out << ch mut value_end := i + 1 for value_end <= end && s[value_end] != quote { value_end++ } if value_end <= end { mut value_start := i + 1 mut value_finish := value_end for value_start < value_finish && is_html_space(s[value_start]) { value_start++ } for value_finish > value_start && is_html_space(s[value_finish - 1]) { value_finish-- } for k := value_start; k < value_finish; k++ { out << s[k] } out << quote i = value_end + 1 continue } } out << ch i++ } return out.bytestr() } fn html_tag_end(s string, start int) int { mut quote := u8(0) for i := start + 1; i < s.len; i++ { ch := s[i] if quote != 0 { if ch == quote { quote = 0 } } else if ch == `"` || ch == `'` { quote = ch } else if ch == `>` { return i } } return -1 } fn html_tag_info(s string, start int, end int) (string, bool, bool) { mut i := start + 1 mut closing := false if i < end && s[i] == `/` { closing = true i++ } for i < end && is_html_space(s[i]) { i++ } name_start := i for i < end && is_html_tag_name_char(s[i]) { i++ } name := s[name_start..i].to_lower() mut j := end - 1 for j > start && is_html_space(s[j]) { j-- } self_closing := !closing && j > start && s[j] == `/` return name, closing, self_closing } fn preserves_html_whitespace(tag_name string) bool { return tag_name in ['s', 'pre', 'textarea', 'script', 'style'] } fn is_html_tag_name_char(ch u8) bool { return (ch >= `a` && ch <= `z`) || (ch >= `A` && ch <= `Z`) || (ch >= `0` && ch <= `9`) || ch == `-` || ch == `_` || ch == `:` } fn is_html_space(ch u8) bool { return ch == ` ` || ch == `\n` || ch == `\t` || ch == `\r` }