| 1 | module main |
| 2 | |
| 3 | import time |
| 4 | import math |
| 5 | import os |
| 6 | import veb |
| 7 | |
| 8 | pub fn (mut app App) running_since() string { |
| 9 | duration := time.now().unix() - app.started_at |
| 10 | |
| 11 | seconds_in_hour := 60 * 60 |
| 12 | |
| 13 | days := int(math.floor(f64(duration) / f64(seconds_in_hour * 24))) |
| 14 | hours := int(math.fmod(math.floor(f64(duration) / f64(seconds_in_hour)), 24)) |
| 15 | minutes := int(math.floor(f64(duration) / 60.0)) % 60 |
| 16 | seconds := duration % 60 |
| 17 | |
| 18 | return '${days} days ${hours} hours ${minutes} minutes and ${seconds} seconds' |
| 19 | } |
| 20 | |
| 21 | pub fn (mut ctx Context) make_path(branch_name string, i int) string { |
| 22 | if i == 0 { |
| 23 | return ctx.path_split[..i + 1].join('/') |
| 24 | } |
| 25 | mut s := ctx.path_split[0] |
| 26 | s += '/tree/${branch_name}/' |
| 27 | s += ctx.path_split[1..i + 1].join('/') |
| 28 | return s |
| 29 | } |
| 30 | |
| 31 | fn create_directory_if_not_exists(path string) { |
| 32 | if !os.exists(path) { |
| 33 | os.mkdir(path) or { panic('cannot create ${path} directory') } |
| 34 | } |
| 35 | } |
| 36 | |
| 37 | fn calculate_pages(count int, per_page int) int { |
| 38 | if count == 0 { |
| 39 | return 0 |
| 40 | } |
| 41 | |
| 42 | return int(math.ceil(f32(count) / f32(per_page))) - 1 |
| 43 | } |
| 44 | |
| 45 | fn generate_prev_next_pages(page int) (int, int) { |
| 46 | prev_page := if page > 0 { page - 1 } else { 0 } |
| 47 | next_page := page + 1 |
| 48 | |
| 49 | return prev_page, next_page |
| 50 | } |
| 51 | |
| 52 | fn check_first_page(page int) bool { |
| 53 | return page == 0 |
| 54 | } |
| 55 | |
| 56 | fn check_last_page(total int, offset int, per_page int) bool { |
| 57 | return (total - offset) < per_page |
| 58 | } |
| 59 | |
| 60 | const is_dev = true |
| 61 | |
| 62 | fn css2(s string) veb.RawHtml { |
| 63 | if is_dev { |
| 64 | return '<link href="http://localhost:8000/${s}" rel="stylesheet" type="text/css">' |
| 65 | } else { |
| 66 | return '<link href="/static/${s}" rel="stylesheet" type="text/css">' |
| 67 | } |
| 68 | } |
| 69 | |
| 70 | fn minify_pr_files_html(mut ctx Context) bool { |
| 71 | if ctx.res.body.len == 0 { |
| 72 | return true |
| 73 | } |
| 74 | minified := strip_intertag_whitespace(ctx.res.body) |
| 75 | if minified.len != ctx.res.body.len { |
| 76 | ctx.res.body = minified |
| 77 | ctx.res.header.set(.content_length, ctx.res.body.len.str()) |
| 78 | } |
| 79 | return true |
| 80 | } |
| 81 | |
| 82 | fn strip_intertag_whitespace(s string) string { |
| 83 | mut out := []u8{cap: s.len} |
| 84 | mut i := 0 |
| 85 | mut preserve_whitespace_depth := 0 |
| 86 | for i < s.len { |
| 87 | ch := s[i] |
| 88 | if ch == `<` { |
| 89 | tag_end := html_tag_end(s, i) |
| 90 | if tag_end == -1 { |
| 91 | out << ch |
| 92 | i++ |
| 93 | continue |
| 94 | } |
| 95 | tag_name, closing, self_closing := html_tag_info(s, i, tag_end) |
| 96 | compact_tag := compact_html_tag(s, i, tag_end) |
| 97 | for k := 0; k < compact_tag.len; k++ { |
| 98 | out << compact_tag[k] |
| 99 | } |
| 100 | if preserves_html_whitespace(tag_name) { |
| 101 | if closing { |
| 102 | if preserve_whitespace_depth > 0 { |
| 103 | preserve_whitespace_depth-- |
| 104 | } |
| 105 | } else if !self_closing { |
| 106 | preserve_whitespace_depth++ |
| 107 | } |
| 108 | } |
| 109 | i = tag_end + 1 |
| 110 | continue |
| 111 | } |
| 112 | if is_html_space(ch) { |
| 113 | mut j := i + 1 |
| 114 | mut has_indentation := ch != ` ` |
| 115 | for j < s.len && is_html_space(s[j]) { |
| 116 | if s[j] != ` ` { |
| 117 | has_indentation = true |
| 118 | } |
| 119 | j++ |
| 120 | } |
| 121 | prev_is_tag_end := out.len > 0 && out[out.len - 1] == `>` |
| 122 | next_is_tag_start := j < s.len && s[j] == `<` |
| 123 | should_strip := preserve_whitespace_depth == 0 |
| 124 | && ((prev_is_tag_end && next_is_tag_start) |
| 125 | || (has_indentation && (prev_is_tag_end || next_is_tag_start))) |
| 126 | if should_strip { |
| 127 | i = j |
| 128 | continue |
| 129 | } |
| 130 | if preserve_whitespace_depth == 0 && has_indentation { |
| 131 | out << ` ` |
| 132 | } else { |
| 133 | for k := i; k < j; k++ { |
| 134 | out << s[k] |
| 135 | } |
| 136 | } |
| 137 | i = j |
| 138 | continue |
| 139 | } |
| 140 | out << ch |
| 141 | i++ |
| 142 | } |
| 143 | return out.bytestr() |
| 144 | } |
| 145 | |
| 146 | fn compact_html_tag(s string, start int, end int) string { |
| 147 | mut out := []u8{cap: end - start + 1} |
| 148 | mut i := start |
| 149 | for i <= end { |
| 150 | ch := s[i] |
| 151 | if ch == `"` || ch == `'` { |
| 152 | quote := ch |
| 153 | out << ch |
| 154 | mut value_end := i + 1 |
| 155 | for value_end <= end && s[value_end] != quote { |
| 156 | value_end++ |
| 157 | } |
| 158 | if value_end <= end { |
| 159 | mut value_start := i + 1 |
| 160 | mut value_finish := value_end |
| 161 | for value_start < value_finish && is_html_space(s[value_start]) { |
| 162 | value_start++ |
| 163 | } |
| 164 | for value_finish > value_start && is_html_space(s[value_finish - 1]) { |
| 165 | value_finish-- |
| 166 | } |
| 167 | for k := value_start; k < value_finish; k++ { |
| 168 | out << s[k] |
| 169 | } |
| 170 | out << quote |
| 171 | i = value_end + 1 |
| 172 | continue |
| 173 | } |
| 174 | } |
| 175 | out << ch |
| 176 | i++ |
| 177 | } |
| 178 | return out.bytestr() |
| 179 | } |
| 180 | |
| 181 | fn html_tag_end(s string, start int) int { |
| 182 | mut quote := u8(0) |
| 183 | for i := start + 1; i < s.len; i++ { |
| 184 | ch := s[i] |
| 185 | if quote != 0 { |
| 186 | if ch == quote { |
| 187 | quote = 0 |
| 188 | } |
| 189 | } else if ch == `"` || ch == `'` { |
| 190 | quote = ch |
| 191 | } else if ch == `>` { |
| 192 | return i |
| 193 | } |
| 194 | } |
| 195 | return -1 |
| 196 | } |
| 197 | |
| 198 | fn html_tag_info(s string, start int, end int) (string, bool, bool) { |
| 199 | mut i := start + 1 |
| 200 | mut closing := false |
| 201 | if i < end && s[i] == `/` { |
| 202 | closing = true |
| 203 | i++ |
| 204 | } |
| 205 | for i < end && is_html_space(s[i]) { |
| 206 | i++ |
| 207 | } |
| 208 | name_start := i |
| 209 | for i < end && is_html_tag_name_char(s[i]) { |
| 210 | i++ |
| 211 | } |
| 212 | name := s[name_start..i].to_lower() |
| 213 | mut j := end - 1 |
| 214 | for j > start && is_html_space(s[j]) { |
| 215 | j-- |
| 216 | } |
| 217 | self_closing := !closing && j > start && s[j] == `/` |
| 218 | return name, closing, self_closing |
| 219 | } |
| 220 | |
| 221 | fn preserves_html_whitespace(tag_name string) bool { |
| 222 | return tag_name in ['s', 'pre', 'textarea', 'script', 'style'] |
| 223 | } |
| 224 | |
| 225 | fn is_html_tag_name_char(ch u8) bool { |
| 226 | return (ch >= `a` && ch <= `z`) || (ch >= `A` && ch <= `Z`) |
| 227 | || (ch >= `0` && ch <= `9`) || ch == `-` || ch == `_` || ch == `:` |
| 228 | } |
| 229 | |
| 230 | fn is_html_space(ch u8) bool { |
| 231 | return ch == ` ` || ch == `\n` || ch == `\t` || ch == `\r` |
| 232 | } |
| 233 | |