diff options
| author | 2021-12-21 05:56:41 +0200 | |
|---|---|---|
| committer | 2021-12-21 05:56:41 +0200 | |
| commit | 2d2278364b6186c6cdf0f0497b0498431dfe7dd1 (patch) | |
| tree | 8f2329afbc90817c855f5c5154a547a58a9458aa /src/Row.zig | |
| download | es-2d2278364b6186c6cdf0f0497b0498431dfe7dd1.tar.gz es-2d2278364b6186c6cdf0f0497b0498431dfe7dd1.tar.xz es-2d2278364b6186c6cdf0f0497b0498431dfe7dd1.zip | |
Initial config
Diffstat (limited to 'src/Row.zig')
| -rw-r--r-- | src/Row.zig | 273 |
1 files changed, 273 insertions, 0 deletions
diff --git a/src/Row.zig b/src/Row.zig new file mode 100644 index 0000000..633e338 --- /dev/null +++ b/src/Row.zig | |||
| @@ -0,0 +1,273 @@ | |||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | const Allocator = std.mem.Allocator; | ||
| 4 | const ArrayList = std.ArrayList; | ||
| 5 | const Buffer = @import("Buffer.zig"); | ||
| 6 | const Config = @import("Config.zig"); | ||
| 7 | const Highlight = @import("highlight.zig").Highlight; | ||
| 8 | const Row = @This(); | ||
| 9 | const StringBuilder = @import("StringBuilder.zig"); | ||
| 10 | |||
| 11 | allocator: Allocator, | ||
| 12 | |||
| 13 | idx: usize, | ||
| 14 | |||
| 15 | data: ArrayList(u8), | ||
| 16 | rdata: ArrayList(u8), | ||
| 17 | hldata: ArrayList(Highlight), | ||
| 18 | |||
| 19 | ends_with_open_comment: bool, | ||
| 20 | |||
| 21 | pub fn init(allocator: Allocator, idx: usize, data: []const u8) !Row { | ||
| 22 | var self = Row{ | ||
| 23 | .allocator = allocator, | ||
| 24 | |||
| 25 | .idx = idx, | ||
| 26 | |||
| 27 | .data = ArrayList(u8).init(allocator), | ||
| 28 | .rdata = ArrayList(u8).init(allocator), | ||
| 29 | .hldata = ArrayList(Highlight).init(allocator), | ||
| 30 | |||
| 31 | .ends_with_open_comment = false, | ||
| 32 | }; | ||
| 33 | errdefer self.deinit(); | ||
| 34 | |||
| 35 | try self.data.appendSlice(data); | ||
| 36 | return self; | ||
| 37 | } | ||
| 38 | |||
| 39 | pub fn deinit(self: Row) void { | ||
| 40 | self.data.deinit(); | ||
| 41 | self.rdata.deinit(); | ||
| 42 | self.hldata.deinit(); | ||
| 43 | } | ||
| 44 | |||
| 45 | pub fn appendString(self: *Row, buf: *Buffer, str: []const u8) !void { | ||
| 46 | try self.data.appendSlice(str); | ||
| 47 | return self.update(buf); | ||
| 48 | } | ||
| 49 | |||
| 50 | pub fn cleanWhiteSpace(self: *Row, buf: *Buffer) !void { | ||
| 51 | const orig_len = self.data.items.len; | ||
| 52 | while (self.data.items.len > 0) { | ||
| 53 | if (std.ascii.isBlank(self.data.items[self.data.items.len - 1])) { | ||
| 54 | _ = self.data.pop(); | ||
| 55 | } else { | ||
| 56 | break; | ||
| 57 | } | ||
| 58 | } | ||
| 59 | |||
| 60 | if (orig_len != self.data.items.len) { | ||
| 61 | buf.dirty = true; | ||
| 62 | try self.update(buf); | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | pub fn cxToRx(self: Row, config: Config, cx: usize) usize { | ||
| 67 | var rx: usize = 0; | ||
| 68 | var i: usize = 0; | ||
| 69 | while (i < cx) : (i += 1) { | ||
| 70 | if (self.data.items[i] == '\t') { | ||
| 71 | rx += config.tab_stop - (rx % config.tab_stop); | ||
| 72 | } else { | ||
| 73 | rx += 1; | ||
| 74 | } | ||
| 75 | } | ||
| 76 | |||
| 77 | return rx; | ||
| 78 | } | ||
| 79 | |||
| 80 | pub fn deleteChar(self: *Row, buf: *Buffer, at: usize) !void { | ||
| 81 | _ = self.data.orderedRemove(at); | ||
| 82 | try self.update(buf); | ||
| 83 | } | ||
| 84 | |||
| 85 | pub fn indentation(self: Row, allocator: Allocator) ![]u8 { | ||
| 86 | var str = ArrayList(u8).init(allocator); | ||
| 87 | defer str.deinit(); | ||
| 88 | |||
| 89 | var idx: usize = 0; | ||
| 90 | while (idx < self.data.items.len) : (idx += 1) { | ||
| 91 | if (!std.ascii.isBlank(self.data.items[idx])) { | ||
| 92 | break; | ||
| 93 | } | ||
| 94 | } | ||
| 95 | |||
| 96 | try str.appendSlice(self.data.items[0..idx]); | ||
| 97 | return str.toOwnedSlice(); | ||
| 98 | } | ||
| 99 | |||
| 100 | pub fn insertChar(self: *Row, buf: *Buffer, at: usize, char: u8) !void { | ||
| 101 | try self.data.insert(at, char); | ||
| 102 | try self.update(buf); | ||
| 103 | } | ||
| 104 | |||
| 105 | pub fn rxToCx(self: Row, config: Config, rx: usize) usize { | ||
| 106 | if (rx == 0) { | ||
| 107 | return 0; | ||
| 108 | } | ||
| 109 | |||
| 110 | var cur_rx: usize = 0; | ||
| 111 | for (self.data.items) |char, cx| { | ||
| 112 | if (char == '\t') { | ||
| 113 | cur_rx += config.tab_stop - (cur_rx % config.tab_stop); | ||
| 114 | } else { | ||
| 115 | cur_rx += 1; | ||
| 116 | } | ||
| 117 | |||
| 118 | if (cur_rx >= rx) { | ||
| 119 | return cx + 1; | ||
| 120 | } | ||
| 121 | } | ||
| 122 | |||
| 123 | return self.data.items.len; | ||
| 124 | } | ||
| 125 | |||
| 126 | // TODO: I don't like that this is modifying both row and buffer (parent of row) | ||
| 127 | pub fn update(self: *Row, buf: *Buffer) !void { | ||
| 128 | self.rdata.clearRetainingCapacity(); | ||
| 129 | |||
| 130 | for (self.data.items) |char| { | ||
| 131 | if (char == '\t') { | ||
| 132 | const len = buf.config.tab_stop - self.rdata.items.len % buf.config.tab_stop; | ||
| 133 | try self.rdata.appendNTimes(' ', len); | ||
| 134 | } else { | ||
| 135 | try self.rdata.append(char); | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 | try self.updateSyntax(buf); | ||
| 140 | } | ||
| 141 | |||
| 142 | const UpdateSyntaxError = std.mem.Allocator.Error; | ||
| 143 | pub fn updateSyntax(self: *Row, buf: *Buffer) UpdateSyntaxError!void { | ||
| 144 | try self.hldata.resize(self.rdata.items.len); | ||
| 145 | std.mem.set(Highlight, self.hldata.items, .normal); | ||
| 146 | if (buf.syntax == null) { | ||
| 147 | return; | ||
| 148 | } | ||
| 149 | |||
| 150 | const syntax = buf.syntax.?; | ||
| 151 | const kw1 = syntax.keywords1; | ||
| 152 | const kw2 = syntax.keywords2; | ||
| 153 | |||
| 154 | var after_sep = true; | ||
| 155 | var in_comment = if (self.idx > 0) buf.rows.items[self.idx - 1].ends_with_open_comment else false; | ||
| 156 | var curr_str_quote: ?u8 = null; | ||
| 157 | |||
| 158 | var i: usize = 0; | ||
| 159 | main_loop: while (i < self.rdata.items.len) { | ||
| 160 | const prev_hl = if (i > 0) self.hldata.items[i - 1] else .normal; | ||
| 161 | |||
| 162 | if (syntax.singleline_comment_start) |scs| { | ||
| 163 | std.debug.assert(scs.len != 0); | ||
| 164 | if (curr_str_quote == null and !in_comment and scs.len + i <= self.rdata.items.len) { | ||
| 165 | if (std.mem.eql(u8, scs, self.rdata.items[i .. (i + scs.len)])) { | ||
| 166 | std.mem.set(Highlight, self.hldata.items[i..], .comment); | ||
| 167 | break; | ||
| 168 | } | ||
| 169 | } | ||
| 170 | } | ||
| 171 | |||
| 172 | if (syntax.multiline_comment_start) |mcs| { | ||
| 173 | std.debug.assert(mcs.len != 0); | ||
| 174 | if (syntax.multiline_comment_end) |mce| { | ||
| 175 | std.debug.assert(mce.len != 0); | ||
| 176 | if (curr_str_quote == null) { | ||
| 177 | if (in_comment) { | ||
| 178 | self.hldata.items[i] = .comment_ml; | ||
| 179 | if (mce.len + i <= self.rdata.items.len | ||
| 180 | and std.mem.eql(u8, mce, self.rdata.items[i .. (i + mce.len)]) | ||
| 181 | ) { | ||
| 182 | std.mem.set(Highlight, self.hldata.items[i .. (i + mce.len)], .comment_ml); | ||
| 183 | i += mce.len; | ||
| 184 | in_comment = false; | ||
| 185 | after_sep = true; | ||
| 186 | } else { | ||
| 187 | i += 1; | ||
| 188 | continue; | ||
| 189 | } | ||
| 190 | } else if (mcs.len + i <= self.rdata.items.len | ||
| 191 | and std.mem.eql(u8, mcs, self.rdata.items[i .. (i + mcs.len)])) { | ||
| 192 | std.mem.set(Highlight, self.hldata.items[i .. (i + mcs.len)], .comment_ml); | ||
| 193 | i += mcs.len; | ||
| 194 | in_comment = true; | ||
| 195 | continue; | ||
| 196 | } | ||
| 197 | } | ||
| 198 | |||
| 199 | } | ||
| 200 | } | ||
| 201 | |||
| 202 | const c = self.rdata.items[i]; | ||
| 203 | |||
| 204 | if (syntax.flags.hl_strings) { | ||
| 205 | if (curr_str_quote) |quote| { | ||
| 206 | self.hldata.items[i] = .string; | ||
| 207 | i += 1; | ||
| 208 | // Pretty dumb way of detecting \" or \' but it works \shrug/ | ||
| 209 | if (c == '\\' and i < self.rdata.items.len) { | ||
| 210 | self.hldata.items[i] = .string; | ||
| 211 | i += 1; | ||
| 212 | } else if (c == quote) { | ||
| 213 | curr_str_quote = null; | ||
| 214 | after_sep = true; | ||
| 215 | } | ||
| 216 | |||
| 217 | continue; | ||
| 218 | } else { | ||
| 219 | // TODO: Move this to syntax struct | ||
| 220 | if (c == '"' or c == '\'') { | ||
| 221 | curr_str_quote = c; | ||
| 222 | self.hldata.items[i] = .string; | ||
| 223 | i += 1; | ||
| 224 | continue; | ||
| 225 | } | ||
| 226 | } | ||
| 227 | } | ||
| 228 | |||
| 229 | if (syntax.flags.hl_numbers) { | ||
| 230 | if ((std.ascii.isDigit(c) and (after_sep or prev_hl == .number)) | ||
| 231 | or (c == '.' and prev_hl == .number)) { | ||
| 232 | after_sep = false; | ||
| 233 | self.hldata.items[i] = .number; | ||
| 234 | i += 1; | ||
| 235 | continue; | ||
| 236 | } | ||
| 237 | } | ||
| 238 | |||
| 239 | if (after_sep) { | ||
| 240 | for (kw1) |kw| { | ||
| 241 | if (i + kw.len <= self.rdata.items.len | ||
| 242 | and std.mem.eql(u8, kw, self.rdata.items[i .. (i + kw.len)]) | ||
| 243 | and (i + kw.len == self.rdata.items.len or syntax.isSeparator(self.rdata.items[i + kw.len]))) { | ||
| 244 | std.mem.set(Highlight, self.hldata.items[i .. (i + kw.len)], .keyword1); | ||
| 245 | i += kw.len; | ||
| 246 | after_sep = false; | ||
| 247 | continue :main_loop; | ||
| 248 | } | ||
| 249 | } | ||
| 250 | |||
| 251 | for (kw2) |kw| { | ||
| 252 | if (i + kw.len <= self.rdata.items.len | ||
| 253 | and std.mem.eql(u8, kw, self.rdata.items[i .. (i + kw.len)]) | ||
| 254 | and (i + kw.len == self.rdata.items.len or syntax.isSeparator(self.rdata.items[i + kw.len]))) { | ||
| 255 | std.mem.set(Highlight, self.hldata.items[i .. (i + kw.len)], .keyword2); | ||
| 256 | i += kw.len; | ||
| 257 | after_sep = false; | ||
| 258 | continue :main_loop; | ||
| 259 | } | ||
| 260 | } | ||
| 261 | } | ||
| 262 | |||
| 263 | after_sep = syntax.isSeparator(c); | ||
| 264 | i += 1; | ||
| 265 | } | ||
| 266 | |||
| 267 | if (in_comment != self.ends_with_open_comment) { | ||
| 268 | self.ends_with_open_comment = in_comment; | ||
| 269 | if (self.idx + 1 < buf.rows.items.len) { | ||
| 270 | try buf.rows.items[self.idx + 1].updateSyntax(buf); | ||
| 271 | } | ||
| 272 | } | ||
| 273 | } | ||