From d13e89cbbdda9722fc636b0666adce58501d1c9b Mon Sep 17 00:00:00 2001 From: Uko Kokņevičs Date: Sun, 2 Jan 2022 08:38:11 +0200 Subject: Some changes in Syntax --- src/Buffer.zig | 18 ++----- src/Row.zig | 54 +++++++++----------- src/Syntax.zig | 39 +++++++++++--- src/Syntax/makefile.zig | 133 ++++++++++++++++++++++++++---------------------- src/Syntax/zig.zig | 95 ++++++++++++++++++---------------- 5 files changed, 183 insertions(+), 156 deletions(-) diff --git a/src/Buffer.zig b/src/Buffer.zig index 7afdb05..ce2212c 100644 --- a/src/Buffer.zig +++ b/src/Buffer.zig @@ -529,20 +529,10 @@ pub fn selectSyntaxHighlighting(self: *Buffer) !void { else self.short_name; - const ext = if (std.mem.lastIndexOfScalar(u8, name, '.')) |idx| name[idx..] else null; - for (Syntax.database) |syntax| { - for (syntax.filematch) |filematch| { - const is_ext = filematch[0] == '.'; - if ((is_ext and ext != null and std.mem.eql(u8, ext.?, filematch)) - or (!is_ext and std.mem.eql(u8, name, filematch))) { - self.syntax = syntax; - - for (self.rows.items) |*row| { - try row.updateSyntax(self); - } - - return; - } + self.syntax = Syntax.chooseSyntax(name); + if (self.syntax == null) { + if (std.mem.lastIndexOfScalar(u8, name, '.')) |idx| { + self.syntax = Syntax.chooseSyntax(name[idx..]); } } } diff --git a/src/Row.zig b/src/Row.zig index 38fb72b..a47be6a 100644 --- a/src/Row.zig +++ b/src/Row.zig @@ -149,14 +149,12 @@ pub fn updateSyntax(self: *Row, buf: *Buffer) UpdateSyntaxError!void { } const syntax = buf.syntax.?; - const kw1 = syntax.keywords1; - const kw2 = syntax.keywords2; - var after_sep = true; var in_comment = if (self.idx > 0) buf.rows.items[self.idx - 1].ends_with_open_comment else false; var curr_str_quote: ?u8 = null; var i: usize = 0; + var last_sep: usize = 0; main_loop: while (i < self.rdata.items.len) { const prev_hl = if (i > 0) self.hldata.items[i - 1] else .normal; @@ -165,7 +163,7 @@ pub fn updateSyntax(self: *Row, buf: *Buffer) UpdateSyntaxError!void { if (curr_str_quote == null and !in_comment and scs.len + i <= self.rdata.items.len) { if (std.mem.eql(u8, scs, self.rdata.items[i..(i + scs.len)])) { std.mem.set(Highlight, self.hldata.items[i..], .comment); - break; + break :main_loop; } } } @@ -181,16 +179,16 @@ pub fn updateSyntax(self: *Row, buf: *Buffer) UpdateSyntaxError!void { std.mem.set(Highlight, self.hldata.items[i..(i + mce.len)], .comment_ml); i += mce.len; in_comment = false; - after_sep = true; + last_sep = i; } else { i += 1; - continue; + continue :main_loop; } } else if (mcs.len + i <= self.rdata.items.len and std.mem.eql(u8, mcs, self.rdata.items[i..(i + mcs.len)])) { std.mem.set(Highlight, self.hldata.items[i..(i + mcs.len)], .comment_ml); i += mcs.len; in_comment = true; - continue; + continue :main_loop; } } } @@ -208,54 +206,50 @@ pub fn updateSyntax(self: *Row, buf: *Buffer) UpdateSyntaxError!void { i += 1; } else if (c == quote) { curr_str_quote = null; - after_sep = true; + last_sep = i; } - continue; + continue :main_loop; } else { // TODO: Move this to syntax struct if (c == '"' or c == '\'') { curr_str_quote = c; self.hldata.items[i] = .string; i += 1; - continue; + continue :main_loop; } } } if (syntax.flags.hl_numbers) { - if ((std.ascii.isDigit(c) and (after_sep or prev_hl == .number)) or (c == '.' and prev_hl == .number)) { - after_sep = false; + if ((std.ascii.isDigit(c) and (last_sep == i or prev_hl == .number)) + or (c == '.' and prev_hl == .number) + ) { self.hldata.items[i] = .number; i += 1; - continue; + continue :main_loop; } } - if (after_sep) { - for (kw1) |kw| { - if (i + kw.len <= self.rdata.items.len and std.mem.eql(u8, kw, self.rdata.items[i..(i + kw.len)]) and (i + kw.len == self.rdata.items.len or syntax.isSeparator(self.rdata.items[i + kw.len]))) { - std.mem.set(Highlight, self.hldata.items[i..(i + kw.len)], .keyword1); - i += kw.len; - after_sep = false; - continue :main_loop; - } + if (syntax.isSeparator(c)) { + const id = self.rdata.items[last_sep..i]; + if (syntax.keyword_classifier(id)) |hl| { + std.mem.set(Highlight, self.hldata.items[last_sep..i], hl); } - for (kw2) |kw| { - if (i + kw.len <= self.rdata.items.len and std.mem.eql(u8, kw, self.rdata.items[i..(i + kw.len)]) and (i + kw.len == self.rdata.items.len or syntax.isSeparator(self.rdata.items[i + kw.len]))) { - std.mem.set(Highlight, self.hldata.items[i..(i + kw.len)], .keyword2); - i += kw.len; - after_sep = false; - continue :main_loop; - } - } + last_sep = i + 1; } - after_sep = syntax.isSeparator(c); i += 1; } + if (!in_comment) { + const id = self.rdata.items[last_sep..self.rdata.items.len]; + if (syntax.keyword_classifier(id)) |hl| { + std.mem.set(Highlight, self.hldata.items[last_sep..self.rdata.items.len], hl); + } + } + if (in_comment != self.ends_with_open_comment) { self.ends_with_open_comment = in_comment; if (self.idx + 1 < buf.rows.items.len) { diff --git a/src/Syntax.zig b/src/Syntax.zig index f29c7fc..6858027 100644 --- a/src/Syntax.zig +++ b/src/Syntax.zig @@ -1,14 +1,18 @@ pub const makefile = @import("Syntax/makefile.zig"); pub const zig = @import("Syntax/zig.zig"); +const es = @import("root"); const std = @import("std"); +const ComptimeStringMap = std.ComptimeStringMap; +const Highlight = es.Highlight; const Syntax = @This(); -pub const database = [_]Syntax{ - makefile.syntax, - zig.syntax, -}; +pub const chooseSyntax = ComptimeStringMap( + Syntax, + pairWith(&makefile.filematch, makefile.syntax) + ++ pairWith(&zig.filematch, zig.syntax), +).get; pub const Flags = struct { hl_numbers: bool = false, @@ -16,10 +20,7 @@ pub const Flags = struct { }; name: []const u8, -// TODO: Make these into comptime StringSets, see std.ComptimeStringMap -filematch: []const []const u8, -keywords1: []const []const u8, -keywords2: []const []const u8, +keyword_classifier: fn([]const u8) ?Highlight, singleline_comment_start: ?[]const u8, multiline_comment_start: ?[]const u8, multiline_comment_end: ?[]const u8, @@ -29,3 +30,25 @@ flags: Flags, pub fn isSeparator(self: Syntax, char: u8) bool { return std.ascii.isSpace(char) or std.mem.indexOfScalar(u8, self.separators, char) != null; } + +pub fn pairWith( + comptime keys: []const []const u8, + comptime value: anytype, +) [keys.len]KeyValue(@TypeOf(value)) { + @setEvalBranchQuota(20000); + + var pairs = [_]KeyValue(@TypeOf(value)) {undefined} ** keys.len; + for (keys) |key, i| { + pairs[i] = .{ .@"0" = key, .@"1" = value }; + } + + return pairs; +} + +fn KeyValue(comptime V: type) type { + return struct { + @"0": []const u8, + @"1": V, + }; +} + diff --git a/src/Syntax/makefile.zig b/src/Syntax/makefile.zig index 5c93df4..6ae7386 100644 --- a/src/Syntax/makefile.zig +++ b/src/Syntax/makefile.zig @@ -1,78 +1,89 @@ // zig fmt: off const es = @import("root"); +const std = @import("std"); +const ComptimeStringMap = std.ComptimeStringMap; +const Highlight = es.Highlight; const Syntax = es.Syntax; +pub const filematch = [_][]const u8{ + "GNUmakefile", "makefile", "Makefile", + + ".mk", +}; + pub const syntax = Syntax{ .name = "Makefile", - .filematch = &[_][]const u8{ "GNUmakefile", "makefile", "Makefile", ".mk" }, - .keywords1 = &[_][]const u8{ - "$@", "$(@D)", "$(@F)", - "$%", "$(%D)", "$(%F)", - "$<", "$(