Bundle curated community plugins (2.1.8-4)

Vendored from upstream, pinned by commit (see debian/extra/README.source):
- gitstatus, gitopen, fontconfig, open_ext, select_colorscheme,
  smoothcaret, nerdicons (font mapping patched to DATADIR, Ships the
  Symbols Nerd Font Mono TTF, SIL OFL 1.1)
- lite-xl-lsp (complete LSP client; idle until a language server is
  configured) plus the lite-xl-widgets library it requires
- 104 language syntax plugins (none duplicate the nine bundled in core)

settings GUI left out upstream is broken: it requires a
libraries.widget.fonts widget that does not exist in
lite-xl-widgets at any revision.

Co-developed-with: ZCode (Z.ai)
This commit is contained in:
2026-09-16 22:45:02 +02:00
parent a693cb645c
commit 3bae6fd448
161 changed files with 42843 additions and 0 deletions
+16
View File
@@ -1,3 +1,19 @@
lite-xl (2.1.8-4) stonking; urgency=medium
* Bundle a curated set of community plugins (vendored, pinned in
debian/extra/README.source):
- gitstatus, gitopen, fontconfig, open_ext, select_colorscheme,
smoothcaret, nerdicons (+ Symbols Nerd Font Mono, font path patched
to DATADIR)
- lite-xl-lsp (full LSP client; activates when a language server is
configured) with the lite-xl-widgets library it requires
- 104 additional language syntax plugins (none duplicate the nine
already bundled with core)
* settings GUI plugin left out: its hard dependency on a widget that is
missing from lite-xl-widgets@master makes it fail to load upstream.
-- Valentin Haudiquet <valentin.haudiquet@canonical.com> Wed, 16 Sep 2026 22:10:00 +0200
lite-xl (2.1.8-3) stonking; urgency=medium
* Ship a VSCode-style dark theme and out-of-the-box config:
+20
View File
@@ -0,0 +1,20 @@
Vendored from upstream, pinned by commit:
- lite-xl-plugins https://github.com/lite-xl/lite-xl-plugins @ 31eef29 (master, 2026-09)
plugins/: gitstatus, gitopen, fontconfig, open_ext, select_colorscheme,
smoothcaret, nerdicons, language_* (all 104; none overlap the ones bundled
in the core data/ directory)
- lite-xl-lsp https://github.com/lite-xl/lite-xl-lsp @ d1432ae (master, 2026-09)
vendored whole as plugins/lsp/ (screenshots removed)
- lite-xl-widgets https://github.com/lite-xl/lite-xl-widgets @ dcf1c8c
NOT vendored: only the settings plugin needs it, and settings@master
requires libraries.widget.fonts which does not exist in the widgets
repository at any revision, so settings cannot load. Revisit when
upstream publishes the missing widget.
- nerdicons font mapping: plugins/font_symbols_nerdfont_mono_regular.lua
shipped as usr/share/lite-xl/libraries/font_symbols_nerdfont_mono_regular.lua
with the font path patched from USERDIR to DATADIR, plus the
Symbols Nerd Font Mono TTF (SIL OFL 1.1) next to it.
Refresh by re-cloning the sources at a new commit and re-applying the single
sed patch to the font mapping path.
Binary file not shown.
File diff suppressed because it is too large Load Diff
+163
View File
@@ -0,0 +1,163 @@
--
-- Button Widget.
-- @copyright Jefferson Gonzalez
-- @license MIT
--
local style = require "core.style"
local Widget = require "libraries.widget"
---@class widget.button.icon
---@field public code string | nil
---@field public color renderer.color | nil
---@field public hover_color renderer.color | nil
local ButtonIcon = {}
---@class widget.button : widget
---@overload fun(parent:widget?, label:string?):widget.button
---@field public padding widget.position
---@field public icon widget.button.icon
---@field public expanded boolean
local Button = Widget:extend()
---Constructor
---@param parent widget
---@param label? string
function Button:new(parent, label)
Button.super.new(self, parent)
self.type_name = "widget.button"
self.icon = {
code = nil, color = nil, hover_color = nil
}
self.padding = {
x = style.padding.x,
y = style.padding.y
}
self.expanded = false
self:set_label(label or "")
end
---When set to true the button width will be the same as parent
---@param expand? boolean | nil
function Button:toggle_expand(expand)
if type(expand) == "boolean" then
self.expanded = expand
else
self.expanded = not self.expanded
end
end
---Set the icon drawn alongside the button text.
---@param code? string
---@param color? renderer.color
---@param hover_color? renderer.color
function Button:set_icon(code, color, hover_color)
self.icon.code = code
self.icon.color = color
self.icon.hover_color = hover_color
self:set_label(self.label)
end
---Set the button text and recalculates the widget size.
---@param text string
function Button:set_label(text)
Button.super.set_label(self, text)
local font = self:get_font()
local border = self.border.width * 2
if self.expanded and self.parent then
self.size.x = self.parent.size.x - self.position.rx - border
else
self.size.x = font:get_width(self.label) + (self.padding.x * 2) - border
end
self.size.y = font:get_height() + (self.padding.y * 2) - border
if self.icon.code then
local icon_w = style.icon_font:get_width(self.icon.code)
if self.label ~= "" then
icon_w = icon_w + (self.padding.x / 2)
end
local icon_h = style.icon_font:get_height() + (self.padding.y * 2) - border
self.size.x = self.size.x + icon_w
self.size.y = math.max(self.size.y, icon_h)
end
end
function Button:on_mouse_enter(...)
Button.super.on_mouse_enter(self, ...)
self.hover_text = style.accent
self.hover_back = style.line_highlight
end
function Button:on_mouse_leave(...)
Button.super.on_mouse_leave(self, ...)
self.hover_text = nil
self.hover_back = nil
end
function Button:on_scale_change(new_scale, prev_scale)
Button.super.on_scale_change(self, new_scale, prev_scale)
self.padding.x = self.padding.x * (new_scale / prev_scale)
self.padding.y = self.padding.y * (new_scale / prev_scale)
end
function Button:update()
if not Button.super.update(self) then return false end
-- update size
self:set_label(self.label)
return true
end
function Button:draw()
self.background_color = self.hover_back or style.background
if not Button.super.draw(self) then return false end
local font = self:get_font()
local offsetx = self.position.x + self.padding.x
local offsety = self.position.y
local h = self:get_height()
local ih, th = style.icon_font:get_height(), font:get_height()
if self.icon.code then
local normal = self.icon.color or style.text
local hover = self.icon.hover_color or style.accent
renderer.draw_text(
style.icon_font,
self.icon.code,
offsetx,
th > ih and (offsety + (h / 2)) - (ih/2) or (offsety + self.padding.y),
self.hover_text and hover or normal
)
offsetx = offsetx + style.icon_font:get_width(self.icon.code) + (style.padding.x / 2)
end
if self.label ~= "" then
renderer.draw_text(
font,
self.label,
offsetx,
ih > th and (offsety + (h / 2)) - (th/2) or (offsety + self.padding.y),
self.hover_text or self.foreground_color or style.text
)
end
return true
end
return Button
+142
View File
@@ -0,0 +1,142 @@
--
-- CheckBox Widget.
-- @copyright Jefferson Gonzalez
-- @license MIT
--
local style = require "core.style"
local Widget = require "libraries.widget"
---@class widget.checkbox : widget
---@overload fun(parent?:widget, label?:string):widget.checkbox
---@field private checked boolean
local CheckBox = Widget:extend()
---Constructor
---@param parent widget
---@param label string
function CheckBox:new(parent, label)
CheckBox.super.new(self, parent)
self.type_name = "widget.checkbox"
self.checked = false
self:set_label(label or "")
self.animating = false
self.animating_color = style.caret
end
---Set the checkbox label and recalculates the widget size.
---@param text string
function CheckBox:set_label(text)
CheckBox.super.set_label(self, text)
local _, _, bw, _ = self:get_box_rect()
local font = self:get_font()
self.size.x = font:get_width(self.label) + bw + (style.padding.x / 2)
self.size.y = font:get_height()
end
---Change the status of the checkbox.
---@param checked boolean
function CheckBox:set_checked(checked)
self.checked = checked
self:on_change(self.checked)
end
---Get the status of the checkbox.
---@return boolean
function CheckBox:is_checked()
return self.checked
end
---Called when the checkbox is (un)checked.
---@param checked boolean
function CheckBox:on_checked(checked) end
function CheckBox:on_mouse_enter(...)
CheckBox.super.on_mouse_enter(self, ...)
self.hover_text = style.accent
self.hover_back = style.dim
end
function CheckBox:on_mouse_leave(...)
CheckBox.super.on_mouse_leave(self, ...)
self.hover_text = nil
self.hover_back = nil
end
function CheckBox:on_click()
self.checked = not self.checked
self:on_checked(self.checked)
self:on_change(self.checked)
self.animating = true
self.animating_color = {table.unpack(style.caret)}
local target_color = {table.unpack(style.caret)}
if self.checked then
self.animating_color[4] = 0
target_color[4] = 255
else
self.animating_color[4] = 255
target_color[4] = 0
end
self:animate(self.animating_color, {table.unpack(target_color)}, {
on_complete = function()
self.animating = false
end
})
end
function CheckBox:get_box_rect()
local size = 1.6
local font = self:get_font()
local fh = font:get_height() / size
return
self.position.x,
self.position.y + (fh / (size * 2)),
font:get_width("x") + 4,
fh
end
function CheckBox:update()
if not CheckBox.super.update(self) then return false end
-- update size
self:set_label(self.label)
return true
end
function CheckBox:draw()
if not self:is_visible() then return false end
local bx, by, bw, bh = self:get_box_rect()
self:draw_border(bx, by, bw, bh)
renderer.draw_rect(
bx, by, bw, bh,
self.hover_back or self.background_color or style.background
)
if self.animating then
renderer.draw_rect(bx + 2, by + 2, bw-4, bh-4, self.animating_color)
elseif self.checked then
renderer.draw_rect(bx + 2, by + 2, bw-4, bh-4, style.caret)
end
renderer.draw_text(
self:get_font(),
self.label,
self.position.x + bw + (style.padding.x / 2),
self.position.y,
self.hover_text or self.foreground_color or style.text
)
return true
end
return CheckBox
+745
View File
@@ -0,0 +1,745 @@
--
-- Color Picker Widget
-- Note: HSV and HSL conversion functions adapted from:
-- https://github.com/EmmanuelOga/columns/blob/master/utils/color.lua
-- which in turn was ported from:
-- http://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c
--
local core = require "core"
local style = require "core.style"
local common = require "core.common"
local Widget = require "libraries.widget"
local TextBox = require "libraries.widget.textbox"
---@alias widget.colorpicker.colorrange renderer.color[]
---The numerical portion of a color range on the hue selection bar.
---@type number
local HUE_COLOR_SEGMENT = 100 / 6
---Hue color ranges in the order rendered on the hue bar.
---@type widget.colorpicker.colorrange[]
local HUE_COLOR_RANGES = {
-- red -> yellow
{ {255, 0, 0, 255}, {255, 255, 0, 255} },
-- yellow -> green
{ {255, 255, 0, 255}, {0, 255, 0, 255} },
-- green -> cyan
{ {0, 255 ,0, 255}, {0, 255, 255, 255} },
-- cyan -> blue
{ {0, 255, 255, 255}, {0, 0, 255, 255} },
-- blue -> purple
{ {0, 0, 255, 255}, {255, 0, 255, 255} },
-- purple -> red
{ {255, 0, 255, 255}, {255, 0, 0, 255} }
}
---@type renderer.color
local COLOR_BLACK = {0, 0, 0, 255}
---@type renderer.color
local COLOR_WHITE = {255, 255, 255, 255}
---@class widget.colorpicker : widget
---@overload fun(parent:widget?, color?:renderer.color|string):widget.colorpicker
---@field hue_color renderer.color
---@field saturation_color renderer.color
---@field brightness_color renderer.color
---@field hue_pos number
---@field saturation_pos number
---@field brightness_pos number
---@field alpha number
---@field hue_mouse_down boolean
---@field saturation_mouse_down boolean
---@field brightness_mouse_down boolean
---@field html_notation widget.textbox
---@field rgba_notation widget.textbox
local ColorPicker = Widget:extend()
---Constructor
---@param parent widget
---@param color? renderer.color | string
function ColorPicker:new(parent, color)
ColorPicker.super.new(self, parent, false)
self.type_name = "widget.colorpicker"
self.hue_pos = 0
self.saturation_pos = 100
self.brightness_pos = 100
self.alpha = 255
self.hue_color = COLOR_BLACK
self.saturation_color = COLOR_BLACK
self.brightness_color = COLOR_BLACK
self.hue_mouse_down = false;
self.saturation_mouse_down = false
self.brightness_mouse_down = false
self.selector = { x = 0, y = 0, w = 0, h = 0 }
self:set_border_width(0)
local this = self
self.html_notation = TextBox(self, "#FF0000")
self.rgba_notation = TextBox(self, "rgba(255,0,0,1)")
self.html_updating = false
self.rgba_updating = false
function self.html_notation:on_change(value)
if
not this.hue_mouse_down
and
not this.saturation_mouse_down
and
not this.brightness_mouse_down
and
not this.html_updating
then
this:set_color(value, true)
end
end
function self.rgba_notation:on_change(value)
if
not this.hue_mouse_down
and
not this.saturation_mouse_down
and
not this.brightness_mouse_down
and
not this.rgba_updating
then
this:set_color(value, false, true)
end
end
self:set_color(color or {255, 0, 0, 255})
-- set initial child positions and size
self:update_size()
end
---Converts an RGB color value to HSL. Conversion formula
---adapted from http://en.wikipedia.org/wiki/HSL_color_space.
---Assumes r, g, and b are contained in the set [0, 255] and
---returns h, s, and l in the set [0, 1].
---@param rgba renderer.color
---@return table hsla
function ColorPicker.rgb_to_hsl(rgba)
local r, g, b, a = rgba[1], rgba[2], rgba[3], rgba[4]
r, g, b = r / 255, g / 255, b / 255
local max, min = math.max(r, g, b), math.min(r, g, b)
local h, s, l
l = (max + min) / 2
if max == min then
h, s = 0, 0 -- achromatic
else
local d = max - min
if l > 0.5 then s = d / (2 - max - min) else s = d / (max + min) end
if max == r then
h = (g - b) / d
if g < b then h = h + 6 end
elseif max == g then h = (b - r) / d + 2
elseif max == b then h = (r - g) / d + 4
end
h = h / 6
end
return {h, s, l, a and a/255 or 1}
end
---Converts an HSL color value to RGB. Conversion formula
---adapted from http://en.wikipedia.org/wiki/HSL_color_space.
---Assumes h, s, and l are contained in the set [0, 1] and
---returns r, g, and b in the set [0, 255].
---@param h number The hue
---@param s number The saturation
---@param l number The lightness
---@param a number The alpha
---@return renderer.color rgba
function ColorPicker.hsl_to_rgb(h, s, l, a)
local r, g, b
if s == 0 then
r, g, b = l, l, l -- achromatic
else
local function hue2rgb(p, q, t)
if t < 0 then t = t + 1 end
if t > 1 then t = t - 1 end
if t < 1/6 then return p + (q - p) * 6 * t end
if t < 1/2 then return q end
if t < 2/3 then return p + (q - p) * (2/3 - t) * 6 end
return p
end
local q
if l < 0.5 then q = l * (1 + s) else q = l + s - l * s end
local p = 2 * l - q
r = hue2rgb(p, q, h + 1/3)
g = hue2rgb(p, q, h)
b = hue2rgb(p, q, h - 1/3)
end
return {r * 255, g * 255, b * 255, a * 255}
end
---Converts an RGB color value to HSV. Conversion formula
---adapted from http://en.wikipedia.org/wiki/HSV_color_space.
---Assumes r, g, and b are contained in the set [0, 255] and
---returns h, s, and v in the set [0, 1].
---@param rgba renderer.color
---@return table hsva The HSV representation
function ColorPicker.rgb_to_hsv(rgba)
local r, g, b, a = rgba[1], rgba[2], rgba[3], rgba[4]
r, g, b, a = r / 255, g / 255, b / 255, a / 255
local max, min = math.max(r, g, b), math.min(r, g, b)
local h, s, v
v = max
local d = max - min
if max == 0 then s = 0 else s = d / max end
if max == min then
h = 0 -- achromatic
else
if max == r then
h = (g - b) / d
if g < b then h = h + 6 end
elseif max == g then h = (b - r) / d + 2
elseif max == b then h = (r - g) / d + 4
end
h = h / 6
end
return {h, s, v, a/255}
end
---Converts an HSV color value to RGB. Conversion formula
---adapted from http://en.wikipedia.org/wiki/HSV_color_space.
---Assumes h, s, and v are contained in the set [0, 1] and
---returns r, g, and b in the set [0, 255].
---@param h number The hue
---@param s number The saturation
---@param v number The brightness
---@param a number The alpha
---@return renderer.color rgba The RGB representation
function ColorPicker.hsv_to_rgb(h, s, v, a)
local r, g, b
local i = math.floor(h * 6);
local f = h * 6 - i;
local p = v * (1 - s);
local q = v * (1 - f * s);
local t = v * (1 - (1 - f) * s);
i = i % 6
if i == 0 then r, g, b = v, t, p
elseif i == 1 then r, g, b = q, v, p
elseif i == 2 then r, g, b = p, v, t
elseif i == 3 then r, g, b = p, q, v
elseif i == 4 then r, g, b = t, p, v
elseif i == 5 then r, g, b = v, p, q
end
return {math.ceil(r * 255), math.ceil(g * 255), math.ceil(b * 255), math.ceil(a * 255)}
end
---Converts a css format color string into a renderer.color if possible,
---if conversion fails returns nil. Adapted from colorpreview plugin.
---@param color string
---@return renderer.color? color
function ColorPicker.color_from_string(color)
local s, e, r, g, b, a, base, nibbles;
s, e, r, g, b, a = color:find("#(%x%x)(%x%x)(%x%x)(%x?%x?)")
if s then
base = 16
else
s, e, r, g, b, a = color:find("#(%x)(%x)(%x)")
if s then
base = 16
nibbles = true
else
s, e, r, g, b, a = color:find(
"rgba?%((%d+)%D+(%d+)%D+(%d+)[%s,]-([%.%d]-)%s-%)"
)
end
end
if not s then return nil end
r = tonumber(r or "", base)
g = tonumber(g or "", base)
b = tonumber(b or "", base)
a = tonumber(a or "", base)
if a ~= nil then
if base ~= 16 then
a = a * 0xff
end
else
a = 0xff
end
if nibbles then
r = r * 16
g = g * 16
b = b * 16
end
return {r, g, b, a}
end
---Gets a color between two given colors on the position
---defined by the given percent.
---@param from_color renderer.color
---@param to_color renderer.color
---@param percent number
---@return renderer.color color
function ColorPicker.color_in_between(from_color, to_color, percent)
local color = {}
for i=1, 4 do
if from_color[i] == to_color[i] then
color[i] = from_color[i]
else
color[i] = common.clamp(
from_color[i] + math.floor((to_color[i] - from_color[i]) * percent),
0,
255
)
end
end
return color
end
function ColorPicker:get_name()
return "Color Picker"
end
---Gets the currently selected color on the hue bar.
---@return renderer.color
function ColorPicker:get_hue_color()
local w = self.selector.w
local pos = self.hue_pos
local pos_percent = pos / 100
local range_size = w / 6
local range
if pos <= (HUE_COLOR_SEGMENT) then
range = 1
elseif pos <= (HUE_COLOR_SEGMENT) * 2 then
range = 2
elseif pos <= (HUE_COLOR_SEGMENT) * 3 then
range = 3
elseif pos <= (HUE_COLOR_SEGMENT) * 4 then
range = 4
elseif pos <= (HUE_COLOR_SEGMENT) * 5 then
range = 5
else
range = 6
end
local range_position = (w * pos_percent) - ((range_size * range)-range_size)
local range_percent = range_position / range_size
return ColorPicker.color_in_between(
HUE_COLOR_RANGES[range][1],
HUE_COLOR_RANGES[range][2],
range_percent
)
end
---Gets the currently selected color on the saturation bar.
---@return renderer.color
function ColorPicker:get_saturation_color()
local w = self.selector.w
local pos = self.saturation_pos
local pos_percent = pos / 100
local range_size = w
local range, color1, color2 = 1, COLOR_WHITE, self.hue_color
local range_position = (w * pos_percent) - ((range_size * range)-range_size)
local range_percent = range_position / range_size
return ColorPicker.color_in_between(color1, color2, range_percent)
end
---Gets the currently selected color on the brightness bar.
---@return renderer.color
function ColorPicker:get_brightness_color()
local w = self.selector.w
local pos = self.brightness_pos
local pos_percent = pos / 100
local range_size = w
local range, color1, color2 = 1, COLOR_BLACK, self.saturation_color
local range_position = (w * pos_percent) - ((range_size * range)-range_size)
local range_percent = range_position / range_size
return ColorPicker.color_in_between(color1, color2, range_percent)
end
---Gets the currently selected rgba color.
---@return renderer.color
function ColorPicker:get_color()
return ColorPicker.hsv_to_rgb(
self.hue_pos / 100,
self.saturation_pos / 100,
self.brightness_pos / 100,
self.alpha / 255
)
end
---Set current color from rgba source which can also
---be a css string representation.
---@param color renderer.color | string
function ColorPicker:set_color(color, skip_html, skip_rgba)
-- we set the color on a coroutine in case it is been set before
-- the control is properly initialized like the constructor.
core.add_thread(function()
if type(color) == "string" then
color = ColorPicker.color_from_string(color)
end
if not color then color = {255, 0, 0, 255} end
local hsva = ColorPicker.rgb_to_hsv(color)
self.hue_pos = hsva[1] * 100
self.saturation_pos = hsva[2] * 100
self.brightness_pos = hsva[3] * 100
self.hue_color = self:get_hue_color()
self.saturation_color = self:get_saturation_color()
self.brightness_color = self:get_brightness_color()
self.alpha = color[4]
if not skip_html then
self.html_updating = true
self.html_notation:set_text(string.format(
"#%02X%02X%02X%02X",
color[1], color[2], color[3], color[4]
))
self.html_updating = false
end
if not skip_rgba then
self.rgba_updating = true
self.rgba_notation:set_text(string.format(
"rgba(%d,%d,%d,%.2f)",
color[1], color[2], color[3], color[4] / 255
))
self.rgba_updating = false
end
self:on_change(color)
end)
end
---Set the transparency level, the lower the given alpha the more transparent.
---@param alpha number A value from 0 to 255
function ColorPicker:set_alpha(alpha)
self.alpha = common.clamp(alpha, 0, 255)
end
---Draw a hue color bar at given location and size.
---@param x number
---@param y number
---@param w number
---@param h number
function ColorPicker:draw_hue(x, y, w, h)
local sx = x
local step = 1
local cwidth = 1
local cheight = h or 10
if w < 255*6 then
step = 255 / (w / 6)
else
cwidth = (w / 6) / 255
end
-- red -> yellow
for g=0, 255, step do
renderer.draw_rect(x, y, cwidth, cheight, {255, g, 0, 255})
x = x + cwidth
end
-- yellow -> green
for r=255, 0, -step do
renderer.draw_rect(x, y, cwidth, cheight, {r, 255, 0, 255})
x = x + cwidth
end
-- green -> cyan
for b=0, 255, step do
renderer.draw_rect(x, y, cwidth, cheight, {0, 255, b, 255})
x = x + cwidth
end
-- cyan -> blue
for g=255, 0, -step do
renderer.draw_rect(x, y, cwidth, cheight, {0, g, 255, 255})
x = x + cwidth
end
-- blue -> purple
for r=0, 255, step do
renderer.draw_rect(x, y, cwidth, cheight, {r, 0, 255, 255})
x = x + cwidth
end
-- purple -> red
for b=255, 0, -step do
renderer.draw_rect(x, y, cwidth, cheight, {255, 0, b, 255})
x = x + cwidth
end
sx = sx + (w * (self.hue_pos / 100))
self:draw_selector(sx, y, cheight, self.hue_color)
end
---Draw a saturation color bar at given location and size.
---@param x number
---@param y number
---@param w number
---@param h number
function ColorPicker:draw_saturation(x, y, w, h)
local sx = x
local step = 1
local cwidth = 1
local cheight = h or 10
if w < 255 then
step = 255 / w
else
cwidth = w / 255
end
-- white to base
for i=0, 255, step do
local color = ColorPicker.color_in_between(COLOR_WHITE, self.hue_color, i / 255)
renderer.draw_rect(x, y, cwidth, cheight, color)
x = x + cwidth
end
sx = sx + (w * (self.saturation_pos / 100))
self:draw_selector(sx, y, cheight, self.saturation_color)
end
---Draw a brightness color bar at given location and size.
---@param x number
---@param y number
---@param w number
---@param h number
function ColorPicker:draw_brightness(x, y, w, h)
local sx = x
local step = 1
local cwidth = 1
local cheight = h or 10
if w < 255 then
step = 255 / w
else
cwidth = w / 255
end
-- black to base
for i=0, 255, step do
local color = ColorPicker.color_in_between(COLOR_BLACK, self.saturation_color, i / 255)
renderer.draw_rect(x, y, cwidth, cheight, color)
x = x + cwidth
end
sx = sx + (w * (self.brightness_pos / 100))
self:draw_selector(sx, y, cheight, self.brightness_color)
end
---@param self widget.colorpicker
local function update_control_values(self)
local color = self:get_color()
self.alpha = color[4]
self.html_updating = true
self.rgba_updating = true
self.html_notation:set_text(string.format(
"#%02X%02X%02X%02X",
color[1], color[2], color[3], color[4]
))
self.rgba_notation:set_text(string.format(
"rgba(%d,%d,%d,%.2f)",
color[1], color[2], color[3], color[4] / 255
))
self.html_updating = false
self.rgba_updating = false
self:on_change(color)
end
function ColorPicker:on_mouse_pressed(button, x, y, clicks)
if not ColorPicker.super.on_mouse_pressed(self, button, x, y, clicks) then
return false
end
if
x >= self.selector.x and x <= self.selector.x + self.selector.w
and
y >= self.selector.y and y <= self.selector.y + self.selector.h
then
local sx, sw = self.selector.x, self.selector.w
self.hue_pos = common.clamp(x, sx, sx + sw)
self.hue_pos = ((self.hue_pos - self.selector.x) / self.selector.w) * 100
self.hue_color = self:get_hue_color()
self.saturation_color = self:get_saturation_color()
self.hue_mouse_down = true
elseif
x >= self.selector.x and x <= self.selector.x + self.selector.w
and
y >= self.selector.y + style.padding.y + self.selector.h
and
y <= self.selector.y + style.padding.y + (self.selector.h * 2)
then
local sx, sw = self.selector.x, self.selector.w
self.saturation_pos = common.clamp(x, sx, sx + sw)
self.saturation_pos = ((self.saturation_pos - self.selector.x) / self.selector.w) * 100
self.saturation_color = self:get_saturation_color()
self.brightness_color = self:get_brightness_color()
self.saturation_mouse_down = true
elseif
x >= self.selector.x and x <= self.selector.x + self.selector.w
and
y >= self.selector.y + style.padding.y * 2 + self.selector.h * 2
and
y <= self.selector.y + style.padding.y * 2 + (self.selector.h * 4)
then
local sx, sw = self.selector.x, self.selector.w
self.brightness_pos = common.clamp(x, sx, sx + sw)
self.brightness_pos = ((self.brightness_pos - self.selector.x) / self.selector.w) * 100
self.brightness_color = self:get_brightness_color()
self.brightness_mouse_down = true
end
if self.hue_mouse_down or self.saturation_mouse_down or self.brightness_mouse_down then
self:capture_mouse()
update_control_values(self)
end
return true
end
function ColorPicker:on_mouse_released(button, x, y)
if self.hue_mouse_down or self.saturation_mouse_down or self.brightness_mouse_down then
self:release_mouse()
end
self.hue_mouse_down = false
self.saturation_mouse_down = false
self.brightness_mouse_down = false
if not ColorPicker.super.on_mouse_released(self, button, x, y) then
return false
end
return true
end
function ColorPicker:on_mouse_moved(x, y, dx, dy)
if self.hue_mouse_down then
local sx, sw = self.selector.x, self.selector.w
self.hue_pos = common.clamp(x, sx, sx + sw)
self.hue_pos = ((self.hue_pos - self.selector.x) / self.selector.w) * 100
self.hue_color = self:get_hue_color()
self.saturation_color = self:get_saturation_color()
self.brightness_color = self:get_brightness_color()
elseif self.saturation_mouse_down then
local sx, sw = self.selector.x, self.selector.w
self.saturation_pos = common.clamp(x, sx, sx + sw)
self.saturation_pos = ((self.saturation_pos - self.selector.x) / self.selector.w) * 100
self.saturation_color = self:get_saturation_color()
self.brightness_color = self:get_brightness_color()
elseif self.brightness_mouse_down then
local sx, sw = self.selector.x, self.selector.w
self.brightness_pos = common.clamp(x, sx, sx + sw)
self.brightness_pos = ((self.brightness_pos - self.selector.x) / self.selector.w) * 100
self.brightness_color = self:get_brightness_color()
end
if self.hue_mouse_down or self.saturation_mouse_down or self.brightness_mouse_down then
update_control_values(self)
else
return ColorPicker.super.on_mouse_moved(self, x, y, dx, dy)
end
return true
end
function ColorPicker:update_size()
self.selector.h = 10 * SCALE
local x, y = 0, style.padding.y * 3 + self.selector.h * 4
self.html_notation:set_position(x, y)
self.rgba_notation:set_position(self.html_notation:get_right() + style.padding.x, y)
if self:get_width() < self.rgba_notation:get_right() then
self:set_size(self.rgba_notation:get_right() + style.padding.x)
end
if self:get_height() < self.rgba_notation:get_bottom() then
self:set_size(nil, self.rgba_notation:get_bottom() + style.padding.y)
end
end
function ColorPicker:update()
if not ColorPicker.super.update(self) then return false end
self:update_size()
return true
end
function ColorPicker:draw_selector(x, y, h, color)
local border = 2 * SCALE
x = x - border - ((10 * SCALE) / border)
y = y - border
renderer.draw_rect(x, y, 14 * SCALE, h + (border * 2), COLOR_WHITE)
renderer.draw_rect(x+border, y + border, 10 * SCALE, h, color)
end
function ColorPicker:draw()
if not ColorPicker.super.draw(self) then return false end
local x, y, w = self.position.x, self.position.y, self.size.x
self.selector.x = x
self.selector.y = style.padding.y + y
self.selector.w = w - style.padding.x - 100
self.selector.h = 10 * SCALE
self:draw_hue(
self.selector.x,
self.selector.y,
self.selector.w,
self.selector.h
)
self:draw_saturation(
self.selector.x,
self.selector.y + style.padding.y + self.selector.h,
self.selector.w,
self.selector.h
)
self:draw_brightness(
self.selector.x,
self.selector.y + style.padding.y * 2 + self.selector.h * 2,
self.selector.w,
self.selector.h
)
local c = self:get_color()
renderer.draw_rect(
self.selector.x + style.padding.x + self.selector.w,
self.selector.y,
100,
(self.selector.y + style.padding.y * 2 + self.selector.h * 3)
- self.selector.y,
c
)
return true
end
return ColorPicker
+77
View File
@@ -0,0 +1,77 @@
--
-- Color Picker Dialog Widget.
-- @copyright Jefferson Gonzalez
-- @license MIT
--
local style = require "core.style"
local Button = require "libraries.widget.button"
local ColorPicker = require "libraries.widget.colorpicker"
local Dialog = require "libraries.widget.dialog"
---@class widget.colorpickerdialog : widget.dialog
---@overload fun(title?:string, color?:renderer.color|string):widget.colorpickerdialog
---@field super widget.dialog
---@field picker widget.colorpicker
---@field apply widget.button
---@field cancel widget.button
local ColorPickerDialog = Dialog:extend()
---Constructor
---@param title? string
---@param color? renderer.color | string
function ColorPickerDialog:new(title, color)
ColorPickerDialog.super.new(self, title or "Color Picker")
self.type_name = "widget.colorpickerdialog"
self.picker = ColorPicker(self.panel, color)
local this = self
self.apply = Button(self.panel, "Apply")
self.apply:set_icon("S")
function self.apply:on_click()
this:on_apply(this.picker:get_color())
this:on_close()
end
self.cancel = Button(self.panel, "Cancel")
self.cancel:set_icon("C")
function self.cancel:on_click()
this:on_close()
end
end
---Called when the user clicks on apply
---@param value renderer.color
function ColorPickerDialog:on_apply(value) end
function ColorPickerDialog:update()
if not ColorPickerDialog.super.update(self) then return false end
self.picker:set_position(style.padding.x/2, 0)
self.apply:set_position(
style.padding.x/2,
self.picker:get_bottom() + style.padding.y
)
self.cancel:set_position(
self.apply:get_right() + style.padding.x,
self.picker:get_bottom() + style.padding.y
)
self.panel.size.x = self.panel:get_real_width() + style.padding.x
self.panel.size.y = self.panel:get_real_height()
self.size.x = self:get_real_width() - (style.padding.x / 2)
self.size.y = self:get_real_height() + (style.padding.y / 2)
self.close:set_position(
self.size.x - self.close.size.x - (style.padding.x / 2),
style.padding.y / 2
)
return true
end
return ColorPickerDialog
+164
View File
@@ -0,0 +1,164 @@
--
-- Dialog object that serves as base to implement other dialogs.
-- @copyright Jefferson Gonzalez
-- @license MIT
--
local core = require "core"
local style = require "core.style"
local Widget = require "libraries.widget"
local Button = require "libraries.widget.button"
local Label = require "libraries.widget.label"
---@class widget.dialog : widget
---@overload fun(title?:string):widget.dialog
---@field protected title widget.label
---@field protected close widget.button
---@field protected panel widget
local Dialog = Widget:extend()
---Constructor
---@param title string
function Dialog:new(title)
Dialog.super.new(self)
self.type_name = "widget.dialog"
self.draggable = true
self.scrollable = false
-- minimum width and height
self.size.mx = 400
self.size.my = 150
self.title = Label(self, "")
self.close = Button(self, "")
self.close:set_icon("X")
self.close.border.width = 0
self.close:toggle_background(false)
self.close.padding.x = 4
self.close.padding.y = 0
self.panel = Widget(self)
self.panel.border.width = 0
self.panel.scrollable = true
local this = self
function self.close:on_click()
this:on_close()
this:hide()
end
self:set_title(title or "")
end
---Returns the widget where you can add child widgets to this dialog.
---@return widget
function Dialog:get_panel()
return self.panel
end
---Change the dialog title.
---@param text string|widget.styledtext
function Dialog:set_title(text)
self.title:set_label(text)
end
---Calculate the dialog size, centers it relative to screen and shows it.
function Dialog:show()
Dialog.super.show(self)
self:update()
self:centered()
end
---Called when the user clicks the close button of the dialog.
function Dialog:on_close()
self:hide()
end
function Dialog:update()
if not Dialog.super.update(self) then return false end
local width = math.max(
self.title:get_width() + (style.padding.x * 3) + self.close:get_width(),
self.size.mx,
self.size.x
)
local height = math.max(
self.title:get_height() + (style.padding.y * 3),
self.size.my,
self.size.y
)
self:set_size(width, height)
self.title:set_position(
style.padding.x / 2,
style.padding.y / 2
)
self.close:set_position(
self.size.x - self.close.size.x - (style.padding.x / 2),
style.padding.y / 2
)
self.panel:set_position(
0,
self.title:get_bottom() + (style.padding.y / 2)
)
self.panel:set_size(
self.size.x,
self.size.y - self.title.size.y - style.padding.y
)
return true
end
---We overwrite default draw function to draw the title background.
function Dialog:draw()
if not self:is_visible() then return false end
Dialog.super.draw(self)
self:draw_border()
if self.background_color then
self:draw_background(self.background_color)
else
self:draw_background(
self.parent and style.background or style.background2
)
end
if #self.childs > 0 then
core.push_clip_rect(
self.position.x,
self.position.y,
self.size.x,
self.size.y
)
end
-- draw the title background
renderer.draw_rect(
self.position.x,
self.position.y,
self.size.x, self.title:get_height() + style.padding.y,
style.selection
)
for i=#self.childs, 1, -1 do
self.childs[i]:draw()
end
if #self.childs > 0 then
core.pop_clip_rect()
end
return true
end
return Dialog
+395
View File
@@ -0,0 +1,395 @@
local core = require "core"
local common = require "core.common"
local style = require "core.style"
local Widget = require "libraries.widget"
local Button = require "libraries.widget.button"
local Label = require "libraries.widget.label"
---@class widget.filepicker : widget
---@overload fun(parent?:widget, path?:string):widget.filepicker
---@field public pick_mode integer
---@field public filters table<integer,string>
---@field private path string
---@field private file widget.label
---@field private textbox widget.textbox
---@field private button widget.button
local FilePicker = Widget:extend()
---Operation modes for the file picker.
---@type table<string,integer>
FilePicker.mode = {
---Opens file browser the selected file does not has to exist.
FILE = 1,
---Opens file browser the selected file has to exist.
FILE_EXISTS = 2,
---Opens directory browser the selected directory does not has to exist.
DIRECTORY = 4,
---Opens directory browser the selected directory has to exist.
DIRECTORY_EXISTS = 8
}
---@param text string
local function suggest_directory(text)
text = common.home_expand(text)
return common.home_encode_list(common.dir_path_suggest(text))
end
---@param path string
local function check_directory_path(path)
local abs_path = system.absolute_path(path)
local info = abs_path and system.get_file_info(abs_path)
if not info or info.type ~= 'dir' then return nil end
return abs_path
end
---@param str string
---@param find string
---@param replace string
local function str_replace(str, find, replace)
local start, ending = str:find(find, 1, true)
if start == 1 then
return replace .. str:sub(ending + 1)
else
return str:sub(1, start - 1) .. replace .. str:sub(ending + 1)
end
end
---@alias widget.filepicker.modes
---| `FilePicker.mode.FILE`
---| `FilePicker.mode.FILE_EXISTS`
---| `FilePicker.mode.DIRECTORY`
---| `FilePicker.mode.DIRECTORY_EXISTS`
---Constructor
---@param parent widget
---@param path? string
function FilePicker:new(parent, path)
FilePicker.super.new(self, parent)
local this = self
self.type_name = "widget.filepicker"
self.filters = {}
self.border.width = 0
self.pick_mode = FilePicker.mode.FILE
self.file = Label(self, "")
self.file.clickable = true
self.file:set_border_width(1)
function self.file:on_click(button)
if button == "left" then
this:show_picker()
end
end
function self.file:on_mouse_enter(...)
Label.super.on_mouse_enter(self, ...)
self.border.color = style.caret
end
function self.file:on_mouse_leave(...)
Label.super.on_mouse_leave(self, ...)
self.border.color = style.text
end
self.button = Button(self, "")
self.button:set_icon("D")
self.button:set_tooltip("open file browser")
function self.button:on_click(button)
if button == "left" then
this:show_picker()
end
end
local label_width = self.file:get_width()
if label_width <= 10 then
label_width = 200 + (self.file.border.width * 2)
self.file:set_size(200, self.button:get_height() - self.button.border.width * 2)
end
self:set_size(
label_width + self.button:get_width(),
math.max(self.file:get_height(), self.button:get_height())
)
self:set_path(path)
end
---Set the filepicker size
---@param width? number
---@param height? number
function FilePicker:set_size(width, height)
FilePicker.super.set_size(self, width, height)
self.file:set_position(0, 0)
self.file:set_size(
self:get_width() - self.button:get_width(),
self.button:get_height()
)
self.button:set_position(self.file:get_right(), 0)
self.size.y = math.max(
self.file:get_height(),
self.button:get_height()
-- something is off on calculation since adding border width should not
-- be needed to display whole rendered control at all...
) + self.button.border.width
end
---Add a lua pattern to the filters list
---@param pattern string
function FilePicker:add_filter(pattern)
table.insert(self.filters, pattern)
end
---Clear the filters list
function FilePicker:clear_filters()
self.filters = {}
end
---Set the operation mode for the file picker.
---@param mode widget.filepicker.modes | string | integer
function FilePicker:set_mode(mode)
if type(mode) == "string" then
---@type integer
local intmode = FilePicker.mode[mode:upper()]
self.pick_mode = intmode
else
self.pick_mode = mode
end
end
---Set the full path including directory and filename.
---@param path? string
function FilePicker:set_path(path)
if path then
self.path = path or ""
if common.path_belongs_to(path, core.project_dir) then
self.file.label = path ~= "" and
common.relative_path(core.project_dir, path)
or
""
else
self.file.label = path
end
else
self.path = ""
self.file.label = ""
end
end
---Get the full path including directory and filename.
---@return string | nil
function FilePicker:get_path()
if self.path ~= "" then
return self.path
end
return nil
end
---Get the full path relative to current project dir or absolute if it doesn't
---belongs to the current project directory.
---@return string
function FilePicker:get_relative_path()
if
self.path ~= ""
and
common.path_belongs_to(self.path, core.project_dir)
then
return common.relative_path(core.project_dir, self.path)
end
return self.path or ""
end
---Set the filename part only.
---@param name string
function FilePicker:set_filename(name)
local dir_part = common.dirname(self.path)
if dir_part then
self:set_path(dir_part .. PATHSEP .. name)
else
self:set_path(name)
end
end
---Get the filename part only.
---@return string | nil
function FilePicker:get_filename()
local dir_part = common.dirname(self.path)
if dir_part then
local filename = str_replace(self.path, dir_part .. PATHSEP, "")
return filename
elseif self.path ~= "" then
return self.path
end
return nil
end
---Set the directory part only.
---@param dir string
function FilePicker:set_directory(dir)
local filename = self:get_filename()
if filename then
self:set_path(dir:gsub("[\\/]$", "") .. PATHSEP .. filename)
else
self:set_path(dir:gsub("[\\/]$", ""))
end
end
---Get the directory part only.
---@return string | nil
function FilePicker:get_directory()
if self.path ~= "" then
local dir_part = common.dirname(self.path)
if dir_part then return dir_part end
end
return nil
end
---Filter a list of directories by applying currently set filters.
---@param self widget.filepicker
---@param list table<integer, string>
---@return table<integer,string>
local function filter(self, list)
if #self.filters > 0 then
local new_list = {}
for _, value in ipairs(list) do
if common.match_pattern(value, self.filters) then
table.insert(new_list, value)
elseif
self.pick_mode == FilePicker.mode.FILE
or
self.pick_mode == FilePicker.mode.FILE_EXISTS
then
local path = common.home_expand(value)
local abs_path = check_directory_path(path)
if abs_path then
table.insert(new_list, value)
end
end
end
return new_list
end
return list
end
---@param self widget.filepicker
local function show_file_picker(self)
core.command_view:enter("Choose File", {
text = self:get_relative_path(),
submit = function(text)
---@type string
local filename = text
local dirname = common.dirname(common.home_expand(text))
if dirname then
filename = common.home_expand(text)
filename = system.absolute_path(dirname)
.. PATHSEP
.. str_replace(filename, dirname .. PATHSEP, "")
elseif filename ~= "" then
filename = core.project_dir .. PATHSEP .. filename
end
self:set_path(filename)
self:on_change(filename ~= "" and filename or nil)
end,
suggest = function (text)
return filter(
self,
common.home_encode_list(common.path_suggest(common.home_expand(text)))
)
end,
validate = function(text)
if #self.filters > 0 and text ~= "" and not common.match_pattern(text, self.filters) then
core.error(
"File does not match the filters: %s",
table.concat(self.filters, ", ")
)
return false
end
local filename = common.home_expand(text)
local path_stat, err = system.get_file_info(filename)
if path_stat and path_stat.type == 'dir' then
core.error("Cannot open %s, is a folder", text)
return false
end
if self.pick_mode == FilePicker.mode.FILE_EXISTS then
if not path_stat then
core.error("Cannot open file %s: %s", text, err)
return false
end
else
local dirname = common.dirname(filename)
local dir_stat = dirname and system.get_file_info(dirname)
if dirname and not dir_stat then
core.error("Directory does not exists: %s", dirname)
return false
end
end
return true
end,
})
end
---@param self widget.filepicker
local function show_dir_picker(self)
core.command_view:enter("Choose Directory", {
text = self:get_relative_path(),
submit = function(text)
local path = common.home_expand(text)
local abs_path = check_directory_path(path)
self:set_path(abs_path or text)
self:on_change(abs_path or (text ~= "" and text or nil))
end,
suggest = function(text)
return filter(self, suggest_directory(text))
end,
validate = function(text)
if #self.filters > 0 and text ~= "" and not common.match_pattern(text, self.filters) then
core.error(
"Directory does not match the filters: %s",
table.concat(self.filters, ", ")
)
return false
end
if self.pick_mode == FilePicker.mode.DIRECTORY_EXISTS then
local path = common.home_expand(text)
local abs_path = check_directory_path(path)
if not abs_path then
core.error("Cannot open directory %q", path)
return false
end
end
return true
end
})
end
---Show the command view file or directory browser depending on the
---current file picker mode.
function FilePicker:show_picker()
if
self.pick_mode == FilePicker.mode.FILE
or
self.pick_mode == FilePicker.mode.FILE_EXISTS
then
show_file_picker(self)
else
show_dir_picker(self)
end
end
function FilePicker:update()
if not FilePicker.super.update(self) then return false end
if self:get_width() ~= (self.file:get_width() + self.button:get_width()) then
self:set_size(
self.file:get_width() + self.button:get_width(),
self.button:get_height()
)
end
return true
end
return FilePicker
+216
View File
@@ -0,0 +1,216 @@
--
-- FoldingBook Widget.
-- @copyright Jefferson Gonzalez
-- @license MIT
--
local style = require "core.style"
local Widget = require "libraries.widget"
local Button = require "libraries.widget.button"
---Represents a foldingbook pane
---@class widget.foldingbook.pane
---@field public name string
---@field public tab widget.button
---@field public container widget
---@field public expanded boolean
local FoldingBookPane = {}
---@class widget.foldingbook : widget
---@overload fun(parent:widget?):widget.foldingbook
---@field public panes widget.foldingbook.pane[]
local FoldingBook = Widget:extend()
---FoldingBook constructor
---@param parent widget
function FoldingBook:new(parent)
FoldingBook.super.new(self, parent)
self.type_name = "widget.foldingbook"
self.panes = {}
self.scrollable = true
end
---@param pane widget.foldingbook.pane
function FoldingBook:on_tab_click(pane)
pane.expanded = not pane.expanded
end
---Adds a new pane to the foldingbook and returns a container widget where
---you can add more child elements.
---@param name string
---@param label string
---@return widget container
function FoldingBook:add_pane(name, label)
---@type widget.button
local tab = Button(self, label)
tab.border.width = 0
tab:toggle_expand(true)
tab:set_icon("+")
if #self.panes > 0 then
if self.panes[#self.panes].expanded then
tab:set_position(0, self.panes[#self.panes].container:get_bottom() + 2)
else
tab:set_position(0, self.panes[#self.panes].tab:get_bottom() + 2)
end
else
tab:set_position(0, 10)
end
local container = Widget(self)
container:set_position(0, tab:get_bottom() + 4)
container:set_size(self:get_width(), 0)
local pane = {
name = name,
tab = tab,
container = container,
expanded = false
}
tab.on_click = function()
self:on_tab_click(pane)
end
table.insert(self.panes, pane)
return container
end
---@param name string
---@return widget.foldingbook.pane | nil
function FoldingBook:get_pane(name)
for _, pane in pairs(self.panes) do
if pane.name == name then
return pane
end
end
return nil
end
---Delete a pane and all its childs from the folding book.
---@param name string
---@return boolean deleted
function FoldingBook:delete_pane(name)
for idx, pane in ipairs(self.panes) do
if pane.name == name then
self:remove_child(pane.tab)
self:remove_child(pane.container)
table.remove(self.panes, idx)
return true
end
end
return false
end
---Activates the given pane
---@param name string
---@param visible boolean | nil
function FoldingBook:toggle_pane(name, visible)
local pane = self:get_pane(name)
if pane then
if type(visible) == "boolean" then
pane.expanded = visible
else
pane.expanded = not pane.expanded
end
end
end
---Change the tab label of the given pane.
---@param name string
---@param label string
function FoldingBook:set_pane_label(name, label)
local pane = self:get_pane(name)
if pane then
pane.tab:set_label(label)
return true
end
return false
end
---Set or remove the icon for the given pane.
---@param name string
---@param icon string
---@param color? renderer.color|nil
---@param hover_color? renderer.color|nil
function FoldingBook:set_pane_icon(name, icon, color, hover_color)
local pane = self:get_pane(name)
if pane then
pane.tab:set_icon(icon, color, hover_color)
return true
end
return false
end
---Recalculate the position of the elements on resizing or position changes.
function FoldingBook:update()
if not FoldingBook.super.update(self) then return false end
---@type widget.foldingbook.pane
local prev_pane = nil
for _, pane in ipairs(self.panes) do
local tx, ty = 0, 10
local cx, cy = 0, 0
local cw, ch = 0, 0
if prev_pane then
if prev_pane and prev_pane.container:is_visible() then
ty = prev_pane.container:get_bottom() + 2
else
ty = prev_pane.tab:get_bottom() + 2
end
end
pane.tab:set_position(tx, ty)
cy = pane.tab:get_bottom() + 4
cw = self:get_width()
if #pane.container.childs > 0 then
ch = pane.container:get_real_height() + 10
end
pane.container.border.color = style.divider
if pane.expanded and not pane.container.hiding then
pane.container:set_position(cx, cy)
pane.container:set_size(cw)
if not pane.container.visible then
pane.container:set_size(cw, ch)
pane.container:show_animated(true)
pane.tab:set_icon("-")
pane.container.hiding = false
end
elseif pane.container.visible and not pane.container.hiding then
pane.tab:set_icon("+")
pane.container.hiding = true
pane.container:hide_animated(true, false, {
on_complete = function()
pane.container.hiding = false
end
})
end
prev_pane = pane
end
return true
end
---Here we draw the bottom line on each tab.
function FoldingBook:draw()
if not FoldingBook.super.draw(self) then return false end
for _, pane in ipairs(self.panes) do
local x = pane.tab.position.x
local y = pane.tab.position.y + pane.tab:get_height()
local w = self:get_width()
renderer.draw_rect(x, y, w, 2, style.selection)
end
return true
end
return FoldingBook
+287
View File
@@ -0,0 +1,287 @@
local core = require "core"
local common = require "core.common"
local Object = require "core.object"
local FontInfo = require "libraries.widget.fonts.info"
---@class widget.fonts.cache : core.object
---@overload fun():widget.fonts.cache
---@field fontinfo widget.fonts.info
---@field found integer
---@field found_monospaced integer
---@field building boolean
---@field monosppaced boolean
---@field searching_monospaced boolean
---@field fontdirs table<integer, string>
---@field fonts widget.fonts.data[]
local FontCache = Object:extend()
---Constructor
function FontCache:new()
self.fontinfo = FontInfo()
self.fontdirs = {}
self.fonts = {}
self.loaded_fonts = {}
self.found = 0
self.found_monospaced = 0
self.building = false
self.searching_monospaced = false
self.monospaced = false
table.insert(self.fontdirs, USERDIR .. "/fonts")
table.insert(self.fontdirs, DATADIR .. "/fonts")
if PLATFORM == "Windows" then
table.insert(self.fontdirs, HOME .. PATHSEP .. "AppData\\Local\\Microsoft\\Windows\\Fonts" )
table.insert(self.fontdirs, os.getenv("SYSTEMROOT") .. PATHSEP .. "Fonts" )
elseif PLATFORM == "Mac OS X" then
table.insert(self.fontdirs, HOME .. "/Library/Fonts")
table.insert(self.fontdirs, "/Library/Fonts")
table.insert(self.fontdirs, "/System/Library/Fonts")
else
table.insert(self.fontdirs, HOME .. "/.local/share/fonts")
table.insert(self.fontdirs, HOME .. "/.fonts")
table.insert(self.fontdirs, "/usr/local/share/fonts")
table.insert(self.fontdirs, "/usr/share/fonts")
end
if not self:load_cache() then
self:build()
elseif not self.monospaced then
self:verify_monospaced()
end
end
---Check if the cache is already building.
---@return boolean building
function FontCache:is_building()
if self.building or self.searching_monospaced then
return true
end
return false
end
---Build the font cache and save it.
---@return boolean started False if cache is already been built
function FontCache:build()
if self:is_building() then
core.log_quiet("The font cache is already been generated, please wait.")
return false
end
self.found = 0
self.building = true
self.monospaced = false
self.loaded_fonts = {}
core.log_quiet("Generating font cache...")
local start_time = system.get_time()
local this = self
core.add_thread(function()
for _, dir in ipairs(this.fontdirs) do
this:scan_dir(dir)
end
this:save_cache()
this.building = false
this.loaded_fonts = {}
core.log_quiet(
"Font cache generated in %.1fs for %s fonts!",
system.get_time() - start_time, tostring(this.found)
)
self:verify_monospaced()
end)
return true
end
---Clear current font cache and rebuild it.
---@return boolean started False if cache is already been built
function FontCache:rebuild()
if self:is_building() then
core.log_quiet("The font cache is already been generated, please wait.")
return false
end
local fontcache_file = USERDIR .. "/font_cache.lua"
local file = io.open(fontcache_file, "r")
if file ~= nil then
file:close()
os.remove(fontcache_file)
end
self.fonts = {}
self.loaded_fonts = {}
self.found = 0
self.found_monospaced = 0
return self:build()
end
---Scan a directory for valid font files and load them into the cache.
---@param path string
---@param run_count? integer
function FontCache:scan_dir(path, run_count)
run_count = run_count or 1
local can_yield = coroutine.running()
local list = system.list_dir(path)
if list then
for _, name in pairs(list) do
if name:match("%.[tToO][tT][fFcC]$") and not self.loaded_fonts[name] then
-- prevent loading of duplicate files
self.loaded_fonts[name] = true
local font_path = path .. PATHSEP .. name
local read, errmsg = self.fontinfo:read(font_path)
if read then
local font_data
font_data, errmsg = self.fontinfo:get_data()
if font_data then
table.insert(self.fonts, font_data)
self.found = self.found + 1
else
io.stderr:write(
"Error: " .. path .. PATHSEP .. name .. "\n"
.. " " .. errmsg .. "\n"
)
end
else
io.stderr:write(
"Error: " .. path .. PATHSEP .. name .. "\n"
.. " " .. errmsg .. "\n"
)
end
if can_yield and run_count % 100 == 0 then
coroutine.yield()
end
else
self:scan_dir(path .. PATHSEP .. name, run_count)
end
run_count = run_count + 1
end
end
end
---Search and mark monospaced fonts on currently loaded cache and save it.
function FontCache:verify_monospaced()
if self:is_building() then
core.log_quiet("The monospaced verification is already running, please wait.")
return
end
self.found_monospaced = 0
self.searching_monospaced = true
self.monospaced = false
core.log_quiet("Finding monospaced fonts...")
local start_time = system.get_time()
local this = self
core.add_thread(function()
for _, font in ipairs(this.fonts) do
if not font.monospace then
FontInfo.check_is_monospace(font)
end
if font.monospace then
this.found_monospaced = this.found_monospaced + 1
end
coroutine.yield()
end
this.monospaced = true
this:save_cache()
this.searching_monospaced = false
core.log_quiet(
"Found %s monospaced fonts in %.1fs!",
tostring(this.found_monospaced), system.get_time() - start_time
)
end)
end
---Load font cache from persistent file for faster startup time.
function FontCache:load_cache()
local ok, t = pcall(dofile, USERDIR .. "/font_cache.lua")
if ok then
self.fonts = t.fonts
self.monospaced = t.monospaced
self.found = t.found
self.found_monospaced = t.found_monospaced
return true
end
return false
end
---Store current font cache to persistent file.
function FontCache:save_cache()
local fp = io.open(USERDIR .. "/font_cache.lua", "w")
if fp then
local output = "{\n"
.. "found = "..tostring(self.found)..",\n"
.. "found_monospaced = "..tostring(self.found_monospaced)..",\n"
.. "monospaced = "..tostring(self.monospaced)..",\n"
.. "[\"fonts\"] = "
.. common.serialize(
self.fonts,
{ pretty = true, escape = true, sort = true, initial_indent = 1 }
):gsub("^%s+", "")
.. "\n}\n"
fp:write("return ", output)
fp:close()
end
end
---Search for a font and return the best match.
---@param name string
---@param style? widget.fonts.style
---@param monospaced? boolean
---@return widget.fonts.data? font_data
---@return string? errmsg
function FontCache:search(name, style, monospaced)
if #self.fonts == 0 then
return nil, "the font cache needs to be rebuilt"
end
style = style or "regular"
name = name:ulower()
style = style:ulower()
if name == "monospace" then
name = "mono"
monospaced = true
end
if not self.monospaced then monospaced = false end
---@type widget.fonts.data
local fontdata = nil
local prev_score = 0
for _, font in ipairs(self.fonts) do
if not monospaced or (monospaced and font.monospace) then
local score = system.fuzzy_match(
font.fullname:ulower(),
name .. " " .. style,
false
)
if score ~= nil and (score > prev_score or prev_score == 0) then
fontdata = font
prev_score = score
end
end
end
if fontdata then
local fontfile = io.open(fontdata.path, "r")
if not fontfile then
return nil, "found font file does not exists, cache is outdated"
else
fontfile:close()
end
else
return nil, "no matching font found"
end
return fontdata
end
return FontCache
+550
View File
@@ -0,0 +1,550 @@
-- Based on the code from:
-- https://gist.github.com/zr-tex8r/1969061a025fa4fc5486c9c28460f48e
local Object = require "core.object"
--------------------------------------------------------------------------------
-- Class Declarations
--------------------------------------------------------------------------------
---@class widget.fonts.cdata : core.object
---@overload fun(data:string):widget.fonts.cdata
---@field private data string
---@field private position integer
local FontCDATA = Object:extend()
---@class widget.fonts.reader : core.object
---@overload fun(font_path?:string):widget.fonts.reader
---@field private file file*
---@field private path string
local FontReader = Object:extend()
---@class widget.fonts.data
---@field public path string
---@field public id number @Numerical id of the font
---@field public type '"ttc"' | '"ttf"' | '"otf"'
---@field public copyright string
---@field public family string
---@field public subfamily '"Regular"' | '"Bold"' | '"Italic"' | '"Bold Italic"'
---@field public fullname string
---@field public version string
---@field public psname string
---@field public url string
---@field public license string
---@field public tfamily string
---@field public tsubfamily '"Regular"' | '"Bold"' | '"Italic"' | '"Bold Italic"'
---@field public wwsfamily string
---@field public wwssubfamily string
---@field public monospace boolean
---@class widget.fonts.info : core.object
---@overload fun(font_path?:string):widget.fonts.info
---@field private reader widget.fonts.reader
---@field public path string @Path of the font file
---@field public data widget.fonts.data[] @Holds the metadata for each of the embedded fonts
local FontInfo = Object:extend()
---@alias widget.fonts.style
---|>'"regular"'
---| '"bold"'
---| '"italic"'
---| '"bold italic"'
---| '"thin"'
---| '"medium"'
---| '"light"'
---| '"black"'
---| '"condensed"'
---| '"oblique"'
---| '"bold oblique"'
---| '"extra nold"'
---| '"Extra bold italic"'
---| '"bold condensed"'
--------------------------------------------------------------------------------
-- FontCDATA Implementation
--------------------------------------------------------------------------------
function FontCDATA:new(data)
self.data = data
self.position = 0
end
function FontCDATA:__tostring()
return "cdata(pos="..self.position..")"
end
function FontCDATA:pos(p)
if not p then return self.position end
self.position = p
return self
end
function FontCDATA:unum(b)
local v, data = 0, self.data
assert(#data >= self.position + b, 11)
for _ = 1, b do
self.position = self.position + 1
v = v * 256 + data:byte(self.position)
end
return v
end
function FontCDATA:setunum(b, v)
local t, data = {}, self.data
t[1] = data:sub(1, self.position)
self.position = self.position + b
assert(#data >= self.position, 12)
t[b + 2] = data:sub(self.position + 1)
for i = 1, b do
t[b + 2 - i] = string.char(v % 256)
v = math.floor(v / 256)
end
self.data = table.concat(t, '')
return self
end
function FontCDATA:str(b)
local data = self.data
self.position = self.position + b
assert(#data >= self.position, 13)
return data:sub(self.position - b + 1, self.position)
end
function FontCDATA:setstr(s)
local t, data = {}, self.data
t[1], t[2] = data:sub(1, self.position), s
self.position = self.position + #s
assert(#data >= self.position, 14)
t[3] = data:sub(self.position + 1)
self.data = table.concat(t, '')
return self
end
function FontCDATA:ushort()
return self:unum(2)
end
function FontCDATA:ulong()
return self:unum(4)
end
function FontCDATA:setulong(v)
return self:setunum(4, v)
end
function FontCDATA:ulongs(num)
local t = {}
for i = 1, num do
t[i] = self:unum(4)
end
return t
end
--------------------------------------------------------------------------------
-- FontReader Implementation
--------------------------------------------------------------------------------
function FontReader:new(font_path)
local file, errmsg = io.open(font_path, "rb")
assert(file, errmsg)
self.file = file
self.path = font_path
end
function FontReader:__gc()
if self.file then
self.file:close()
end
end
function FontReader:__tostring()
return "reader("..self.path..")"
end
---@param offset integer
---@param len integer
---@return widget.fonts.cdata?
---@return string|nil errmsg
function FontReader:cdata(offset, len)
local data, errmsg = self:read(offset, len)
if data then
return FontCDATA(data)
end
return nil, errmsg
end
function FontReader:read(offset, len)
self.file:seek("set", offset)
local data = self.file:read(len)
if data:len() ~= len then
return nil, "failed reading font data"
end
return data
end
function FontReader:close()
self.file:close()
self.file = nil
end
--------------------------------------------------------------------------------
-- FontInfo Helper Functions
--------------------------------------------------------------------------------
-- speeds up function lookups
local floor, ceil = math.floor, math.ceil
local function div(x, y)
return floor(x / y), x % y
end
local function utf16betoutf8(src)
local s, d = { tostring(src):byte(1, -1) }, {}
for i = 1, #s - 1, 2 do
local c = s[i] * 256 + s[i+1]
if c < 0x80 then d[#d+1] = c
elseif c < 0x800 then
local x, y = div(c, 0x40)
d[#d+1] = x + 0xC0; d[#d+1] = y + 0x80
elseif c < 0x10000 then
local x, y, z = div(c, 0x1000); y, z = div(y, 0x40)
d[#d+1] = x + 0xE0; d[#d+1] = y + 0x80; d[#d+1] = z + 0x80
else
assert(nil)
end
end
return string.char(table.unpack(d))
end
local file_type = {
[0x74746366] = 'ttc',
[0x10000] = 'ttf',
[0x4F54544F] = 'otf',
[1008813135] = 'ttc'
}
---@param reader widget.fonts.reader
local function otf_offset(reader)
local cd, errmsg = reader:cdata(0, 12)
if not cd then
return nil, errmsg
end
local tag = cd:ulong()
local ftype = file_type[tag];
if ftype == 'ttc' then
local ver = cd:ulong();
local num = cd:ulong();
cd, errmsg = reader:cdata(12, 4 * num)
if not cd then
return nil, errmsg
end
local res = cd:ulongs(num);
return res
elseif ftype == 'otf' or ftype == 'ttf' then
return { 0 }
else
return nil, string.format("unknown file tag: %s", tag)
end
end
---@param reader widget.fonts.reader
---@param fofs integer
---@param ntbl integer
local function otf_name_table(reader, fofs, ntbl)
local cd_d = reader:cdata(fofs + 12, 16 * ntbl)
if not cd_d then
return nil, "error reading names table"
end
for _ = 1, ntbl do
local t = {-- tag, csum, ofs, len
cd_d:str(4), cd_d:ulong(), cd_d:ulong(), cd_d:ulong()
}
if t[1] == 'name' then
return reader:cdata(t[3], ceil(t[4] / 4) * 4)
end
end
return nil, "name table is missing"
end
---@param cdata widget.fonts.cdata
local function otf_name_records(cdata)
local nfmt, nnum, nofs = cdata:ushort(), cdata:ushort(), cdata:ushort()
assert(nfmt == 0, string.format("unsupported name table format: %s", nfmt))
local nr = {}
for i = 1, nnum do
nr[i] = { -- pid, eid, langid, nameid, len, ofs
cdata:ushort(), cdata:ushort(), cdata:ushort(),
cdata:ushort(), cdata:ushort(), cdata:ushort() + nofs
}
end
return nr
end
---@param cdata widget.fonts.cdata
local function otf_name(cdata, nr, nameid)
local function seek(pid, eid, lid)
for i = 1, #nr do
local t = nr[i]
local ok = (t[4] == nameid and t[1] == pid and t[2] == eid and
t[3] == lid)
if ok then return t end
end
end
local rec = seek(3, 1, 0x409)
or seek(3, 10, 0x409)
or seek(1, 0, 0) or seek(0, 3, 0)
or seek(0, 4, 0) or seek(0, 6, 0)
if not rec then return '' end
local s = cdata:pos(rec[6]):str(rec[5])
return (rec[1] == 3) and utf16betoutf8(s) or s
end
---@param reader widget.fonts.reader
local function otf_list(reader, fid, fofs)
local cd_fh, errmsg = reader:cdata(fofs, 12)
if not cd_fh then
return nil, errmsg
end
local tag = cd_fh:ulong()
local ntbl = cd_fh:ushort()
local cd_n = nil
cd_n, errmsg = otf_name_table(reader, fofs, ntbl)
if not cd_n then
return nil, errmsg
end
local ext = { id = fid; type = file_type[tag] or '' }
local nr = nil
nr, errmsg = otf_name_records(cd_n)
if not nr then
return nil, errmsg
end
local output = {
id = ext.id,
type = ext.type,
copyright = otf_name(cd_n, nr, 0),
family = otf_name(cd_n, nr, 1),
subfamily = otf_name(cd_n, nr, 2),
fullname = otf_name(cd_n, nr, 4),
version = otf_name(cd_n, nr, 5),
psname = otf_name(cd_n, nr, 6),
url = otf_name(cd_n, nr, 11),
license = otf_name(cd_n, nr, 13),
tfamily = otf_name(cd_n, nr, 16),
tsubfamily = otf_name(cd_n, nr, 17),
}
return output
end
--------------------------------------------------------------------------------
-- FontInfo Implementation
--------------------------------------------------------------------------------
---Helper function to check and update a font monospace attribute.
---@param font_data widget.fonts.data
---@return boolean checked
---@return string? errmsg
function FontInfo.check_is_monospace(font_data)
if font_data then
local loaded, fontren = pcall(renderer.font.load, font_data.path, 8, {})
if not loaded then
return false, "could not load font"
else
if fontren:get_width("|") == fontren:get_width("W") then
font_data.monospace = true
else
font_data.monospace = false
end
end
end
return true
end
---Constructor
---@param font_path? string
function FontInfo:new(font_path)
if type(font_path) == "string" then
self:read(font_path)
else
self.data = {}
self.path = ""
self.last_error = "no font given"
end
end
local function fontinfo_read_native(self, font_path)
---@type widget.fonts.data
local font
---@type string?
local errmsg
---@diagnostic disable-next-line
font, errmsg = renderer.font.get_metadata(font_path)
if not font then
self.last_error = errmsg
return font, errmsg
end
local add = true
local family = nil
if font.tfamily then
family = font.tfamily
elseif font.family then
family = font.family
end
local subfamily = nil
if font.tsubfamily then
subfamily = font.tsubfamily -- sometimes tsubfamily includes more styles
elseif font.subfamily then
subfamily = font.subfamily
end
-- fix font meta data or discard if empty
if family and subfamily then
font.fullname = family .. " " .. subfamily
elseif font.fullname and family and not font.fullname:ufind(family, 1, true) then
font.fullname = font.fullname .. " " .. family
elseif not font.fullname and family then
font.fullname = family
else
self.last_error = "font metadata is empty"
add = false
end
if add then
table.insert(self.data, font)
else
return nil, self.last_error
end
return true
end
local function fontinfo_read_nonnative(self, font_path)
self.reader = FontReader(font_path)
local tofs, errmsg = otf_offset(self.reader)
if not tofs then
self.last_error = errmsg
return nil, errmsg
end
local data = nil
for i = 1, #tofs do
data, errmsg = otf_list(self.reader, i - 1, tofs[i])
if data then
table.insert(self.data, data)
else
self.last_error = errmsg
return nil, errmsg
end
end
if self.data[1] then
local font = self.data[1]
local family = nil
if font.tfamily ~= "" then
family = font.tfamily
elseif font.family ~= "" then
family = font.family
end
local subfamily = nil
if font.tsubfamily ~= "" then
subfamily = font.tsubfamily -- sometimes tsubfamily includes more styles
elseif font.subfamily ~= "" then
subfamily = font.subfamily
end
-- fix font meta data or discard if empty
if family and subfamily then
font.fullname = family .. " " .. subfamily
elseif font.fullname ~= "" and family and not font.fullname:ufind(family, 1, true) then
font.fullname = font.fullname .. " " .. family
elseif font.fullname == "" and family then
font.fullname = family
else
self.data = {}
self.last_error = "font metadata is empty"
return nil, self.last_error
end
end
self.reader:close()
return true
end
---Open a font file and read its metadata.
---@param font_path string
---@return widget.fonts.info?
---@return string|nil errmsg
function FontInfo:read(font_path)
self.data = {}
self.path = font_path
local read, errmsg
---@diagnostic disable-next-line
if type(renderer.font.get_metadata) == "function" then
read, errmsg = fontinfo_read_native(self, font_path)
else
read, errmsg = fontinfo_read_nonnative(self, font_path)
end
if not read then
return read, errmsg
end
return self
end
---Get the amount of collections on the font file.
---@return integer
function FontInfo:embedded_fonts_count()
return #self.data
end
---Get the metadata of a previously read font file without
---copyright and license information which can be long.
---@param idx? integer Optional position of the embedded font
---@return widget.fonts.data?
---@return string|nil errmsg
function FontInfo:get_data(idx)
idx = idx or 1
local data = {}
if #self.data > 0 and self.data[idx] then
data = self.data[idx]
else
return nil, self.last_error
end
return {
path = self.path,
id = data.id,
type = data.type,
family = data.family,
subfamily = data.subfamily,
fullname = data.fullname,
version = data.version,
psname = data.psname,
url = data.url,
tfamily = data.tfamily,
tsubfamily = data.tsubfamily,
wwsfamily = data.wwsfamily,
wwssubfamily = data.wwssubfamily,
monospace = data.monospace or false
}
end
return FontInfo
+230
View File
@@ -0,0 +1,230 @@
local core = require "core"
local common = require "core.common"
local style = require "core.style"
local FontCache = require "libraries.widget.fonts.cache"
local StatusView = require "core.statusview"
---@class widget.fonts
local Fonts = {}
---@type widget.fonts.cache | nil
local fontcache = nil
---@type table<integer, string> | nil
local fonts = nil
---Last time the status view item was rendered
local last_statusview_render = 0
---The amount of fonts matching the user query
local matching_fonts = 0
---Flag that indicates if command view font picker is for monospaced
local pick_monospaced = false
---Generate the list of fonts displayed on the CommandView.
---@param monospaced? boolean Only display fonts detected as monospaced.
local function generate_fonts(monospaced)
if fontcache then
if fontcache.building then monospaced = false end
fonts = {}
for idx, f in ipairs(fontcache.fonts) do
if not monospaced or (monospaced and f.monospace) then
table.insert(fonts, f.fullname .. "||" .. idx)
end
end
end
end
---Helper function to split a string by a given delimeter.
local function split(s, delimeter, delimeter_pattern)
if not delimeter_pattern then
delimeter_pattern = delimeter
end
local result = {};
for match in (s..delimeter):gmatch("(.-)"..delimeter_pattern) do
table.insert(result, match);
end
return result;
end
local already_cleaning = false
---Clean the generated font cache used on command view to free some ram
local function clean_fonts_cache()
if not fontcache or already_cleaning then return end
if not fontcache.building and not fontcache.searching_monospaced then
fontcache = nil
fonts = nil
collectgarbage "collect"
else
already_cleaning = true
core.add_thread(function()
while fontcache.building or fontcache.searching_monospaced do
coroutine.yield(1)
end
if
core.active_view ~= core.command_view
or
(
core.command_view.label ~= "Select Font: "
and
core.command_view.label ~= "List only monospaced fonts?: "
)
then
fontcache = nil
fonts = nil
collectgarbage "collect"
already_cleaning = false
end
end)
end
end
---Launch the commandview and let the user select a font.
---@param callback fun(name:string, path:string)
---@param monospaced boolean
function Fonts.show_picker(callback, monospaced)
if not fontcache then fontcache = FontCache() end
pick_monospaced = monospaced
if not fontcache.building and (not monospaced or fontcache.monospaced) then
generate_fonts(monospaced)
else
core.add_thread(function()
while
(fontcache.building or (monospaced and not fontcache.monospaced))
and
core.active_view == core.command_view
and
core.command_view.label == "Select Font: "
do
core.command_view:update_suggestions()
coroutine.yield(2)
end
generate_fonts(monospaced)
core.command_view:update_suggestions()
end)
end
last_statusview_render = system.get_time()
core.command_view:enter("Select Font", {
submit = function(text, item)
callback(item.text, item.info)
clean_fonts_cache()
end,
suggest = function(text)
if fontcache.building or (monospaced and fontcache.searching_monospaced) then
generate_fonts(monospaced)
end
local res = common.fuzzy_match(fonts, text)
matching_fonts = #res
for i, name in ipairs(res) do
local font_info = split(name, "||")
local id = tonumber(font_info[2])
local font_data = fontcache.fonts[id]
res[i] = {
text = font_data.fullname,
info = font_data.path,
id = id
}
end
return res
end,
cancel = function()
clean_fonts_cache()
end
})
end
---Same as `show_picker()` but asks the user if he wants a monospaced font.
---@param callback fun(name:string, path:string)
function Fonts.show_picker_ask_monospace(callback)
if not fontcache then fontcache = FontCache() end
core.command_view:enter("List only monospaced fonts?", {
submit = function(text, item)
Fonts.show_picker(callback, item.mono)
end,
suggest = function(text)
local res = common.fuzzy_match({"Yes", "No"}, text)
for i, name in ipairs(res) do
res[i] = {
text = name,
mono = text == "Yes" and true or false
}
end
return res
end,
cancel = function()
clean_fonts_cache()
end
})
end
---Check if the font cache is been built.
---@return boolean building
function Fonts.cache_is_building()
if not fontcache then return false end
return fontcache:is_building()
end
---Remove current fonts cache file and regenerates a fresh one.
---@return boolean started False if cache is already been built
function Fonts.clean_cache()
if not fontcache then fontcache = FontCache() end
return fontcache:rebuild()
end
core.status_view:add_item({
predicate = function()
return core.active_view == core.command_view
and core.command_view.label == "Select Font: "
end,
name = "widget:font-select",
alignment = StatusView.Item.LEFT,
get_item = function()
local found = 0
local dots, status = "", ""
if fontcache then
if fontcache.building or fontcache.searching_monospaced then
dots = "."
if system.get_time() - last_statusview_render >= 3 then
last_statusview_render = system.get_time()
elseif system.get_time() - last_statusview_render >= 2 then
dots = "..."
elseif system.get_time() - last_statusview_render >= 1 then
dots = ".."
end
end
if fontcache.building then
status = " | searching system fonts" .. dots
elseif fontcache.searching_monospaced then
status = " | detecting monospaced fonts" .. dots
end
if fontcache.building or not pick_monospaced then
found = fontcache.found
else
found = fontcache.found_monospaced
end
end
return {
style.text,
style.font,
"Matches: "
.. tostring(matching_fonts)
.. " / "
.. tostring(found)
.. status
}
end,
position = 1
})
return Fonts
+223
View File
@@ -0,0 +1,223 @@
--
-- FontsList Widget.
-- @copyright Jefferson Gonzalez
-- @license MIT
--
local style = require "core.style"
local Widget = require "libraries.widget"
local Button = require "libraries.widget.button"
local ListBox = require "libraries.widget.listbox"
local FontDialog = require "libraries.widget.fontdialog"
local MessageBox = require "libraries.widget.messagebox"
---@class widget.fontslist.font : widget
---@field name string
---@field path string
---@class widget.fontslist : widget
---@overload fun(parent?:widget):widget.fontslist
---@field list widget.listbox
---@field add widget.button
---@field remove widget.button
---@field up widget.button
---@field down widget.button
---@field options renderer.fontoptions
---@field private dialog boolean
local FontsList = Widget:extend()
---Constructor
---@param parent widget
function FontsList:new(parent)
FontsList.super.new(self, parent)
self.type_name = "widget.fontslist"
self.border.width = 0
self.dialog = false
self.options = {}
self.list = ListBox(self)
local this = self
function self.list:on_mouse_pressed(button, x, y, clicks)
if not ListBox.on_mouse_pressed(self, button, x, y, clicks) then
return false
end
if clicks == 2 and not this.dialog then
this.dialog = true
local selected = this.list:get_selected()
local fontdata = this.list:get_row_data(selected)
---@type widget.inputdialog
local font = FontDialog(fontdata, this:get_options())
function font:on_save(fontdata, options)
this:set_options(options)
this:edit_font(selected, fontdata)
end
function font:on_close()
FontDialog.on_close(self)
self:destroy()
this.dialog = false
end
font:show()
end
return true
end
self.add = Button(self, "Add")
self.add:set_icon("B")
function self.add:on_click()
if #this.list.rows > 9 then
MessageBox.error("Max Fonts Reached", "Only a maximum of ten fonts can be added.")
return
end
if not this.dialog then
this.dialog = true
---@type widget.inputdialog
local font = FontDialog(nil, this:get_options())
function font:on_save(fontdata, options)
this:set_options(options)
this:add_font(fontdata)
end
function font:on_close()
FontDialog.on_close(self)
self:destroy()
this.dialog = false
end
font:show()
end
end
self.remove = Button(self, "Remove")
self.remove:set_icon("C")
function self.remove:on_click()
local selected = this.list:get_selected()
if selected then
if #this.list.rows > 1 then
this:remove_font(selected)
else
MessageBox.error("Font required", "A minimum of one font is needed")
end
else
MessageBox.error("No font selected", "Please select a font to remove")
end
end
self.up = Button(self, "")
self.up:set_icon("<")
self.up:set_tooltip("increase font priority")
function self.up:on_click()
local selected = this.list:get_selected()
if selected then
this.list:move_row_up(selected)
this:on_change()
else
MessageBox.error("No font selected", "Please select a font to move")
end
end
self.down = Button(self, "")
self.down:set_icon(">")
self.down:set_tooltip("decrease font priority")
function self.down:on_click()
local selected = this.list:get_selected()
if selected then
this.list:move_row_down(selected)
this:on_change()
else
MessageBox.error("No font selected", "Please select a font to move")
end
end
end
---Add a new font into the list.
---@param font widget.fontslist.font
function FontsList:add_font(font)
self.list:add_row({font.name}, font)
self.list:set_visible_rows()
self:on_change()
end
---Edit an existing font on the list.
---@param idx integer
---@param font widget.fontslist.font
function FontsList:edit_font(idx, font)
self.list:set_row(idx, {font.name})
self.list:set_row_data(idx, font)
self:on_change()
end
---Remove the given font from the list.
---@param idx integer
function FontsList:remove_font(idx)
self.list:remove_row(idx)
self:on_change()
end
---Return the fonts from the list.
---@return table<integer, string>
function FontsList:get_fonts()
local output = {}
local count = #self.list.rows
for i=1, count, 1 do
table.insert(output, self.list:get_row_data(i))
end
return output
end
---Set the global options for the fonts group
---@param options renderer.fontoptions
function FontsList:set_options(options)
self.options = options
end
---Get the global options for the font group
---@return renderer.fontoptions
function FontsList:get_options()
return self.options
end
function FontsList:update()
if not FontsList.super.update(self) then return false end
if self.size.x == 0 then
self.size.x = self.add:get_width()
+ (style.padding.x / 2) + self.remove:get_width()
+ (style.padding.x / 2) + self.up:get_width()
+ (style.padding.x / 2) + self.down:get_width() + (50 * SCALE)
self.size.y = self.add:get_height() + (style.padding.y * 2) + 100
end
self.list:set_position(0, 0)
self.list:set_size(
self.size.x,
self.size.y - self.add:get_height() - (style.padding.y * 2)
)
self.add:set_position(0, self.list:get_bottom() + style.padding.y)
self.remove:set_position(
self.add:get_right() + (style.padding.x / 2),
self.list:get_bottom() + style.padding.y
)
self.up:set_position(
self.remove:get_right() + (style.padding.x / 2),
self.list:get_bottom() + style.padding.y
)
self.down:set_position(
self.up:get_right() + (style.padding.x / 2),
self.list:get_bottom() + style.padding.y
)
return true
end
return FontsList
File diff suppressed because it is too large Load Diff
+88
View File
@@ -0,0 +1,88 @@
--
-- Input Dialog Widget.
-- @copyright Jefferson Gonzalez
-- @license MIT
--
local style = require "core.style"
local Button = require "libraries.widget.button"
local Dialog = require "libraries.widget.dialog"
local Label = require "libraries.widget.label"
local TextBox = require "libraries.widget.textbox"
---@class widget.inputdialog : widget.dialog
---@overload fun(title?:string, message?:string, text?:string):widget.inputdialog
---@field super widget.dialog
---@field message widget.label
---@field text widget.textbox
---@field save widget.button
---@field cancel widget.button
local InputDialog = Dialog:extend()
---Constructor
---@param title string
---@param message string
---@param text string
function InputDialog:new(title, message, text)
InputDialog.super.new(self, title or "Enter Value")
self.type_name = "widget.inputdialog"
self.message = Label(self.panel, message)
self.text = TextBox(self.panel, text or "")
local this = self
self.save = Button(self.panel, "Save")
self.save:set_icon("S")
function self.save:on_click()
this:on_save(this.text:get_text())
this:on_close()
end
self.cancel = Button(self.panel, "Cancel")
self.cancel:set_icon("C")
function self.cancel:on_click()
this:on_close()
end
end
---Called when the user clicks on save
---@param value string
function InputDialog:on_save(value) end
function InputDialog:update()
if not InputDialog.super.update(self) then return false end
self.message:set_position(style.padding.x/2, 0)
self.text:set_position(style.padding.x/2, self.message:get_bottom() + style.padding.y)
self.save:set_position(
style.padding.x/2,
self.text:get_bottom() + style.padding.y
)
self.cancel:set_position(
self.save:get_right() + style.padding.x,
self.text:get_bottom() + style.padding.y
)
self.panel.size.x = self.panel:get_real_width() + style.padding.x
self.panel.size.y = self.panel:get_real_height()
self.size.x = self:get_real_width() - (style.padding.x / 2)
self.size.y = self:get_real_height() + (style.padding.y / 2)
self.text:set_size(
self.size.x - style.padding.x,
self.text:get_real_height()
)
self.close:set_position(
self.size.x - self.close.size.x - (style.padding.x / 2),
style.padding.y / 2
)
return true
end
return InputDialog
+162
View File
@@ -0,0 +1,162 @@
--
-- ItemsList Widget.
-- @copyright Jefferson Gonzalez
-- @license MIT
--
local style = require "core.style"
local Widget = require "libraries.widget"
local Button = require "libraries.widget.button"
local ListBox = require "libraries.widget.listbox"
local InputDialog = require "libraries.widget.inputdialog"
local MessageBox = require "libraries.widget.messagebox"
---@class widget.itemslist : widget
---@overload fun(parent:widget?):widget.itemslist
---@field list widget.listbox
---@field add widget.button
---@field remove widget.button
local ItemsList = Widget:extend()
---Constructor
---@param parent widget
function ItemsList:new(parent)
ItemsList.super.new(self, parent)
self.type_name = "widget.itemslist"
self.border.width = 0
self.dialog = false
self.list = ListBox(self)
local this = self
function self.list:on_mouse_pressed(button, x, y, clicks)
if not ListBox.on_mouse_pressed(self, button, x, y, clicks) then
return false
end
if clicks == 2 and not this.dialog then
this.dialog = true
local selected = this.list:get_selected()
local selvalue = this.list:get_row_text(selected)
---@type widget.inputdialog
local input = InputDialog("Edit Item", "Enter the new item value:", selvalue)
function input:on_save(value)
this:edit_item(selected, value)
end
function input:on_close()
InputDialog.on_close(self)
self:destroy()
this.dialog = false
end
input:show()
end
return true
end
self.add = Button(self, "Add")
self.add:set_icon("B")
function self.add:on_click()
if not this.dialog then
---@type widget.inputdialog
local input = InputDialog("Add Item", "Enter the new item:")
function input:on_save(value)
this:add_item(value)
end
function input:on_close()
InputDialog.on_close(self)
self:destroy()
this.dialog = false
end
input:show()
end
end
self.remove = Button(self, "Remove")
self.remove:set_icon("C")
function self.remove:on_click()
local selected = this.list:get_selected()
if selected then
this:remove_item(selected)
else
MessageBox.error("No item selected", "Please select an item to remove")
end
end
end
---Add a new item into the list.
---@param text widget.styledtext | string
---@param data any
function ItemsList:add_item(text, data)
if type(text) == "string" then
text = {text}
end
self.list:add_row(text, data)
self.list:set_visible_rows()
self:on_change()
end
---Edit an existing item on the list.
---@param idx integer
---@param text widget.styledtext | string
---@param data any
function ItemsList:edit_item(idx, text, data)
if type(text) == "string" then
text = {text}
end
self.list:set_row(idx, text)
if data then
self.list:set_row_data(idx, data)
end
self:on_change()
end
---Remove the given item from the list.
---@param idx integer
function ItemsList:remove_item(idx)
self.list:remove_row(idx)
self:on_change()
end
---Return the items from the list.
---@return table<integer, string>
function ItemsList:get_items()
local output = {}
local count = #self.list.rows
for i=1, count, 1 do
table.insert(output, self.list:get_row_text(i))
end
return output
end
function ItemsList:update()
if not ItemsList.super.update(self) then return false end
if self.size.x == 0 then
self.size.x = self.add:get_width()
+ (style.padding.x / 2) + self.remove:get_width() + (50 * SCALE)
self.size.y = self.add:get_height() + (style.padding.y * 2) + 100
end
self.list:set_position(0, 0)
self.list:set_size(
self.size.x,
self.size.y - self.add:get_height() - (style.padding.y * 2)
)
self.add:set_position(0, self.list:get_bottom() + style.padding.y)
self.remove:set_position(
self.add:get_right() + (style.padding.x / 2),
self.list:get_bottom() + style.padding.y
)
return true
end
return ItemsList
+257
View File
@@ -0,0 +1,257 @@
--
-- KeyBinding Dialog Widget.
-- @copyright Jefferson Gonzalez
-- @license MIT
--
local keymap = require "core.keymap"
local style = require "core.style"
local Button = require "libraries.widget.button"
local Dialog = require "libraries.widget.dialog"
local Label = require "libraries.widget.label"
local Line = require "libraries.widget.line"
local ListBox = require "libraries.widget.listbox"
local MessageBox = require "libraries.widget.messagebox"
---@type widget.keybinddialog
local current_dialog = nil
---@class widget.keybinddialog : widget.dialog
---@overload fun():widget.keybinddialog
---@field super widget.dialog
---@field selected integer
---@field shortcuts widget.listbox
---@field add widget.button
---@field remove widget.button
---@field line widget.line
---@field message widget.label
---@field binding widget.label
---@field mouse_intercept widget.label
---@field save widget.button
---@field reset widget.button
---@field cancel widget.button
local KeybindDialog = Dialog:extend()
---Constructor
function KeybindDialog:new()
KeybindDialog.super.new(self, "Keybinding Selector")
self.type_name = "widget.keybinddialog"
self.selected = nil
local this = self
self.shortcuts = ListBox(self.panel)
self.shortcuts:set_size(100, 100)
function self.shortcuts:on_row_click(idx, data)
this.selected = idx
end
self.add = Button(self.panel, "Add")
self.add:set_icon("B")
function self.add:on_click()
this.shortcuts:add_row({"none"})
this.shortcuts:set_selected(#this.shortcuts.rows)
this.shortcuts:set_visible_rows()
this.selected = #this.shortcuts.rows
end
self.remove = Button(self.panel, "Remove")
self.remove:set_icon("C")
function self.remove:on_click()
local selected = this.shortcuts:get_selected()
if selected then
this.shortcuts:remove_row(selected)
this.shortcuts:set_selected(nil)
this.selected = nil
else
MessageBox.error("No shortcut selected", "Please select an shortcut to remove")
end
end
self.line = Line(self.panel)
self.message = Label(self.panel, "Press a key combination to change selected")
self.mouse_intercept = Label(self.panel, "Grab mouse events here")
self.mouse_intercept.border.width = 1
self.mouse_intercept.clickable = true
self.mouse_intercept:set_size(100, 100)
function self.mouse_intercept:on_mouse_pressed(button, x, y, clicks)
keymap.on_mouse_pressed(button, x, y, clicks)
return true
end
function self.mouse_intercept:on_mouse_wheel(y)
keymap.on_mouse_wheel(y)
return true
end
function self.mouse_intercept:on_mouse_enter(...)
Label.super.on_mouse_enter(self, ...)
self.border.color = style.caret
end
function self.mouse_intercept:on_mouse_leave(...)
Label.super.on_mouse_leave(self, ...)
self.border.color = style.text
end
self.save = Button(self.panel, "Save")
self.save:set_icon("S")
function self.save:on_click()
this:on_save(this:get_bindings())
this:on_close()
end
self.reset = Button(self.panel, "Reset")
function self.reset:on_click()
this:on_reset()
this:on_close()
end
self.cancel = Button(self.panel, "Cancel")
self.cancel:set_icon("C")
function self.cancel:on_click()
this:on_close()
end
end
---@param bindings table<integer, string>
function KeybindDialog:set_bindings(bindings)
self.shortcuts:clear()
for _, binding in ipairs(bindings) do
self.shortcuts:add_row({binding})
end
if #bindings > 0 then
self.shortcuts:set_selected(1)
self.selected = 1
end
self.shortcuts:set_visible_rows()
end
---@return table<integer, string>
function KeybindDialog:get_bindings()
local bindings = {}
for idx=1, #self.shortcuts.rows, 1 do
table.insert(bindings, self.shortcuts:get_row_text(idx))
end
return bindings
end
---Show the dialog and enable key interceptions
function KeybindDialog:show()
current_dialog = self
KeybindDialog.super.show(self)
end
---Hide the dialog and disable key interceptions
function KeybindDialog:hide()
current_dialog = nil
KeybindDialog.super.hide(self)
end
---Called when the user clicks on save
---@param bindings string
function KeybindDialog:on_save(bindings) end
---Called when the user clicks on reset
function KeybindDialog:on_reset() end
function KeybindDialog:update()
if not KeybindDialog.super.update(self) then return false end
self.shortcuts:set_position(style.padding.x/2, 0)
self.add:set_position(
style.padding.x/2,
self.shortcuts:get_bottom() + style.padding.y
)
self.remove:set_position(
self.add:get_right() + (style.padding.x/2),
self.shortcuts:get_bottom() + style.padding.y
)
self.line:set_position(
0,
self.remove:get_bottom() + style.padding.y
)
self.message:set_position(
style.padding.x/2,
self.line:get_bottom() + style.padding.y
)
self.mouse_intercept:set_position(
style.padding.x/2,
self.message:get_bottom() + style.padding.y
)
self.save:set_position(
style.padding.x/2,
self.mouse_intercept:get_bottom() + style.padding.y
)
self.reset:set_position(
self.save:get_right() + style.padding.x,
self.mouse_intercept:get_bottom() + style.padding.y
)
self.cancel:set_position(
self.reset:get_right() + style.padding.x,
self.mouse_intercept:get_bottom() + style.padding.y
)
self.panel.size.x = self.panel:get_real_width() + style.padding.x
self.panel.size.y = self.panel:get_real_height()
self.size.x = self:get_real_width() - (style.padding.x / 2)
self.size.y = self:get_real_height() + (style.padding.y / 2)
self.shortcuts:set_size(self.size.x - style.padding.x)
self.line:set_width(self.size.x - style.padding.x)
self.mouse_intercept:set_size(self.size.x - style.padding.x)
return true
end
--------------------------------------------------------------------------------
-- Intercept keymap events
--------------------------------------------------------------------------------
-- Same declarations as in core.keymap because modkey_map is not public
local macos = PLATFORM == "Mac OS X"
local modkeys_os = require("core.modkeys-" .. (macos and "macos" or "generic"))
local modkey_map = modkeys_os.map
local modkeys = modkeys_os.keys
---Copied from core.keymap because it is not public
local function key_to_stroke(k)
local stroke = ""
for _, mk in ipairs(modkeys) do
if keymap.modkeys[mk] then
stroke = stroke .. mk .. "+"
end
end
return stroke .. k
end
local keymap_on_key_pressed = keymap.on_key_pressed
function keymap.on_key_pressed(k, ...)
if current_dialog and current_dialog.selected then
local mk = modkey_map[k]
if mk then
keymap.modkeys[mk] = true
-- work-around for windows where `altgr` is treated as `ctrl+alt`
if mk == "altgr" then
keymap.modkeys["ctrl"] = false
end
current_dialog.shortcuts:set_row(current_dialog.selected, {key_to_stroke("")})
else
current_dialog.shortcuts:set_row(current_dialog.selected, {key_to_stroke(k)})
end
return true
else
return keymap_on_key_pressed(k, ...)
end
end
return KeybindDialog
+95
View File
@@ -0,0 +1,95 @@
--
-- Label Widget.
-- @copyright Jefferson Gonzalez
-- @license MIT
--
local style = require "core.style"
local Widget = require "libraries.widget"
---@class widget.label : widget
---@overload fun(parent:widget?, label?:string):widget.label
---@field clickable boolean
local Label = Widget:extend()
---Constructor
---@param parent widget
---@param label string
function Label:new(parent, label)
Label.super.new(self, parent)
self.type_name = "widget.label"
self.clickable = false
self.border.width = 0
self.custom_size = {x = 0, y = 0}
self:set_label(label or "")
end
---@param width? integer
---@param height? integer
function Label:set_size(width, height)
Label.super.set_size(self, width, height)
self.custom_size.x = self.size.x
self.custom_size.y = self.size.y
end
---Set the label text and recalculates the widget size.
---@param text string|widget.styledtext
function Label:set_label(text)
Label.super.set_label(self, text)
local font = self:get_font()
if self.custom_size.x <= 0 then
if type(text) == "table" then
self.size.x, self.size.y = self:draw_styled_text(text, 0, 0, true)
else
self.size.x = font:get_width(self.label)
self.size.y = font:get_height()
end
if self.border.width > 0 then
self.size.x = self.size.x + style.padding.x
self.size.y = self.size.y + style.padding.y
end
end
end
function Label:update()
if not Label.super.update(self) then return false end
if self.custom_size.x <= 0 then
-- update the size
self:set_label(self.label)
end
return true
end
function Label:draw()
if not self:is_visible() then return false end
self:draw_border()
local px = self.border.width > 0 and (style.padding.x / 2) or 0
local py = self.border.width > 0 and (style.padding.y / 2) or 0
local posx, posy = self.position.x + px, self.position.y + py
if type(self.label) == "table" then
self:draw_styled_text(self.label, posx, posy)
else
renderer.draw_text(
self:get_font(),
self.label,
posx,
posy,
self.foreground_color or style.text
)
end
return true
end
return Label
+61
View File
@@ -0,0 +1,61 @@
--
-- Line Widget.
-- @copyright Jefferson Gonzalez
-- @license MIT
--
local style = require "core.style"
local Widget = require "libraries.widget"
---@class widget.line : widget
---@overload fun(parent?:widget, thickness?:integer, padding?:number):widget.line
---@field public padding integer
---@field private custom_width number
local Line = Widget:extend()
---Constructor
---@param parent widget
---@param thickness integer
---@param padding number
function Line:new(parent, thickness, padding)
Line.super.new(self, parent)
self.type_name = "widget.line"
self.size.y = thickness or 2
self.custom_width = nil
self.border.width = 0
self.padding = padding or (style.padding.x / 2)
end
---Set the thickness of the line
---@param thickness number
function Line:set_thickness(thickness)
self.size.y = thickness or 2
end
---Set a custom width for the line
---@param width number
function Line:set_width(width)
self.custom_width = width
self.size.x = width
end
function Line:draw()
if not self:is_visible() then return false end
if not self.custom_width then
self.size.x = self.parent.size.x - (self.padding * 2)
end
renderer.draw_rect(
self.position.x + self.padding,
self.position.y,
self.size.x,
self.size.y,
self.foreground_color or style.caret
)
return true
end
return Line
+926
View File
@@ -0,0 +1,926 @@
--
-- ListBox Widget.
-- @copyright Jefferson Gonzalez
-- @license MIT
--
local core = require "core"
local style = require "core.style"
local Widget = require "libraries.widget"
local MessageBox = require "libraries.widget.messagebox"
---@class widget.listbox.column
---@field public name string
---@field public width string
---@field public expand boolean
---@field public longest integer
---@alias widget.listbox.drawcol fun(self, row, x, y, font, color, only_calc)
---@alias widget.listbox.filtercb fun(self:widget.listbox, idx:integer, row:widget.listbox.row, data:any):number?
---@alias widget.listbox.row table<integer, renderer.font|widget.fontreference|renderer.color|integer|string|widget.listbox.drawcol>
---@alias widget.listbox.colpos table<integer,integer>
---@class widget.listbox : widget
---@overload fun(parent:widget?):widget.listbox
---@field rows widget.listbox.row[]
---@field private row_data any
---@field private rows_original widget.listbox.row[]
---@field private row_data_original any
---@field private columns widget.listbox.column[]
---@field private positions widget.listbox.colpos[]
---@field private mouse widget.position
---@field private selected_row integer
---@field private hovered_row integer
---@field private largest_row integer
---@field private expand boolean
---@field private visible_rows table<integer, integer>
---@field private visible_rendered boolean
---@field private last_scale integer
---@field private last_offset integer
local ListBox = Widget:extend()
---Indicates on a widget.listbox.row that the end
---of a column was reached.
---@type integer
ListBox.COLEND = 1
---Indicates on a widget.listbox.row that a new line
---follows while still rendering the same column.
---@type integer
ListBox.NEWLINE = 2
---Constructor
---@param parent widget
function ListBox:new(parent)
ListBox.super.new(self, parent)
self.type_name = "widget.listbox"
self.scrollable = true
self.rows = {}
self.row_data = {}
self.rows_original = {}
self.row_data_original = {}
self.rows_idx_original = {}
self.columns = {}
self.positions = {}
self.selected_row = 0
self.hovered_row = 0
self.largest_row = 0
self.expand = false
self.visible_rows = {}
self.visible_rendered = false
self.last_scale = 0
self.last_offset = 0
self:set_size(200, (self:get_font():get_height() + (style.padding.y*2)) * 3)
end
---Set which rows to show using the specified match string or callback,
---if nil all rows are restored.
---@param match? string | widget.listbox.filtercb
function ListBox:filter(match)
if (not match or match == "") and #self.rows_original > 0 then
self:clear()
for idx, row in ipairs(self.rows_original) do
self:add_row(row, self.row_data_original[idx])
end
self.rows_original = {}
self.row_data_original = {}
self.rows_idx_original = {}
return
elseif match and match ~= "" then
self.rows_original = #self.rows_original > 0
and self.rows_original or self.rows
self.row_data_original = #self.row_data_original > 0
and self.row_data_original or self.row_data
self.rows_idx_original = {}
self:clear()
local match_type = type(match)
local rows = {}
for idx, row in ipairs(self.rows_original) do
local score
if match_type == "function" then
score = match(self, idx, row, self.row_data_original[idx])
else
score = system.fuzzy_match(self:get_row_text(row), match, false)
end
if score then
table.insert(rows, {row, self.row_data_original[idx], score, idx})
end
end
table.sort(rows, function(a, b) return a[3] > b[3] end)
for _, row in ipairs(rows) do
self:add_row(row[1], row[2])
table.insert(self.rows_idx_original, row[4])
end
end
end
---If no width is given column will be set to automatically
---expand depending on the longest element
---@param name string
---@param width? number
---@param expand? boolean
function ListBox:add_column(name, width, expand)
local column = {
name = name,
width = width or self:get_font():get_width(name),
expand = expand and expand or (width and false or true)
}
table.insert(self.columns, column)
end
---You can give it a table a la statusview style where you pass elements
---like fonts, colors, ListBox.COLEND, ListBox.NEWLINE and multiline strings.
---@param row widget.listbox.row
---@param data any Associated with the row and given to on_row_click()
function ListBox:add_row(row, data)
table.insert(self.rows, row)
table.insert(self.positions, self:get_col_positions(row))
if type(data) ~= "nil" then
self.row_data[#self.rows] = data
end
-- increase columns width if needed
if #self.columns > 0 then
local ridx = #self.rows
for col, pos in ipairs(self.positions[ridx]) do
if self.columns[col].expand then
local w = self:draw_row_range(ridx, row, pos[1], pos[2], 1, 1, true)
-- store the row with longest column for cheaper calculation
self.columns[col].width = math.max(self.columns[col].width, w)
if self.columns[col].width < w then
self.columns[col].longest = ridx
end
end
end
end
-- precalculate the row size and position
self:calc_row_size_pos(#self.rows)
end
---Calculate a row position and size and store it on the row it
---self on the fields x, y, w, h
---@param ridx integer
function ListBox:calc_row_size_pos(ridx)
local x = self.border.width
local y = self.border.width
if ridx == 1 then
-- if columns are enabled leave some space to render them
if #self.columns > 0 then
y = y + self:get_font():get_height() + style.padding.y
end
else
y = y + self.rows[ridx-1].y + self.rows[ridx-1].h
end
self:draw_row(ridx, x, y, true)
end
---Recalculate all row sizes and positions which should be only required
---when lite-xl ui scale changes or a row is removed from the list
function ListBox:recalc_all_rows()
for ridx, _ in ipairs(self.rows) do
self:calc_row_size_pos(ridx)
end
end
---Calculates the scrollable size based on the last row of the list.
---@return number
function ListBox:get_scrollable_size()
local size = self.size.y
local rows = #self.rows
if rows > 0 and self.rows[rows].y then
size = math.max(size, self.rows[rows].y + self.rows[rows].h)
end
return size
end
function ListBox:get_h_scrollable_size()
local size = self.size.x
local rows = #self.rows
if rows > 0 and self.rows[rows].x then
size = math.max(size, self.rows[rows].x + self.rows[rows].w)
end
return size
end
---Detects the rows that are visible each time the content is scrolled,
---this way the draw function will only process the visible rows.
function ListBox:set_visible_rows()
local _, oy = self:get_content_offset()
local h = self.size.y
-- substract column heading from list height
local colh = 0
if #self.columns > 0 then
colh = self:get_font():get_height() + style.padding.y
h = h - colh
end
-- start from nearest row relative to scroll direction for
-- better performance on long lists
local idx, total, step = 1, #self.rows, 1
if #self.visible_rows > 0 then
if oy < self.last_offset or not self.visible_rendered then
idx = self.visible_rows[1]
self.visible_rendered = true
else
idx = self.visible_rows[#self.visible_rows]
total = 1
step = -1
end
end
oy = oy - self.position.y
self.visible_rows = {}
local first_visible = false
local height = 0
for i=idx, total, step do
local row = self.rows[i]
if row then
local top = row.y - colh + row.h + oy
local visible = false
local visible_area = h - top
if top < 0 and (top + row.h) > 0 then
visible = true
elseif top >= 0 and top < h then
visible = true
end
if visible and height <= h then
table.insert(self.visible_rows, i)
first_visible = true
-- store only the visible height
if top < 0 then
height = height + (top + row.h)
else
if visible_area > row.h then
height = height + row.h
else
height = height + visible_area
end
end
elseif first_visible then
table.insert(self.visible_rows, i)
break
end
end
end
-- append one more row if possible to fill possible empty spaces of
-- incomplete row height calculation above (bad math skills workarounds)
local last_row = self.visible_rows[#self.visible_rows]
local first_row = self.visible_rows[1]
if #self.visible_rows > 0 then
if step == 1 then
if self.rows[last_row+1] then
table.insert(self.visible_rows, last_row+1)
end
else
if self.rows[first_row-2] and first_row-2 ~= 1 then
table.insert(self.visible_rows, first_row-2)
elseif self.rows[last_row+1] then
table.insert(self.visible_rows, last_row+1)
end
-- sort for proper subsequent loop interations
table.sort(
self.visible_rows,
function(val1, val2) return val1 < val2 end
)
local frow = self.visible_rows[1]
for i, _ in ipairs(self.visible_rows) do
if self.rows[frow] then
self.visible_rows[i] = frow
frow = frow + 1
end
end
if #self.visible_rows > 1 then
if
self.visible_rows[#self.visible_rows]
==
self.visible_rows[#self.visible_rows-1]
then
table.remove(self.visible_rows, #self.visible_rows)
end
end
end
end
end
-- Solution to safely remove elements from array table:
-- found at https://stackoverflow.com/a/53038524
local function array_remove(t, fnKeep)
local j, n = 1, #t;
for i=1, n do
if (fnKeep(t, i, j)) then
if (i ~= j) then
t[j] = t[i];
t[i] = nil;
end
j = j + 1;
else
t[i] = nil;
end
end
return t;
end
---Remove a given row index from the list.
---@param ridx integer
function ListBox:remove_row(ridx)
if not self.rows[ridx] then return end
if #self.rows_idx_original > 0 then
MessageBox.error(
"Can not remove row",
"Rows can not be removed when the list is filtered."
)
return
end
local last_col = false
local row_y = self.rows[ridx].y
local row_h = self.rows[ridx].h
if ridx == #self.rows then
last_col = true
end
local fields = { "rows", "positions", "row_data" }
for _, field in ipairs(fields) do
array_remove(self[field], function(_, i, _)
if i == ridx then
return false
end
return true
end)
end
for _, col in ipairs(self.columns) do
if col.longest == ridx then
col.longest = nil
end
end
if not last_col and #self.rows > 0 then
for idx=ridx, #self.rows, 1 do
self.rows[idx].y = self.rows[idx].y - row_h
end
end
local visible_removed = false
array_remove(self.visible_rows, function(t, i, _)
if t[i] == ridx then
visible_removed = true
return false
end
return true
end)
-- make visible rows sequence correctly incremental
if visible_removed and #self.visible_rows > 0 then
local first_row = self.visible_rows[1]
for i, _ in ipairs(self.visible_rows) do
self.visible_rows[i] = first_row
first_row = first_row + 1
end
self:set_visible_rows()
end
end
---Set the row that is currently active/selected.
---@param idx? integer
function ListBox:set_selected(idx)
self.selected_row = idx or 0
end
---Get the row that is currently active/selected.
---@return integer | nil
function ListBox:get_selected()
if self.selected_row > 0 then
return self.selected_row
end
return nil
end
---Change the content assigned to a row.
---@param idx integer
---@param row widget.listbox.row
function ListBox:set_row(idx, row)
--TODO: recalculate subsequent row sizes and max col width if needed
if self.rows[idx] then
self.rows[idx] = row
if #self.rows_idx_original > 0 then
self.rows_original[self.rows_idx_original[idx]] = row
end
-- precalculate the row size and position
self:calc_row_size_pos(idx)
end
end
---Change the data assigned to a row.
---@param idx integer
---@param data any|nil
function ListBox:set_row_data(idx, data)
if self.rows[idx] then
self.row_data[idx] = data
if #self.rows_idx_original > 0 then
self.row_data_original[self.rows_idx_original[idx]] = data
end
end
end
---Get the data associated with a row.
---@param idx integer
---@return any|nil
function ListBox:get_row_data(idx)
if type(self.row_data[idx]) ~= "nil" then
return self.row_data[idx]
end
return nil
end
---Get the text only of a styled row.
---@param row integer | table
---@return string
function ListBox:get_row_text(row)
local text = ""
row = type(row) == "table" and row or self.rows[row]
if row then
for _, element in ipairs(row) do
if type(element) == "string" then
text = text .. element
elseif element == ListBox.NEWLINE then
text = text .. "\n"
end
end
end
return text
end
---Get the starting and ending position of columns in a row table.
---@param row widget.listbox.row
---@return widget.listbox.colpos
function ListBox:get_col_positions(row)
local positions = {}
local idx = 1
local idx_start = 1
local row_len = #row
for _, element in ipairs(row) do
if element == ListBox.COLEND then
table.insert(positions, { idx_start, idx-1 })
idx_start = idx + 1
elseif idx == row_len then
table.insert(positions, { idx_start, idx })
end
idx = idx + 1
end
return positions
end
---Move a row to the desired position if possible.
---@param idx integer
---@param pos integer
---@return boolean moved
function ListBox:move_row_to(idx, pos)
if idx == pos or (pos == #self.rows and #self.rows == 1) then return false end
if pos < 1 then pos = 1 end
local row = table.remove(self.rows, idx)
local position = table.remove(self.positions, idx)
if pos <= #self.rows then
table.insert(self.rows, pos, row)
table.insert(self.positions, pos, position)
else
table.insert(self.rows, row)
table.insert(self.positions, position)
pos = #self.rows
end
local moved_row_data = self.row_data[idx]
local swapped_row_data = self.row_data[pos]
self.row_data[idx] = swapped_row_data
self.row_data[pos] = moved_row_data
self.selected_row = pos
self:recalc_all_rows()
self:set_visible_rows()
return true
end
---Move a row one position up if possible.
---@param idx integer
---@return boolean moved
function ListBox:move_row_up(idx)
return self:move_row_to(idx, idx-1)
end
---Move a row one position down if possible.
---@param idx integer
---@return boolean moved
function ListBox:move_row_down(idx)
self:move_row_to(idx, idx+1)
end
---Enables expanding the element to total size of parent on content updates.
function ListBox:enable_expand(expand)
self.expand = expand
if expand then
self:resize_to_parent()
end
end
---Resizes the listbox to match the parent size
function ListBox:resize_to_parent()
self.size.x = self.parent.size.x
- (self.border.width * 2)
self.size.y = self.parent.size.y
- (self.border.width * 2)
self:set_visible_rows()
end
---Remove all the rows from the listbox.
function ListBox:clear()
self.rows = {}
self.row_data = {}
self.positions = {}
self.selected_row = 0
self.hovered_row = 0
for cidx, col in ipairs(self.columns) do
col.width = self:get_col_width(cidx)
col.longest = nil
end
self:set_visible_rows()
end
---Render or calculate the size of the specified range of elements in a row.
---@param ridx integer
---@param row widget.listbox.row
---@param start_idx integer
---@param end_idx integer
---@param x integer
---@param y integer
---@param only_calc boolean
---@return integer width
---@return integer height
function ListBox:draw_row_range(ridx, row, start_idx, end_idx, x, y, only_calc)
local font = self:get_font()
local color = self.foreground_color or style.text
local width = 0
local height = font:get_height()
local new_line = false
local nx = x
for pos=start_idx, end_idx, 1 do
local element = row[pos]
local ele_type = type(element)
if
ele_type == "userdata"
or
(
ele_type == "table"
and
(element.container or type(element[1]) == "userdata")
)
then
if ele_type == "table" and element.container then
font = element.container[element.name]
else
font = element
end
elseif ele_type == "table" then
color = element
elseif element == ListBox.NEWLINE then
y = y + font:get_height()
nx = x
new_line = true
elseif ele_type == "function" then
local w, h = element(self, ridx, nx, y, font, color, only_calc)
nx = nx + width
height = math.max(height, h)
width = width + w
elseif ele_type == "string" then
local rx, ry, w, h = self:draw_text_multiline(
font, element, nx, y, color, only_calc
)
y = ry
nx = rx
if new_line then
height = height + h
width = math.max(width, w)
new_line = false
else
height = math.max(height, h)
width = width + w
end
end
end
return width, height
end
---Calculate the overall width of a column.
---@param col integer
---@return number
function ListBox:get_col_width(col)
if self.columns[col] then
if not self.columns[col].expand then
return self.columns[col].width
else
-- if longest is available don't iterate the entire row list
if self.columns[col].longest then
local id = self.columns[col].longest
local width = self:draw_row_range(
id,
self.rows[id],
self.positions[id][col][1],
self.positions[id][col][2],
1,
1,
true
)
return width
end
local width = self:get_font():get_width(self.columns[col].name)
for id, row in ipairs(self.rows) do
local w, h = self:draw_row_range(
id,
row,
self.positions[id][col][1],
self.positions[id][col][2],
1,
1,
true
)
width = math.max(width, w)
end
return width
end
end
return 0
end
---Draw the column headers of the list if available
---@param w integer
---@param h integer
---@param ox number Horizontal offset
function ListBox:draw_header(w, h, ox)
local x = self.position.x
local y = self.position.y
renderer.draw_rect(x, y, w, h, style.background2)
x = ox + self.position.x
for _, col in ipairs(self.columns) do
renderer.draw_text(
self:get_font(),
col.name,
x + style.padding.x / 2,
y + style.padding.y / 2,
style.accent
)
x = x + col.width + style.padding.x
end
end
---Draw or calculate the dimensions of the given row position and stores
---the size and position on the row it self.
---@param row integer
---@param x integer
---@param y integer
---@param only_calc? boolean
---@return integer width
---@return integer height
function ListBox:draw_row(row, x, y, only_calc)
local w, h = 0, 0
if not only_calc and self.rows[row].w then
w, h = self.rows[row].w, self.rows[row].h
w = self.largest_row > 0 and self.largest_row or w
if self.selected_row == row then
renderer.draw_rect(x, y, w, h, style.selection)
end
local mouse = self.mouse
if
mouse.x >= x
and
mouse.x <= x + w
and
mouse.y >= y
and
mouse.y <= y + h
then
renderer.draw_rect(x, y, w, h, style.line_highlight)
self.hovered_row = row
end
w, h = 0, 0
end
-- add padding on top
y = y + (style.padding.y / 2)
if #self.columns > 0 then
for col, coldata in ipairs(self.columns) do
-- padding on left
w = w + style.padding.x / 2
local cw, ch = self:draw_row_range(
row,
self.rows[row],
self.positions[row][col][1],
self.positions[row][col][2],
x + w,
y,
only_calc
)
-- add column width and end with padding on right
w = w + coldata.width + (style.padding.x / 2)
-- only store column height if bigger than previous one
h = math.max(h, ch)
end
else
local cw, ch = self:draw_row_range(
row,
self.rows[row],
1,
#self.rows[row],
x + style.padding.x / 2,
y,
only_calc
)
h = ch
w = cw + style.padding.x
end
-- Add padding on top and bottom
h = h + style.padding.y
if only_calc or not self.rows[row].w then
-- store the dimensions for inexpensive subsequent hover calculation
self.rows[row].w = w
self.rows[row].h = h
-- TODO: performance improvement, render only the visible rows on the view?
self.rows[row].x = x
self.rows[row].y = y - (style.padding.y / 2)
end
-- return height with padding on top and bottom
return w, h
end
---
--- Events
---
function ListBox:on_mouse_leave(x, y, dx, dy)
ListBox.super.on_mouse_leave(self, x, y, dx, dy)
self.hovered_row = 0
end
function ListBox:on_mouse_moved(x, y, dx, dy)
ListBox.super.on_mouse_moved(self, x, y, dx, dy)
self.hovered_row = 0
end
function ListBox:on_click(button, x, y)
if button == "left" and self.hovered_row > 0 then
self.selected_row = self.hovered_row
self:on_row_click(self.hovered_row, self.row_data[self.hovered_row])
end
end
---You can overwrite this to listen to item clicks
---@param idx integer
---@param data any Data associated with the row
function ListBox:on_row_click(idx, data) end
function ListBox:update()
if not ListBox.super.update(self) then return false end
-- only calculate columns width on scale change since this can be expensive
if self.last_scale ~= SCALE then
if #self.columns > 0 then
for col, column in ipairs(self.columns) do
column.width = self:get_col_width(col)
end
end
self:recalc_all_rows()
self.last_scale = SCALE
end
local _, oy = self:get_content_offset()
if self.last_offset ~= oy then
self:set_visible_rows()
self.last_offset = oy
end
return true
end
function ListBox:draw()
if not ListBox.super.draw(self) then return false end
if #self.rows > 0 and #self.visible_rows <= 0 then
self:set_visible_rows()
end
local new_width = 0
local new_height = 0
local font = self:get_font()
if #self.columns > 0 then
new_height = new_height + font:get_height() + style.padding.y
for _, col in ipairs(self.columns) do
new_width = new_width + col.width + style.padding.x
end
end
if self.expand then
self:resize_to_parent()
self.largest_row = self.size.x
- (self.parent.border.width * 2)
end
-- Normalize the offset position
local opx, opy = self.parent:get_content_offset()
if not self.parent.parent and not self.defer_draw then
-- TODO: inspect why is this workaround needed
-- Without it wrong offset occurs on child listviews of a single parent
-- like in the case of the recent projects in EmptyView.
opy = 0
end
local ox, oy = self:get_content_offset()
oy = oy - opy
if #self.visible_rows > 0 then
oy = oy + (self.rows[self.visible_rows[1]].y - new_height)
end
oy = oy - (self.position.y - self.parent.position.y)
ox = ox - opx
ox = ox - (self.position.x - self.parent.position.x)
local x = ox + self.position.x + self.border.width
local y = oy + self.position.y + self.border.width + new_height
core.push_clip_rect(
self.position.x, self.position.y, self.size.x, self.size.y
)
for _, ridx in ipairs(self.visible_rows) do
if self.rows[ridx] then
local w, h = self:draw_row(ridx, x, y)
new_width = math.max(new_width, w)
new_height = new_height + h
y = y + h
end
end
if not self.expand then
self.largest_row = self:get_width() - (self.border.width*2)
self.size.x = self.largest_row
end
if #self.columns > 0 then
self:draw_header(
self.largest_row,
font:get_height() + style.padding.y,
ox
)
end
core.pop_clip_rect()
self:draw_border()
self:draw_scrollbar()
return true
end
return ListBox
+343
View File
@@ -0,0 +1,343 @@
--
-- MessageBox Widget/Dialog.
-- @copyright Jefferson Gonzalez
-- @license MIT
--
local core = require "core"
local common = require "core.common"
local style = require "core.style"
local Widget = require "libraries.widget"
local Button = require "libraries.widget.button"
local Label = require "libraries.widget.label"
---@class widget.messagebox : widget
---@overload fun(parent?:widget, title?:string, message?:string|widget.styledtext, icon?:widget.messagebox.icontype, icon_color?:renderer.color):widget.messagebox
---@field private title widget.label
---@field private icon widget.label
---@field private message widget.label
---@field private buttons widget.button[]
local MessageBox = Widget:extend()
MessageBox.icon_huge_font = style.icon_font:copy(50 * SCALE)
MessageBox.ICON_ERROR = "X"
MessageBox.ICON_INFO = "i"
MessageBox.ICON_WARNING = "!"
---@alias widget.messagebox.icontype
---|>`MessageBox.ICON_ERROR`
---| `MessageBox.ICON_INFO`
---| `MessageBox.ICON_WARNING`
MessageBox.BUTTONS_OK = 1
MessageBox.BUTTONS_OK_CANCEL = 2
MessageBox.BUTTONS_YES_NO = 3
MessageBox.BUTTONS_YES_NO_CANCEL = 4
---@alias widget.messagebox.buttonstype
---|>`MessageBox.BUTTONS_OK`
---| `MessageBox.BUTTONS_OK_CANCEL`
---| `MessageBox.BUTTONS_YES_NO`
---| `MessageBox.BUTTONS_YES_NO_CANCEL`
---@alias widget.messagebox.onclosehandler fun(self: widget.messagebox, button_id: integer, button: widget.button)
---Constructor
---@param parent widget
---@param title string
---@param message string | widget.styledtext
---@param icon widget.messagebox.icontype
---@param icon_color renderer.color
function MessageBox:new(parent, title, message, icon, icon_color)
MessageBox.super.new(self, parent)
self.type_name = "widget.messagebox"
self.draggable = true
self.scrollable = true
self.title = Label(self, "")
self.icon = Label(self, "")
self.message = Label(self, "")
self.buttons = {}
self.last_scale = SCALE
self:set_title(title or "")
self:set_message(message or "")
self:set_icon(icon or "", icon_color)
end
---Change the message box title.
---@param text string | widget.styledtext
function MessageBox:set_title(text)
self.title:set_label(text)
end
---Change the message box icon.
---@param icon widget.messagebox.icontype
---@param color? renderer.color
function MessageBox:set_icon(icon, color)
if not color then
color = style.text
if icon == MessageBox.ICON_WARNING then
color = { common.color "#c7763e" }
elseif icon == MessageBox.ICON_ERROR then
color = { common.color "#c73e3e" }
end
end
self.icon:set_label({ MessageBox.icon_huge_font, color, icon })
end
---Change the message box message.
---@param text string | widget.styledtext
function MessageBox:set_message(text)
self.message:set_label(text)
end
---Adds a new button to the message box.
---@param button_or_label string|widget.button
function MessageBox:add_button(button_or_label)
if type(button_or_label) == "table" then
table.insert(self.buttons, button_or_label)
else
local button = Button(self, button_or_label)
table.insert(self.buttons, button)
end
local button_id = #self.buttons
local new_button = self.buttons[button_id]
local on_click = new_button.on_click
new_button.on_click = function(this, ...)
on_click(this, ...)
self:on_close(button_id, new_button)
end
end
---Calculate the width of all buttons combined.
---@return number width
function MessageBox:get_buttons_width()
local width = 0
if #self.buttons > 0 then
for _, button in ipairs(self.buttons) do
width = width + button:get_width()
end
-- add padding inbetween buttons
if #self.buttons > 1 then
width = width + ((style.padding.x) * (#self.buttons - 1))
end
end
return width
end
---Get the height of biggest button.
---@return number height
function MessageBox:get_buttons_height()
local height = 0
if #self.buttons > 0 then
for _, button in ipairs(self.buttons) do
height = math.max(height, button:get_height())
end
end
return height
end
---Position the buttons relative to the message.
function MessageBox:reposition_buttons()
local buttons_width = self:get_buttons_width()
local buttons_x = ((self.size.x / 2) - (buttons_width / 2))
local buttons_y = self.message:get_bottom() + (style.padding.y * 2)
if self.icon.label[3] ~= "" then
buttons_y = math.max(
buttons_y, self.icon:get_bottom() + (style.padding.y * 2)
)
end
for _, button in ipairs(self.buttons) do
button:set_position(buttons_x, buttons_y)
buttons_x = buttons_x + button:get_width() + style.padding.x
end
end
---Calculate the MessageBox size, centers it relative to screen and shows it.
function MessageBox:show()
MessageBox.super.show(self)
self:update()
self:centered()
end
---Called when the user clicks one of the buttons in the message box.
---@param button_id integer
---@param button widget.button
---@diagnostic disable-next-line
function MessageBox:on_close(button_id, button) self:hide() end
function MessageBox:update()
if not MessageBox.super.update(self) then return false end
if self.last_scale ~= SCALE then
MessageBox.icon_huge_font = style.icon_font:copy(50 * SCALE)
self.last_scale = SCALE
self.icon.label[1] = MessageBox.icon_huge_font
elseif self.updated then
self.updated = true
return
end
local width = math.max(self.title:get_width())
width = math.max(width, self.message:get_width() + self.icon:get_width())
width = math.max(width, self:get_buttons_width())
local height = self.title:get_height() + style.padding.y
if self.icon.label[3] == "" then
height = height + self.message:get_height() + (style.padding.y * 2)
else
height = height
+ math.max(self.icon:get_height(), self.message:get_height())
+ (style.padding.y * 2)
end
height = height + self:get_buttons_height()
self:set_size(width + style.padding.x * 2, height + style.padding.y * 2)
self.title:set_position(
style.padding.x / 2,
style.padding.y / 2
)
self.icon:set_position(
style.padding.x,
self.title:get_bottom() + style.padding.y
)
if self.icon.label[3] == "" then
self.message:set_position(
style.padding.x,
self.title:get_bottom() + style.padding.y
)
else
local msg_y = self.title:get_bottom() + style.padding.y + 10
if self.icon:get_height() > self.message:get_height() then
msg_y = (self.icon:get_height() / 2)
- (self.message:get_height() / 2)
+ self.title:get_bottom() + style.padding.y
end
self.message:set_position(
self.icon:get_width() + (style.padding.x * 2) - (style.padding.x / 2),
msg_y
)
end
self:reposition_buttons()
return true
end
---We overwrite default draw function to draw the title background.
function MessageBox:draw()
if not self:is_visible() then return false end
Widget.super.draw(self)
self:draw_border()
if self.background_color then
self:draw_background(self.background_color)
else
self:draw_background(
self.parent and style.background or style.background2
)
end
if #self.childs > 0 then
core.push_clip_rect(
self.position.x,
self.position.y,
self.size.x,
self.size.y
)
end
-- draw the title background
renderer.draw_rect(
self.position.x,
self.position.y,
self.size.x, self.title:get_height() + style.padding.y,
style.selection
)
for i=#self.childs, 1, -1 do
self.childs[i]:draw()
end
if #self.childs > 0 then
core.pop_clip_rect()
end
self:draw_scrollbar()
return true
end
---Wrapper to easily show a message box.
---@param title string | widget.styledtext
---@param message string | widget.styledtext
---@param icon widget.messagebox.icontype
---@param icon_color? renderer.color
---@param on_close? widget.messagebox.onclosehandler
---@param buttons? widget.messagebox.buttonstype
function MessageBox.alert(title, message, icon, icon_color, on_close, buttons)
buttons = buttons or MessageBox.BUTTONS_OK
---@type widget.messagebox
local msgbox = MessageBox(nil, title, message, icon, icon_color)
if buttons == MessageBox.BUTTONS_OK_CANCEL then
msgbox:add_button("Ok")
msgbox:add_button("Cancel")
elseif buttons == MessageBox.BUTTONS_YES_NO then
msgbox:add_button("Yes")
msgbox:add_button("No")
elseif buttons == MessageBox.BUTTONS_YES_NO_CANCEL then
msgbox:add_button("Yes")
msgbox:add_button("No")
msgbox:add_button("Cancel")
else
msgbox:add_button("Ok")
end
local msgbox_on_close = msgbox.on_close
msgbox.on_close = function(self, button_id, button)
if on_close then
on_close(self, button_id, button)
end
msgbox_on_close(self, button_id, button)
self:destroy()
end
msgbox:show()
end
---Wrapper to easily show a info message box.
---@param title string | widget.styledtext
---@param message string | widget.styledtext
---@param on_close? widget.messagebox.onclosehandler
---@param buttons? widget.messagebox.buttonstype
function MessageBox.info(title, message, on_close, buttons)
MessageBox.alert(title, message, MessageBox.ICON_INFO, nil, on_close, buttons)
end
---Wrapper to easily show a warning message box.
---@param title string | widget.styledtext
---@param message string | widget.styledtext
---@param on_close? widget.messagebox.onclosehandler
---@param buttons? widget.messagebox.buttonstype
function MessageBox.warning(title, message, on_close, buttons)
MessageBox.alert(title, message, MessageBox.ICON_WARNING, nil, on_close, buttons)
end
---Wrapper to easily show an error message box.
---@param title string | widget.styledtext
---@param message string | widget.styledtext
---@param on_close? widget.messagebox.onclosehandler
---@param buttons? widget.messagebox.buttonstype
function MessageBox.error(title, message, on_close, buttons)
MessageBox.alert(title, message, MessageBox.ICON_ERROR, nil, on_close, buttons)
end
return MessageBox
+188
View File
@@ -0,0 +1,188 @@
--
-- NoteBook Widget.
-- @copyright Jefferson Gonzalez
-- @license MIT
--
local style = require "core.style"
local Widget = require "libraries.widget"
local Button = require "libraries.widget.button"
local HSPACING = 2
local VSPACING = 2
---Represents a notebook pane
---@class widget.notebook.pane
---@field public name string
---@field public tab widget.button
---@field public container widget
local NoteBookPane = {}
---@class widget.notebook : widget
---@overload fun(parent?:widget):widget.notebook
---@field public panes widget.notebook.pane[]
---@field public active_pane widget.notebook.pane
local NoteBook = Widget:extend()
---Notebook constructor
---@param parent widget
function NoteBook:new(parent)
NoteBook.super.new(self, parent)
self.type_name = "widget.notebook"
self.panes = {}
self.active_pane = nil
end
---Called when a tab is clicked.
---@param pane widget.notebook.pane
---@diagnostic disable-next-line
function NoteBook:on_tab_click(pane) end
---Adds a new pane to the notebook and returns a container widget where
---you can add more child elements.
---@param name string
---@param label string
---@return widget container
function NoteBook:add_pane(name, label)
---@type widget.button
local tab = Button(self, label)
tab.border.width = 0
if #self.panes > 0 then
tab:set_position(self.panes[#self.panes].tab:get_right() + HSPACING, 0)
end
local container = Widget(self)
container.scrollable = true
container:set_position(0, tab:get_bottom() + VSPACING)
container:set_size(
self:get_width(),
self:get_height() - tab:get_height() - VSPACING
)
local pane = {
name = name,
tab = tab,
container = container
}
if not self.active_pane then
self.active_pane = pane
end
tab.on_click = function()
self.active_pane = pane
self:on_tab_click(pane)
end
table.insert(self.panes, pane)
return container
end
---Search the pane for the given name and return it.
---@param name string
---@return widget.notebook.pane | nil
function NoteBook:get_pane(name)
for _, pane in pairs(self.panes) do
if pane.name == name then
return pane
end
end
return nil
end
---Activates the given pane.
---@param name string
---@return boolean
function NoteBook:set_pane(name)
local pane = self:get_pane(name)
if pane then
self.active_pane = pane
return true
end
return false
end
---Change the tab label of the given pane.
---@param name string
---@param label string
function NoteBook:set_pane_label(name, label)
local pane = self:get_pane(name)
if pane then
pane.tab:set_label(label)
return true
end
return false
end
---Set or remove the icon for the given pane.
---@param name string
---@param icon? string|nil
---@param color? renderer.color|nil
---@param hover_color? renderer.color|nil
function NoteBook:set_pane_icon(name, icon, color, hover_color)
local pane = self:get_pane(name)
if pane then
pane.tab:set_icon(icon, color, hover_color)
return true
end
return false
end
---Recalculate the position of the elements on resizing or position
---changes and also make changes to properly render active pane.
function NoteBook:update()
if not NoteBook.super.update(self) then return false end
for pos, pane in pairs(self.panes) do
if pos ~= 1 then
pane.tab:set_position(
self.panes[pos-1].tab:get_right() + HSPACING, 0
)
else
pane.tab:set_position(0, 0)
end
if pane ~= self.active_pane then
if pane.container.visible then
pane.tab.background_color = style.background
pane.tab.foreground_color = style.text
pane.container:hide()
end
elseif not pane.container.visible then
pane.container:show()
end
end
if self.active_pane then
self.active_pane.tab.foreground_color = style.accent
self.active_pane.container:set_position(
0, self.active_pane.tab:get_bottom() + VSPACING
)
self.active_pane.container:set_size(
self:get_width(),
self:get_height() - self.active_pane.tab:get_height() - VSPACING
)
self.active_pane.container.border.color = style.divider
end
return true
end
---Here we draw the bottom line on the tab of active pane.
function NoteBook:draw()
if not NoteBook.super.draw(self) then return false end
if self.active_pane then
local x = self.active_pane.tab.position.x
local y = self.active_pane.tab.position.y + self.active_pane.tab:get_bottom()
local w = self.active_pane.tab:get_width()
renderer.draw_rect(x, y, w, HSPACING, style.caret)
end
return true
end
return NoteBook
+238
View File
@@ -0,0 +1,238 @@
--
-- NumberBox Widget.
-- @copyright Jefferson Gonzalez
-- @license MIT
--
local core = require "core"
local Widget = require "libraries.widget"
local Button = require "libraries.widget.button"
local TextBox = require "libraries.widget.textbox"
---@class widget.numberbox : widget
---@overload fun(parent?:widget, value:number, min?:number, max?:number, step?:number):widget.numberbox
---@field private textbox widget.textbox
---@field private decrease_button widget.button
---@field private increase_button widget.button
---@field private minimum number
---@field private maximum number
---@field private step number
local NumberBox = Widget:extend()
---Constructor
---@param parent widget
---@param value number
---@param min? number
---@param max? number
---@param step? number
function NumberBox:new(parent, value, min, max, step)
NumberBox.super.new(self, parent)
self.type_name = "widget.numberbox"
self:set_range(min, max)
self:set_step(step)
self.textbox = TextBox(self, "")
self.textbox.scrollable = true
self.decrease_button = Button(self, "-")
self.increase_button = Button(self, "+")
self:set_value(value)
local this = self
function self.textbox.textview.doc:on_text_change(type)
if not tonumber(this.textbox:get_text()) then
if not this.coroutine_run then
this.coroutine_run = true
core.add_thread(function()
this.textbox:set_text(this.current_text)
this.coroutine_run = false
end)
end
else
this.textbox.placeholder_active = false
this.current_text = this.textbox:get_text()
this:on_change(tonumber(this.current_text))
end
end
function self.textbox:on_mouse_wheel(y)
if self.active then
if y > 0 then this:increase() else this:decrease() end
return true
end
return false
end
function self.decrease_button:on_mouse_pressed(button, x, y, clicks)
if Button.super.on_mouse_pressed(self, button, x, y, clicks) then
this.mouse_is_pressed = true
this:mouse_pressed(false)
return true
end
return false
end
function self.increase_button:on_mouse_pressed(button, x, y, clicks)
if Button.super.on_mouse_pressed(self, button, x, y, clicks) then
this.mouse_is_pressed = true
this:mouse_pressed(true)
return true
end
return false
end
function self.decrease_button:on_mouse_released(button, x, y)
if Button.super.on_mouse_released(self, button, x, y) then
this.mouse_is_pressed = false
return true
end
return false
end
function self.increase_button:on_mouse_released(button, x, y)
if Button.super.on_mouse_released(self, button, x, y) then
this.mouse_is_pressed = false
return true
end
return false
end
self.border.width = 0
self:set_size(
self.textbox:get_width() - 100
+ self.decrease_button:get_width()
+ self.increase_button:get_width()
)
end
---Set a new value.
---@param value number
function NumberBox:set_value(value)
if type(value) == "number" then
self.textbox:set_text(tostring(value))
elseif type(value) == "string" and tonumber(value) then
self.textbox:set_text(value)
else
self.textbox:set_text(tostring(self.minimum))
end
self.textbox.placeholder_active = false
self.current_text = self.textbox:get_text()
self:on_change(tonumber(self.current_text))
end
---Get the current value.
---@return number
function NumberBox:get_value()
return tonumber(self.textbox:get_text()) or self.minimum
end
---Set the minimum and maximum values allowed.
---@param min? number
---@param max? number
function NumberBox:set_range(min, max)
self.minimum = min or math.mininteger
self.maximum = max or math.maxinteger
end
---Set the value used to increase or decrease the number when the
---buttons are pressed.
---@param step number
function NumberBox:set_step(step)
self.step = step or 1
end
---Decrease the current value.
function NumberBox:decrease()
self.textbox.placeholder_active = false
local value = tonumber(self.textbox:get_text()) or self.maximum
if (value - self.step) >= self.minimum then
self:set_value(value - self.step)
end
end
---Increase the current value.
function NumberBox:increase()
self.textbox.placeholder_active = false
local value = tonumber(self.textbox:get_text()) or self.minimum
if (value + self.step) <= self.maximum then
self:set_value(value + self.step)
end
end
---Triggered when the mouse is pressed on the increase/decrease buttons.
---@param increase boolean
function NumberBox:mouse_pressed(increase)
if increase then self:increase() else self:decrease() end
local elapsed = system.get_time() + 0.3
local this = self
core.add_thread(function()
while this.mouse_is_pressed do
if elapsed < system.get_time() then
if increase then
this:increase()
else
this:decrease()
end
core.redraw = true
elapsed = system.get_time() + 0.1
end
coroutine.yield()
end
end)
end
---Overrided to enforce minimum allowed size.
---@param width integer
---@param height? integer Ignored on the number box
function NumberBox:set_size(width, height)
local buttons_w = self.decrease_button:get_width()
+ self.increase_button:get_width()
-- permit a minimum of 100 pixels wide for textbox
if width < (buttons_w + 100) then
width = 100 + buttons_w
end
self.textbox:set_size(width - buttons_w)
NumberBox.super.set_size(
self,
width,
math.max(
self.textbox:get_height(),
self.decrease_button:get_height(),
self.increase_button:get_height()
)
-- TODO: check what causes the need for this border size addition since
-- it shouldn't be needed but for now fixes occasional bottom border cut.
+ self.increase_button.border.width
)
end
function NumberBox:update()
if not NumberBox.super.update(self) then return false end
self:set_size(
self.textbox:get_width()
+ self.decrease_button:get_width()
+ self.increase_button:get_width()
)
self.textbox:set_position(0, 0)
self.decrease_button:set_position(
self.textbox:get_right(),
0
)
self.increase_button:set_position(
self.decrease_button:get_right(),
0
)
return true
end
return NumberBox
+95
View File
@@ -0,0 +1,95 @@
--
-- ProgressBar Widget.
-- @copyright Jefferson Gonzalez
-- @license MIT
--
local style = require "core.style"
local Widget = require "libraries.widget"
---@class widget.progressbar : widget
---@overload fun(parent?:widget, percent?:number, width?:number):widget.progressbar
---@field public percent number
---@field public show_percent boolean
---@field private percent_width number
---@field private percent_x number
---@field private percent_y number
local ProgressBar = Widget:extend()
---Constructor
---@param parent widget
---@param percent number
---@param width number
function ProgressBar:new(parent, percent, width)
ProgressBar.super.new(self, parent)
self.type_name = "widget.progressbar"
self.clickable = false
self.percent = percent or 0
self.percent_width = 0
self.show_percent = true
self:set_size(width or 200, self:get_font():get_height() + style.padding.y)
end
---@param percent number
function ProgressBar:set_percent(percent)
self.percent = percent
end
---@return number
function ProgressBar:get_percent()
return self.percent
end
function ProgressBar:update()
if not ProgressBar.super.update(self) then return false end
local font = self:get_font()
-- update the size
self:set_label(self.percent .. "%")
self:set_size(
nil,
font:get_height() + style.padding.y
)
local percent_width = (self.size.x * (self.percent / 100))
self:move_towards(self, "percent_width", percent_width, 0.2)
if self.show_percent then
self.percent_x = (self:get_width() / 2)
- (font:get_width(self.label) / 2)
self.percent_y = style.padding.y / 2
end
return true
end
function ProgressBar:draw()
if not ProgressBar.super.draw(self) then return false end
renderer.draw_rect(
self.position.x,
self.position.y,
self.percent_width,
self.size.y,
style.dim
)
if self.show_percent then
renderer.draw_text(
self:get_font(),
self.label,
self.position.x + self.percent_x,
self.position.y + self.percent_y,
style.text
)
end
return true
end
return ProgressBar
+33
View File
@@ -0,0 +1,33 @@
--
-- Extends core.scrollbar to allow propagating force status to child elements.
--
---@type core.scrollbar
local CoreScrollBar = require "core.scrollbar"
---@class widget.scrollbar : core.scrollbar
---@overload fun(parent?:widget, options?:table):widget.scrollbar
---@field super widget.scrollbar
---@field widget_parent widget
local ScrollBar = CoreScrollBar:extend()
function ScrollBar:new(parent, options)
self.widget_parent = parent
ScrollBar.super.new(self, options)
end
function ScrollBar:set_forced_status(status)
ScrollBar.super.set_forced_status(self, status)
if self.widget_parent and self.widget_parent.childs then
for _, child in pairs(self.widget_parent.childs) do
if self.direction == "v" then
child.v_scrollbar:set_forced_status(status)
else
child.h_scrollbar:set_forced_status(status)
end
end
end
end
return ScrollBar
+607
View File
@@ -0,0 +1,607 @@
--
-- SearchReplaceList Widget.
-- @copyright Jefferson Gonzalez
-- @license MIT
--
local core = require "core"
local common = require "core.common"
local style = require "core.style"
local Widget = require "libraries.widget"
---@class widget.searchreplacelist.lineposition
---@field col1 integer
---@field col2 integer
---@field checked boolean?
---@class widget.searchreplacelist.line
---@field line integer
---@field text string
---@field positions widget.searchreplacelist.lineposition[]
---@class widget.searchreplacelist.file
---@field path string
---@field lines widget.searchreplacelist.line[]
---@field expanded boolean
---@class widget.searchreplacelist.item
---@field checked boolean
---@field file widget.searchreplacelist.file?
---@field parent widget.searchreplacelist.item?
---@field line widget.searchreplacelist.line?
---@field position widget.searchreplacelist.lineposition?
---@class widget.searchreplacelist : widget
---@field replacement string?
---@field selected integer
---@field hovered integer
---@field items widget.searchreplacelist.item[]
---@field total_files integer
---@field total_results integer
---@field base_dir string
---@overload fun(parent:widget, find:string, replacement:string?):widget.searchreplacelist
local SearchReplaceList = Widget:extend()
---Colors to use when performing a replacement.
local DIFF = {
ADD = { common.color "#72b886" },
DEL = { common.color "#F36161" },
TEXT = { common.color "#000000" }
}
---Constructor
---@param parent widget
---@param replacement string?
function SearchReplaceList:new(parent, replacement)
SearchReplaceList.super.new(self, parent)
self.type_name = "widget.searchreplacelist"
self.replacement = replacement or nil
self.selected = 0
self.hovered = 0
self.items = {}
self.max_width = 0
self.hovered_checkbox = false
self.hovered_expander = false
self.scrollable = true
self.total_files = 0
self.total_results = 0
self.base_dir = ""
end
---Overridable event triggered when an item is clicked.
---@param item widget.searchreplacelist.item
---@param clicks integer
function SearchReplaceList:on_item_click(item, clicks) end
---Add a new file with all the matching lines and positions.
---@param path string
---@param lines widget.searchreplacelist.line[]
---@param expanded boolean?
function SearchReplaceList:add_file(path, lines, expanded)
if type(expanded) == "nil" then expanded = true end
table.insert(self.items, {
checked = true,
file = {
path = path,
lines = lines,
expanded = false
}
})
self.total_files = self.total_files + 1
-- expand results and count them
if expanded and #lines > 0 then
self:expand(#self.items, true)
-- count the results only
else
for _, line in ipairs(self.items[#self.items]) do
self.total_results = self.total_results + #line.positions
end
end
end
---Removes all elements from the list and reset it.
function SearchReplaceList:clear()
self.selected = 0
self.hovered = 0
self.items = {}
self.max_width = 0
self.hovered_checkbox = false
self.hovered_expander = false
self.total_files = 0
self.total_results = 0
end
---Uncollapse a file line results.
---@param position integer
function SearchReplaceList:expand(position, count_results)
local parent = self.items[position]
if
parent and parent.file
and
not parent.file.expanded
then
local insert_pos = position+1
local items = {}
for _, line in ipairs(parent.file.lines) do
for _, line_pos in ipairs(line.positions) do
table.insert(items, {
parent = parent,
line = line,
position = line_pos
})
if count_results then
self.total_results = self.total_results + 1
end
end
end
common.splice(self.items, insert_pos, 0, items)
parent.file.expanded = true
end
end
---Collapse a file line results.
---@param position integer
function SearchReplaceList:contract(position)
local parent = self.items[position]
if
parent and parent.file
and
parent.file.expanded
then
local start_pos = position+1
local end_pos = 0
for _, line in ipairs(parent.file.lines) do
for _, _ in ipairs(line.positions) do
end_pos = end_pos + 1
end
end
common.splice(self.items, start_pos, end_pos)
parent.file.expanded = false
end
end
---Collapse/uncollapse a file line results.
---@param position integer
function SearchReplaceList:toggle_expand(position)
local parent = self.items[position]
if parent and parent.file then
if parent.file.expanded then
self:contract(position)
else
self:expand(position)
end
end
end
---Toggle the checkbox of the given item position.
---@param pos integer
function SearchReplaceList:toggle_check(pos)
local item = self.items[pos]
if not item or self.replacement == nil then return end
if item.file then
item.checked = not item.checked
for _, line in ipairs(item.file.lines) do
for _, position in ipairs(line.positions) do
position.checked = item.checked
end
end
else
if type(item.position.checked) == "nil" then
item.position.checked = false
else
item.position.checked = not item.position.checked
end
local parent_checked = true
for _, line in ipairs(item.parent.file.lines) do
for _, position in ipairs(line.positions) do
if position.checked == false then
parent_checked = false
break
end
end
end
item.parent.checked = parent_checked
end
end
---Replace a position on a string with a given replacement.
---@param str string
---@param s integer
---@param e integer
---@param rep string
local function replace_substring(str, s, e, rep)
local head = s <= 1 and "" or string.sub(str, 1, s - 1)
local tail = e >= #str and "" or string.sub(str, e + 1)
return head .. rep .. tail
end
---Applies the replacement on the given item position but not on the real file.
---
---The purpose of this function is to reflect the changes on the listed items.
---@param position integer
function SearchReplaceList:apply_replacement(position)
local item = self.items[position]
if item and item.file and self.replacement then
local replacement = self.replacement
local replacement_len = #self.replacement
for _, line in ipairs(item.file.lines) do
local offset = 0
for _, pos in ipairs(line.positions) do
local col1 = pos.col1 + offset
local col2 = pos.col2 + offset
if pos.checked or type(pos.checked) == "nil" then
line.text = replace_substring(line.text, col1, col2, replacement)
local current_len = col2 - col1 + 1
local len_diff = 0
if current_len > replacement_len then
len_diff = current_len - replacement_len
offset = offset - len_diff
col2 = col2 - len_diff
elseif current_len < replacement_len then
len_diff = replacement_len - current_len
offset = offset + len_diff
col2 = col2 + len_diff
end
end
pos.col1, pos.col2 = col1, col2
end
end
end
end
---Select the item that follows currently selected item.
---@return widget.searchreplacelist.item?
function SearchReplaceList:select_next()
local items_count = #self.items
if items_count <= 0 then return nil end
local selected = self.selected+1
if selected > items_count then selected = 1 end
self.selected = common.clamp(selected, 1, items_count)
self:scroll_to_selected()
return self.items[self.selected]
end
---Select the item that precedes currently selected item.
---@return widget.searchreplacelist.item?
function SearchReplaceList:select_prev()
local items_count = #self.items
if items_count <= 0 then return nil end
local selected = self.selected-1
if selected < 1 then selected = items_count end
self.selected = common.clamp(selected, 1, items_count)
self:scroll_to_selected()
return self.items[self.selected]
end
---Get the currently selected item.
---@return widget.searchreplacelist.item?
function SearchReplaceList:get_selected()
if self.selected > 0 and self.selected <= #self.items then
return self.items[self.selected]
end
return nil
end
---Get the line height used when drawing each item row.
---@return number height
function SearchReplaceList:get_line_height()
return style.padding.y + style.font:get_height()
end
---Used when calculating if vertical scrolling is needed.
---@return number size
function SearchReplaceList:get_scrollable_size()
return #self.items * self:get_line_height() + style.padding.y
end
---Used when calculating if horizontal scrolling is needed.
---@return number size
function SearchReplaceList:get_h_scrollable_size()
local width = style.padding.x / 2
+ style.icon_font:get_width("-")
+ style.padding.x / 2
+ self.max_width
if self.replacement then
local cb_w = self:get_checkbox_size()
width = width
+ cb_w + style.padding.x / 2
+ style.font:get_width(self.replacement)
end
return width
end
---Get the checkbox size based on the line height.
---@param y? number
---@return number w
---@return number h
---@return number y Vertically center align coord based on given y param
function SearchReplaceList:get_checkbox_size(y)
if not y then y = 0 end
local lh = self:get_line_height()
local w = lh * 0.6
local h = w
y = y + ((lh / 2) - (h / 2))
return w, h, y
end
---Get the position of first and last visible items.
---@return integer first
---@return integer last
function SearchReplaceList:get_visible_items_range()
local lh = self:get_line_height()
local min = math.max(1, math.floor(self.scroll.y / lh))
return min, min + math.floor(self.size.y / lh) + 1
end
---Allows iterating the currently visible items only.
---@return fun():integer,widget.searchreplacelist.item,number,number,number,number
function SearchReplaceList:each_visible_item()
return coroutine.wrap(function()
local lh = self:get_line_height()
local x, y = self:get_content_offset()
local min, max = self:get_visible_items_range()
y = y + lh * (min - 1)
for i = min, max do
local item = self.items[i]
if not item then break end
coroutine.yield(i, item, x, y, self.size.x, lh)
y = y + lh
end
end)
end
---Iterates over all files, only those that have a position checked on replacement mode.
---@return fun():integer,widget.searchreplacelist.file
function SearchReplaceList:each_file()
return coroutine.wrap(function()
local replacement = self.replacement
for i, item in ipairs(self.items) do
if item.file then
if replacement then
local none_checked = true
for _, line in ipairs(item.file.lines) do
for _, pos in ipairs(line.positions) do
if type(pos.checked) == "nil" or pos.checked then
none_checked = false
break
end
end
end
if none_checked then
goto continue
end
end
coroutine.yield(i, item.file)
end
::continue::
end
end)
end
---Scroll to currently selected item only if not already visible.
function SearchReplaceList:scroll_to_selected()
if self.selected == 0 then return end
local h = self:get_line_height()
local y = h * (self.selected - 1)
self.scroll.to.y = math.min(self.scroll.to.y, y)
self.scroll.to.y = math.max(self.scroll.to.y, y + h - self.size.y)
end
function SearchReplaceList:on_mouse_moved(mx, my, ...)
if not SearchReplaceList.super.on_mouse_moved(self, mx, my, ...) then
return false
end
self.hovered = 0
for i, item, x,y,w,h in self:each_visible_item() do
w = self.size.x
if mx >= x and my >= y and mx < x + w and my < y + h then
self.hovered = i
x = x + style.padding.x / 2
w = style.icon_font:get_width('-')
if item.file and mx >= x and my >= y and mx < x + w and my < y + h then
self.hovered_expander = true
self.hovered_checkbox = false
else
self.hovered_expander = false
end
if not self.hovered_expander and self.replacement then
x = x + w + style.padding.x / 2
w, h, y = self:get_checkbox_size(y)
if mx >= x and my >= y and mx < x + w and my < y + h then
self.hovered_checkbox = true
self.hovered_expander = false
else
self.hovered_checkbox = false
end
end
break
end
end
return true
end
function SearchReplaceList:on_mouse_pressed(button, x, y, clicks)
if
not SearchReplaceList.super.on_mouse_pressed(self, button, x, y, clicks)
then
return false
end
if self:scrollbar_hovering() then return true end
local item = self.items[self.hovered]
if not item then return true end
self.selected = self.hovered
if self.hovered_checkbox then
self:toggle_check(self.selected)
elseif item.file and (clicks > 1 or self.hovered_expander) then
if not item.file.expanded then
self:expand(self.hovered)
else
self:contract(self.hovered)
end
else
self:on_item_click(item, clicks)
end
return true
end
function SearchReplaceList:draw_checkbox(checked, hovered, x, y, lh)
local w, h, cy = self:get_checkbox_size(y)
renderer.draw_rect(x, cy, w, h, style.text)
renderer.draw_rect(
x + 2, cy + 2, w-4, h-4,
hovered and style.dim or style.background
)
if checked then
renderer.draw_rect(x + 5, cy + 5, w-10, h-10, style.caret)
end
return x + w
end
function SearchReplaceList:draw()
if not SearchReplaceList.super.draw(self) then return false end
core.push_clip_rect(
self.position.x,
self.position.y,
self.size.x,
self.size.y
)
local font = self:get_font()
local replacement = self.replacement
local replacement_width = font:get_width(replacement or "")
local file_path
self.max_width = 0
for i, item, x,y,w,h in self:each_visible_item() do
if item.file then
file_path = common.relative_path(self.base_dir, item.file.path)
end
-- add left padding
x = x + style.padding.x / 2
local text_color = style.text
if i == self.selected then
renderer.draw_rect(self.position.x, y, self.size.x, h, style.selection)
elseif i == self.hovered then
renderer.draw_rect(self.position.x, y, self.size.x, h, style.line_highlight)
text_color = style.accent
end
-- draw collapse/contract symbol
if item.file then
common.draw_text(
style.icon_font,
(self.hovered == i and self.hovered_expander) and style.accent or style.text,
item.file.expanded and "-" or "+",
"left",
x, y, w, h
)
x = x + style.icon_font:get_width("-")
else
x = x + style.icon_font:get_width("-")
end
x = x + style.padding.x / 2
-- draw checkbox
if replacement then
local checked = false
if item.file then
checked = item.checked
else
if type(item.position.checked) == "nil" then
checked = true
else
checked = item.position.checked
end
end
x = style.padding.x / 2 + self:draw_checkbox(
checked,
i == self.hovered and self.hovered_checkbox or false,
x, y, h
)
end
-- draw text
local text = item.file and file_path or item.line.text
local all_text = ""
if item.line then
local start_pos, end_pos = 1, #text
local prefix, postfix = "", ""
-- truncate long lines to keep good rendering performance
if #text > 120 then
start_pos = math.max(item.position.col1 - 50, 1)
end_pos = math.min(item.position.col2 + 50, end_pos)
if start_pos ~= 1 then prefix = "..." end
if end_pos ~= #text then postfix = "..." end
end
x = common.draw_text(
font,
style.syntax["number"],
tostring(item.line.line) .. ": ",
"left",
x, y, w, h
)
local start_text = item.position.col1 ~= 1 and
prefix .. text:sub(start_pos, item.position.col1-1)
or
""
local end_text = item.position.col2 ~= #text and
text:sub(item.position.col2+1, end_pos) .. postfix
or
""
local found_text = text:sub(item.position.col1, item.position.col2)
local found_width = style.font:get_width(found_text)
if start_text ~= "" then
x = common.draw_text(
font,
text_color,
start_text,
"left",
x, y, w, h
)
end
local found_color = not replacement and style.dim or DIFF.DEL
local found_text_color = not replacement and text_color or DIFF.TEXT
renderer.draw_rect(x, y, found_width, h, found_color)
x = common.draw_text(font, found_text_color, found_text, "left", x, y, w, h)
if replacement then
renderer.draw_rect(x, y, replacement_width, h, DIFF.ADD)
x = common.draw_text(font, DIFF.TEXT, replacement, "left", x, y, w, h)
end
if end_text ~= "" then
x = common.draw_text(
font,
text_color,
end_text,
"left",
x, y, w, h
)
end
all_text = item.line.line .. ": " .. start_text .. found_text .. end_text
else
x = common.draw_text(font, text_color, text, "left", x, y, w, h)
all_text = file_path
end
-- recalc max_width for horizontal scrollbar
self.max_width = math.max(self.max_width, style.font:get_width(all_text))
end
core.pop_clip_rect()
self:draw_scrollbar()
return true
end
return SearchReplaceList
+288
View File
@@ -0,0 +1,288 @@
--
-- SelectBox Widget.
-- @copyright Jefferson Gonzalez
-- @license MIT
--
local core = require "core"
local common = require "core.common"
local style = require "core.style"
local Widget = require "libraries.widget"
local ListBox = require "libraries.widget.listbox"
---@class widget.selectbox : widget
---@overload fun(parent?:widget, label?:string):widget.selectbox
---@field private list_container widget
---@field private list widget.listbox
---@field private selected integer
---@field private hover_text renderer.color
local SelectBox = Widget:extend()
---Constructor
---@param parent widget
---@param label string
function SelectBox:new(parent, label)
SelectBox.super.new(self, parent)
self.type_name = "widget.selectbox"
self.size.x = 200 + (style.padding.x * 2)
self.size.y = self:get_font():get_height() + (style.padding.y * 2)
self.list_container = Widget()
self.list_container.name = self:get_name()
self.list_container:set_size(
self.size.x - self.list_container.border.width,
150
)
self.list = ListBox(self.list_container)
self.list.border.width = 0
self.list:enable_expand(true)
self.selected = 0
local list_on_row_click = self.list.on_row_click
self.list.on_row_click = function(this, idx, data)
list_on_row_click(this, idx, data)
if idx ~= 1 then
self.selected = idx-1
self:on_selected(idx-1, data)
self:on_change(self.selected)
end
self.list_container:hide_animated(true)
end
-- Hide list if mouse clicked outside
self.list_container:force_event("mouse_released")
self.list_container.on_mouse_released = function(this, button, x, y)
if
this:is_visible()
and
not this:mouse_on_top(x, y) and not self:mouse_on_top(x, y)
then
this:hide()
return false
end
if this:is_visible() and this:mouse_on_top(x, y) then
return Widget.on_mouse_released(this, button, x, y)
end
end
self:set_label(label or "select")
end
---Set the text displayed when no item is selected.
---@param text string
function SelectBox:set_label(text)
SelectBox.super.set_label(self, "- "..text.." -")
if not self.list.rows[1] then
self.list:add_row({"- "..text.." -"})
else
self.list.rows[1][1] = "- "..text.." -"
end
end
---Add selectable option to the selectbox.
---@param text widget.styledtext|string
---@param data any
function SelectBox:add_option(text, data)
if type(text) == "string" then
self.list:add_row({ text }, data)
else
self.list:add_row(text, data)
end
end
---Check if a text is longer than the given maximum width and if larger returns
---a chopped version with the overflow_chars appended to it.
---@param text string
---@param max_width number
---@param font widget.font Default is style.font
---@param overflow_chars? string Default is '...'
---@return string chopped_text
---@return boolean overflows True if the text overflows
function SelectBox:text_overflow(text, max_width, font, overflow_chars)
font = self:get_font(font)
overflow_chars = overflow_chars or "..."
local overflow = false
local overflow_chars_width = font:get_width(overflow_chars)
if font:get_width(text) > max_width then
overflow = true
for i = 1, #text do
local reduced_text = text:sub(1, #text - i)
if
font:get_width(reduced_text) + overflow_chars_width
<=
max_width
then
text = reduced_text .. ""
break
end
end
end
return text, overflow
end
---Set the active option index.
---@param idx integer
function SelectBox:set_selected(idx)
if self.list.rows[idx+1] then
self.selected = idx
self.list:set_selected(idx+1)
else
self.selected = 0
self.list:set_selected()
end
self:on_change(self.selected)
end
---Get the currently selected option index.
---@return integer
function SelectBox:get_selected()
return self.selected
end
---Get the currently selected option text.
---@return string|nil
function SelectBox:get_selected_text()
if self.selected > 0 then
return self.list:get_row_text(self.selected + 1)
end
return nil
end
---Get the currently selected option associated data.
---@return any|nil
function SelectBox:get_selected_data()
if self.selected > 0 then
return self.list:get_row_data(self.selected + 1)
end
return nil
end
---Repositions the listbox container according to the selectbox position
---and available screensize.
function SelectBox:reposition_container()
local y1 = self.position.y + self:get_height()
local y2 = self.position.y - self.list:get_height()
local _, h = system.get_window_size(core.window)
if y1 + self.list:get_height() <= h then
self.list_container:set_position(
self.position.x,
y1
)
else
self.list_container:set_position(
self.position.x,
y2
)
end
self.list_container.size.x = self.size.x - (self.border.width * 2)
end
---Overrided to destroy the floating listbox container.
function SelectBox:destroy_childs()
SelectBox.super.destroy_childs(self)
self.list_container:destroy()
end
--
-- Events
--
---Overwrite to listen to on_selected events.
---@param item_idx integer
---@param item_data widget.listbox.row
---@diagnostic disable-next-line
function SelectBox:on_selected(item_idx, item_data) end
function SelectBox:on_mouse_enter(...)
SelectBox.super.on_mouse_enter(self, ...)
self.hover_text = style.accent
end
function SelectBox:on_mouse_leave(...)
SelectBox.super.on_mouse_leave(self, ...)
self.hover_text = nil
end
function SelectBox:on_click(button, x, y)
SelectBox.super.on_click(self, button, x, y)
if button == "left" then
self:reposition_container()
self.list_container.border.color = style.caret
self.list_container:toggle_visible(true, true)
self.list:resize_to_parent()
end
end
function SelectBox:update()
if not SelectBox.super.update(self) then return false end
local font = self:get_font()
self.size.y = font:get_height() + style.padding.y * 2
if
self.list_container.visible
and
self.list_container.position.y ~= self.position.y + self:get_height()
then
self:reposition_container()
end
return true
end
function SelectBox:draw()
if not SelectBox.super.draw(self) then return false end
local font = self:get_font()
local icon_width = style.icon_font:get_width("+")
local max_width = self.size.x
- icon_width
- (style.padding.x * 2) -- left/right paddings
- (style.padding.x / 2) -- space between icon and text
local item_text = self.selected == 0 and
self.label or self.list:get_row_text(self.selected+1)
local text = self:text_overflow(item_text, max_width, font)
-- draw label or selected item
common.draw_text(
font,
self.hover_text or self.foreground_color or style.text,
text,
"left",
self.position.x + style.padding.x,
self.position.y,
self.size.x - style.padding.x,
self.size.y
)
-- draw arrow down icon
common.draw_text(
style.icon_font,
self.hover_text or self.foreground_color or style.text,
"-",
"right",
self.position.x,
self.position.y,
self.size.x - style.padding.x,
self.size.y
)
return true
end
return SelectBox
+308
View File
@@ -0,0 +1,308 @@
--
-- TextBox widget re-using code from lite's DocView.
--
local core = require "core"
local style = require "core.style"
local translate = require "core.doc.translate"
local Doc = require "core.doc"
local DocView = require "core.docview"
local View = require "core.view"
local Widget = require "libraries.widget"
---@class widget.textbox.SingleLineDoc : core.doc
---@overload fun():widget.textbox.SingleLineDoc
---@field super core.doc
local SingleLineDoc = Doc:extend()
function SingleLineDoc:insert(line, col, text)
SingleLineDoc.super.insert(self, line, col, text:gsub("\n", ""))
end
---@class widget.textbox.TextView : core.docview
---@overload fun():widget.textbox.TextView
---@field super core.docview
local TextView = DocView:extend()
function TextView:new()
TextView.super.new(self, SingleLineDoc())
self.gutter_width = 0
self.hide_lines_gutter = true
self.gutter_text_brightness = 0
self.scrollable = true
self.font = "font"
self.name = View.get_name(self)
self.size.y = 0
self.label = ""
end
function TextView:get_name()
return self.name
end
function TextView:get_scrollable_size()
return 0
end
function TextView:get_text()
return self.doc:get_text(1, 1, 1, math.huge)
end
function TextView:set_text(text, select)
self.doc:remove(1, 1, math.huge, math.huge)
self.doc:text_input(text)
if select then
self.doc:set_selection(math.huge, math.huge, 1, 1)
end
end
function TextView:get_gutter_width()
return self.gutter_width or 0
end
function TextView:get_line_height()
return math.floor(self:get_font():get_height() * 1.2)
end
function TextView:draw_line_gutter(idx, x, y)
if self.hide_lines_gutter then
return
end
TextView.super.draw_line_gutter(self, idx, x, y)
end
function TextView:draw_line_highlight()
-- no-op function to disable this functionality
end
-- Overwrite this function just to disable the core.push_clip_rect
function TextView:draw()
self:draw_background(style.background)
local _, indent_size = self.doc:get_indent_info()
self:get_font():set_tab_size(indent_size)
local minline, maxline = self:get_visible_line_range()
local lh = self:get_line_height()
local x, y = self:get_line_screen_position(minline)
for i = minline, maxline do
self:draw_line_gutter(i, self.position.x, y)
y = y + lh
end
x, y = self:get_line_screen_position(minline)
for i = minline, maxline do
self:draw_line_body(i, x, y)
y = y + lh
end
self:draw_overlay()
self:draw_scrollbar()
end
---@class widget.textbox : widget
---@overload fun(parent?:widget, text?:string, placeholder?:string):widget.textbox
---@field textview widget.textbox.TextView
---@field placeholder string
---@field placeholder_active boolean
local TextBox = Widget:extend()
function TextBox:new(parent, text, placeholder)
TextBox.super.new(self, parent)
self.type_name = "widget.textbox"
self.textview = TextView()
self.textview.name = parent.name
self.size.x = 200 + (style.padding.x * 2)
self.textview.size.x = self.size.x
self.size.y = self:get_font():get_height() + (style.padding.y * 2)
self.placeholder = placeholder or ""
self.placeholder_active = false
-- this widget is for text input
self.input_text = true
self.cursor = "ibeam"
self.active = false
self.drag_select = false
if text ~= "" then
self.textview:set_text(text, select)
else
self.placeholder_active = true
self.textview:set_text(self.placeholder)
end
local this = self
function self.textview.doc:on_text_change()
if not this.placeholder_active then
this:on_change(this:get_text())
end
end
-- more granular listening of text changing events
local doc_raw_insert = self.textview.doc.raw_insert
function self.textview.doc:raw_insert(...)
doc_raw_insert(self, ...)
this:on_text_change("insert", ...)
end
local doc_raw_remove = self.textview.doc.raw_remove
function self.textview.doc:raw_remove(...)
doc_raw_remove(self, ...)
this:on_text_change("remove", ...)
end
end
---@param width integer
function TextBox:set_size(width)
TextBox.super.set_size(
self,
width,
self:get_font():get_height() + (style.padding.y * 2)
)
self.textview.size.x = self.size.x
end
--- Get the text displayed on the textbox.
---@return string
function TextBox:get_text()
if self.placeholder_active then
return ""
end
return self.textview:get_text()
end
--- Set the text displayed on the textbox.
---@param text string
---@param select? boolean
function TextBox:set_text(text, select)
self.textview:set_text(text, select)
end
--
-- Events
--
function TextBox:on_mouse_pressed(button, x, y, clicks)
if TextBox.super.on_mouse_pressed(self, button, x, y, clicks) then
self.textview:on_mouse_pressed(button, x, y, clicks)
local line, col = self.textview:resolve_screen_position(x, y)
self.drag_select = { line = line, col = col }
self.textview.doc:set_selection(line, col, line, col)
if clicks == 2 then
local line1, col1 = translate.start_of_word(self.textview.doc, line, col)
local line2, col2 = translate.end_of_word(self.textview.doc, line1, col1)
self.textview.doc:set_selection(line2, col2, line1, col1)
elseif clicks == 3 then
self.textview.doc:set_selection(1, 1, 1, math.huge)
end
if core.active_view ~= self.textview then
self.textview:on_mouse_released(button, x, y)
end
return true
end
return false
end
function TextBox:on_mouse_released(button, x, y)
if TextBox.super.on_mouse_released(self, button, x, y) then
self.drag_select = false
self.textview:on_mouse_released(button, x, y)
return true
end
return false
end
function TextBox:on_mouse_moved(x, y, dx, dy)
if self.drag_select then
local line, col = self.textview:resolve_screen_position(x, y)
self.textview.doc:set_selection(
self.drag_select.line, self.drag_select.col, line, col
)
end
if TextBox.super.on_mouse_moved(self, x, y, dx, dy) then
if self.active or core.active_view == self.textview then
self.textview:on_mouse_moved(x, y, dx, dy)
end
return true
end
return false
end
function TextBox:activate()
self.hover_border = style.caret
if self.placeholder_active then
self.placeholder_active = false
self:set_text("")
end
self.active = true
core.request_cursor("ibeam")
end
function TextBox:deactivate()
self.hover_border = nil
self.drag_select = false
if self:get_text() == "" then
self.placeholder_active = true
self:set_text(self.placeholder)
end
self.active = false
core.request_cursor("arrow")
end
function TextBox:on_text_input(text)
TextBox.super.on_text_input(self, text)
self.textview:on_text_input(text)
end
---Event fired on any text change event.
---@param action string Can be "insert" or "remove",
---insert arguments (see Doc:raw_insert):
--- line, col, text, undo_stack, time
---remove arguments (see Doc:raw_remove):
--- line1, col1, line2, col2, undo_stack, time
---@diagnostic disable-next-line
function TextBox:on_text_change(action, ...) end
function TextBox:update()
if not TextBox.super.update(self) then return false end
if
self.drag_select
or
(self.active and self:mouse_on_top(self.mouse.x, self.mouse.y))
then
core.request_cursor("ibeam")
end
self.textview:update()
self.size.y = self:get_font():get_height() + (style.padding.y * 2)
return true
end
function TextBox:draw()
if not self:is_visible() then return false end
self.border.color = self.hover_border or style.text
TextBox.super.draw(self)
self.textview.position.x = self.position.x + (style.padding.x / 2)
self.textview.position.y = self.position.y - (style.padding.y/2.5)
self.textview.size.x = self.size.x
self.textview.size.y = self.size.y - (style.padding.y * 2)
core.push_clip_rect(
self.position.x,
self.position.y,
self.size.x,
self.size.y
)
self.textview:draw()
core.pop_clip_rect()
return true
end
return TextBox
+140
View File
@@ -0,0 +1,140 @@
--
-- Toggle Widget.
-- @copyright Jefferson Gonzalez
-- @license MIT
--
local style = require "core.style"
local Widget = require "libraries.widget"
local Label = require "libraries.widget.label"
-- Hold dimensions of rendered toggle
local BOX = 40
local TOGGLE = 15
local BORDER = 3
---@class widget.toggle : widget
---@overload fun(parent?:widget, label?:string, enable?:boolean):widget.toggle
---@field public enabled boolean
---@field private caption_label widget.textbox
---@field private padding integer
---@field private switch_x number
---@field private toggle_bg renderer.color
local Toggle = Widget:extend()
---Constructor
---@param parent widget
---@param label string
---@param enable boolean
function Toggle:new(parent, label, enable)
Toggle.super.new(self, parent)
self.type_name = "widget.toggle"
self.enabled = enable or false
self.label = label or ""
self.caption_label = Label(self, self.label)
self.caption_label:set_position(0, 0)
self.padding = 2
self.border.width = 0
self:set_size(
self.caption_label:get_width() + (style.padding.x / 2) + (BOX * SCALE),
self.caption_label:get_height() + ((self.padding * 2) * SCALE)
)
self.animate_switch = false
self.toggle_x = 0
end
---@param enabled boolean
function Toggle:set_toggle(enabled)
self.enabled = enabled
self.animate_switch = true
self:on_change(self.enabled)
end
---@return boolean
function Toggle:is_toggled()
return self.enabled
end
function Toggle:toggle()
self.enabled = not self.enabled
self.animate_switch = true
self:on_change(self.enabled)
end
---@param text string|widget.styledtext
function Toggle:set_label(text)
Toggle.super.set_label(self, text)
self.caption_label:set_label(text)
end
function Toggle:on_click()
self:toggle()
end
function Toggle:update()
if not Toggle.super.update(self) then return false end
local px = style.padding.x / 2
self:set_size(
self.caption_label:get_width() + px + (BOX * SCALE),
self.caption_label:get_height() + ((self.padding * 2) * SCALE)
)
self.toggle_x = self.caption_label:get_right() + px
local switch_x = self.enabled and
self.position.x + self.toggle_x
+ ((BOX - TOGGLE - BORDER) * SCALE)
or
self.position.x + self.toggle_x + (BORDER * SCALE)
if not self.animate_switch then
self.switch_x = switch_x
self.toggle_bg = {}
local color = self.enabled and style.caret or style.line_number
for i=1, 4, 1 do self.toggle_bg[i] = color[i] end
else
local color = self.enabled and style.caret or style.line_number
self:move_towards(self, "switch_x", switch_x, 0.2)
for i=1, 4, 1 do
self:move_towards(self.toggle_bg, i, color[i], 0.2)
end
if self.switch_x == switch_x then
self.animate_switch = false
end
end
return true
end
function Toggle:draw()
if not Toggle.super.draw(self) then return false end
renderer.draw_rect(
self.position.x + self.toggle_x,
self.position.y,
BOX * SCALE,
self.size.y,
self.toggle_bg
)
renderer.draw_rect(
self.switch_x,
self.position.y + (BORDER * SCALE),
TOGGLE * SCALE,
self.size.y - ((BORDER * 2) * SCALE),
style.line_highlight
)
return true
end
return Toggle
+609
View File
@@ -0,0 +1,609 @@
--
-- TreeList Widget heavily based on TreeView plugin.
-- @copyright Jefferson Gonzalez
-- @license MIT
--
local core = require "core"
local common = require "core.common"
local style = require "core.style"
local Widget = require "libraries.widget"
---@class widget.treelist.item
---@field name string
---@field label string
---@field data any?
---@field expanded boolean?
---@field visible boolean?
---@field tooltip string?
---@field depth integer?
---@field childs widget.treelist.item[]?
---@field parent widget.treelist.item[]?
---@field icon string?
---@class widget.treelist : widget
---@field items widget.treelist.item[]
---@field selected_item widget.treelist.item?
---@field hovered_item widget.treelist.item?
---@field icon_font renderer.font?
---@field private count_lines integer
---@field private scroll_width integer
---@overload fun(parent:widget?):widget.treelist
local TreeList = Widget:extend()
---Constructor
---@param parent? widget
function TreeList:new(parent)
TreeList.super.new(self, parent)
self.type_name = "widget.treelist"
self.scrollable = true
self.init_size = true
self.count_lines = 0
self.scroll_width = 0
self.items = {}
self.tooltip = { x = 0, y = 0, begin = 0, alpha = 0 }
self.last_scroll_y = 0
self.item_icon_width = 0
self.item_text_spacing = 0
end
---Get the height of a single item.
---@return number h
function TreeList:get_item_height()
return style.font:get_height() + style.padding.y
end
---Add new item to to tree list
---@param item widget.treelist.item
function TreeList:add_item(item)
table.insert(self.items, item)
end
---Remove all items from the tree
function TreeList:clear()
self.items = {}
self.selected_item = nil
self.hovered_item = nil
end
---Retrieve the amount of visible items and also yield them.
---@param item widget.treelist.item
---@param x number
---@param y number
---@param w number
---@param h number
---@param depth? number
---@return integer items_count
function TreeList:get_items(item, x, y, w, h, depth)
if not depth then depth = 0 else depth = depth + 1 end
item.depth = depth
coroutine.yield(item, x, y, w, h)
local count_lines = 1
if item and item.childs and item.expanded then
for _, child in ipairs(item.childs) do
if child.visible ~= false then
count_lines = count_lines + self:get_items(
child, x, y + count_lines * h, w, h, depth
)
end
end
end
return count_lines
end
---Allows iterating the currently visible items only.
---@return fun():widget.treelist.item,number,number,number,number
function TreeList:each_item()
return coroutine.wrap(function()
local count_lines = 0
local ox, oy = self:get_content_offset()
local h = self:get_item_height()
if #self.items > 0 then
for i=1, #self.items do
count_lines = count_lines + self:get_items(
self.items[i],
ox, oy + style.padding.y + h * count_lines,
self.size.x, h
)
end
end
self.count_lines = count_lines
end)
end
---Retrieve an item by name using the query format:
---"parent_name>child_name_2>child_name_2>etc..."
---@param query string
---@param items? widget.treelist.item[]
---@param separator? string Use a different separator (default: >)
---@return widget.treelist.item?
function TreeList:query_item(query, items, separator)
local parent = items or self.items
local item = nil
separator = separator or ">"
for name in query:gmatch("([^"..separator.."]+)") do
if parent then
local found = false
for _, child in ipairs(parent) do
if name == child.name then
item = child
parent = child.childs
found = true
break
end
end
if not found then return nil end
else
return nil
end
end
return item
end
---Set the active item.
---@param selection widget.treelist.item
---@param selection_y? number
---@param center? boolean
---@param instant? boolean
function TreeList:set_selection(selection, selection_y, center, instant)
self.selected_item = selection
if selection and selection_y
and (selection_y <= 0 or selection_y >= self.size.y) then
local lh = self:get_item_height()
if not center and selection_y >= self.size.y - lh then
selection_y = selection_y - self.size.y + lh
end
if center then
selection_y = selection_y - (self.size.y - lh) / 2
end
local _, y = self:get_content_offset()
self.scroll.to.y = selection_y - y
self.scroll.to.y = common.clamp(
self.scroll.to.y, 0, self:get_scrollable_size() - self.size.y
)
if instant then
self.scroll.y = self.scroll.to.y
end
end
end
---Sets the selection to the file with the specified path.
---TODO: Not tested, idea is to allow query like selections using item names
---by introducing a get_item/set_item methods that accepts a string query,
---For the moment we leave this inherited TreeView function here.
---@param path string #Absolute path of item to select
---@param expand boolean #Expand dirs leading to the item
---@param scroll_to boolean #Scroll to make the item visible
---@param instant boolean #Don't animate the scroll
---@return table? #The selected item
function TreeList:set_selection_from_path(path, expand, scroll_to, instant)
local separator = "||"
local to_select, to_select_y
local let_it_finish, done
::restart::
for item, _,y,_,_ in self:each_item() do
if not done then
if item.childs and #item.childs > 0 then
local _, to = string.find(path, item.name..separator, 1, true)
if to and to == #item.name + #separator then
to_select, to_select_y = item, y
if expand and not item.expanded then
self:toggle_expand(true, item)
-- Because we altered the size of the TreeList
-- and because TreeList:get_scrollable_size uses self.count_lines
-- which gets updated only when TreeList:each_item finishes,
-- we can't stop here or we risk that the scroll
-- gets clamped by View:clamp_scroll_position.
let_it_finish = true
-- We need to restart the process because if TreeList:toggle_expand
-- altered the cache, TreeList:each_item risks looping indefinitely.
goto restart
end
end
else
if item.name == path then
to_select, to_select_y = item, y
done = true
if not let_it_finish then break end
end
end
end
end
if to_select then
self:set_selection(to_select, scroll_to and to_select_y, true, instant)
end
return to_select
end
---Set the icon font used to render the items icon.
---@param font renderer.font
function TreeList:set_icon_font(font)
if font:get_size() ~= style.icon_font:get_size() then
font:set_size(style.icon_font:get_size())
end
self.icon_font = font
end
---Keep the icon font size updated to match current scale.
function TreeList:on_scale_change()
if self.icon_font then
self.icon_font:set_size(style.icon_font:get_size())
end
end
function TreeList:on_mouse_moved(px, py, ...)
if TreeList.super.on_mouse_moved(self, px, py, ...) then
self.hovered_item = nil
else
return false
end
local position = self:get_position()
local item_changed, tooltip_changed
for item, x,y,w,h in self:each_item() do
if px > x and py > y and px <= (self.size.x + position.x) and py <= y + h then
item_changed = true
self.hovered_item = item
x = math.max(x, self.position.x)
if px > x and py > y and px <= x + w and py <= y + h then
tooltip_changed = true
self.tooltip.x, self.tooltip.y = px, py
self.tooltip.begin = system.get_time()
end
break
end
end
if not item_changed then self.hovered_item = nil end
if not tooltip_changed then self.tooltip.x, self.tooltip.y = nil, nil end
return true
end
---Override to listen for item click events.
---@param item widget.treelist.item
---@param button string
---@param clicks integer
function TreeList:on_item_click(item, button, x, y, clicks) end
function TreeList:on_mouse_pressed(button, x, y, clicks)
if TreeList.super.on_mouse_pressed(self, button, x, y, clicks) then
if self:scrollbar_hovering() then return true end
self:set_selection(self.hovered_item)
if self.hovered_item then
local emit_click = false
if clicks > 1 then
self:toggle_expand()
else
if self.hovered_item.childs then
local x1, x2 = self:get_chevron_position(self.hovered_item)
if x >= x1 and x <= x2 then
self:toggle_expand()
else
emit_click = true
end
else
emit_click = true
end
end
if emit_click then
self:on_item_click(self.hovered_item, button, x, y, clicks)
end
end
return true
end
return false
end
function TreeList:on_mouse_left()
TreeList.super.on_mouse_left(self)
self.hovered_item = nil
end
function TreeList:update()
if not self:is_visible() then return end
local duration = system.get_time() - self.tooltip.begin
local tooltip_delay = 0.5
if self.hovered_item and self.tooltip.x and duration > tooltip_delay then
self:move_towards(self.tooltip, "alpha", 255, 1, "treeview")
else
self.tooltip.alpha = 0
end
self.item_icon_width = style.icon_font:get_width("D")
self.item_text_spacing = style.icon_font:get_width("f") / 2
-- this will make sure hovered_item is updated
local dy = math.abs(self.last_scroll_y - self.scroll.y)
if dy > 0 then
self:on_mouse_moved(core.root_view.mouse.x, core.root_view.mouse.y, 0, 0)
self.last_scroll_y = self.scroll.y
end
TreeList.super.update(self)
end
function TreeList:get_scrollable_size()
return self.count_lines and self:get_item_height() * (self.count_lines + 1) or math.huge
end
function TreeList:get_h_scrollable_size()
local _, _, v_scroll_w = self.v_scrollbar:get_thumb_rect()
return self.scroll_width + (
self.size.x > self.scroll_width + v_scroll_w and 0 or style.padding.x
)
end
local function replace_alpha(color, alpha)
local r, g, b = table.unpack(color)
return { r, g, b, alpha }
end
function TreeList:draw_tooltip()
if not self.hovered_item or not self.hovered_item.tooltip then
return
end
local text = common.home_encode(self.hovered_item.tooltip)
local w, h = style.font:get_width(text), style.font:get_height()
local tooltip_offset = style.font:get_height()
local x, y = self.tooltip.x + tooltip_offset, self.tooltip.y + tooltip_offset
w, h = w + style.padding.x, h + style.padding.y
if x + w > core.root_view.root_node.size.x then -- check if we can span right
x = x - w -- span left instead
end
local tooltip_border = 1
local bx, by = x - tooltip_border, y - tooltip_border
local bw, bh = w + 2 * tooltip_border, h + 2 * tooltip_border
renderer.draw_rect(
bx, by, bw, bh, replace_alpha(style.text, self.tooltip.alpha)
)
renderer.draw_rect(
x, y, w, h, replace_alpha(style.background2, self.tooltip.alpha)
)
common.draw_text(
style.font,
replace_alpha(style.text, self.tooltip.alpha),
text, "center", x, y, w, h
)
end
---@param item widget.treelist.item
---@param active boolean
---@param hovered boolean
function TreeList:get_item_icon(item, active, hovered)
local character = item.icon
local font = self.icon_font or style.icon_font
local color = style.text
if active or hovered then
color = style.accent
end
return character, font, color
end
---@param item widget.treelist.item
---@param active boolean
---@param hovered boolean
function TreeList:get_item_text(item, active, hovered)
local text = item.label
local font = style.font
local color = style.text
if active or hovered then
color = style.accent
end
return text, font, color
end
---@param item widget.treelist.item
---@param active boolean
---@param hovered boolean
---@param x number
---@param y number
---@param w number
---@param h number
function TreeList:draw_item_text(item, active, hovered, x, y, w, h)
local item_text, item_font, item_color = self:get_item_text(item, active, hovered)
return common.draw_text(item_font, item_color, item_text, "left", x, y, 0, h)
end
---@param item widget.treelist.item
---@param active boolean
---@param hovered boolean
---@param x number
---@param y number
---@param w number
---@param h number
function TreeList:draw_item_icon(item, active, hovered, x, y, w, h)
local icon_char, icon_font, icon_color = self:get_item_icon(item, active, hovered)
if not icon_char then return 0 end
common.draw_text(icon_font, icon_color, icon_char, "left", x, y, 0, h)
return self.item_icon_width + self.item_text_spacing
end
---@param item widget.treelist.item
---@param active boolean
---@param hovered boolean
---@param x number
---@param y number
---@param w number
---@param h number
function TreeList:draw_item_body(item, active, hovered, x, y, w, h)
x = x + self:draw_item_icon(item, active, hovered, x, y, w, h)
return self:draw_item_text(item, active, hovered, x, y, w, h)
end
---@param item widget.treelist.item
---@param active boolean
---@param hovered boolean
---@param x number
---@param y number
---@param w number
---@param h number
function TreeList:draw_item_chevron(item, active, hovered, x, y, w, h)
if item.childs and #item.childs > 0 then
local chevron_icon = item.expanded and "-" or "+"
local chevron_color = hovered and style.accent or style.text
common.draw_text(style.icon_font, chevron_color, chevron_icon, "left", x, y, 0, h)
end
return style.padding.x
end
---Get an item chevron starting and ending positions.
---@return number x1
---@return number x2
function TreeList:get_chevron_position(item)
local ox = self:get_content_offset()
local x1 = ox + item.depth * style.padding.x
local x2 = x1 + style.padding.x * 2
return x1, x2
end
---@param item widget.treelist.item
---@param active boolean
---@param hovered boolean
---@param x number
---@param y number
---@param w number
---@param h number
function TreeList:draw_item_background(item, active, hovered, x, y, w, h)
if hovered then
local hover_color = { table.unpack(style.line_highlight) }
hover_color[4] = 160
renderer.draw_rect(self.position.x, y, self.size.x, h, hover_color)
elseif active then
renderer.draw_rect(self.position.x, y, self.size.x, h, style.line_highlight)
end
end
---@param item widget.treelist.item
---@param active boolean
---@param hovered boolean
---@param x number
---@param y number
---@param w number
---@param h number
function TreeList:draw_item(item, active, hovered, x, y, w, h)
self:draw_item_background(item, active, hovered, x, y, w, h)
x = x + item.depth * style.padding.x + style.padding.x
x = x + self:draw_item_chevron(item, active, hovered, x, y, w, h)
return self:draw_item_body(item, active, hovered, x, y, w, h)
end
function TreeList:draw()
if not TreeList.super.draw(self) then return end
local position, ox = self:get_position(), self:get_content_offset()
local _y, _h, sw = position.y, self.size.y, 0
for item, x,y,w,h in self:each_item() do
if y + h >= _y and y < _y + _h then
w = self:draw_item(
item,
item == self.selected_item,
item == self.hovered_item,
x, y, w, h
) - position.x + (position.x - ox)
sw = math.max(w, sw)
end
end
self.scroll_width = sw
self:draw_scrollbar()
if
self.hovered_item and self.hovered_item.tooltip
and
self.tooltip.x and self.tooltip.alpha > 0
then
core.root_view:defer_draw(self.draw_tooltip, self)
end
end
---@param item? widget.treelist.item
---@param where integer
---@return widget.treelist.item item
---@return number x
---@return number y
---@return number w
---@return number h
function TreeList:get_item(item, where)
item = item or self.selected_item
local last_item, last_x, last_y, last_w, last_h
local stop = false
for it, x, y, w, h in self:each_item() do
if not item and where >= 0 then
return it, x, y, w, h
end
if item == it then
if where < 0 and last_item then
break
elseif where == 0 or (where < 0 and not last_item) then
return it, x, y, w, h
end
stop = true
elseif stop then
item = it
return it, x, y, w, h
end
last_item, last_x, last_y, last_w, last_h = it, x, y, w, h
end
return last_item, last_x, last_y, last_w, last_h
end
---@param item? widget.treelist.item
---@return widget.treelist.item item
---@return number x
---@return number y
---@return number w
---@return number h
function TreeList:get_next(item)
return self:get_item(item, 1)
end
---@param item? widget.treelist.item
---@return widget.treelist.item item
---@return number x
---@return number y
---@return number w
---@return number h
function TreeList:get_previous(item)
return self:get_item(item, -1)
end
function TreeList:select_next()
self.selected_item = self:get_next()
end
function TreeList:select_prev()
self.selected_item = self:get_previous()
end
---Expand or collapse the currently selected or given item.
---@param toggle? boolean
---@param item? widget.treelist.item
function TreeList:toggle_expand(toggle, item)
item = item or self.selected_item
if not item then return end
if item.childs and #item.childs > 0 then
if type(toggle) == "boolean" then
item.expanded = toggle
else
item.expanded = not item.expanded
end
end
end
return TreeList
+118
View File
@@ -0,0 +1,118 @@
-- mod-version:3
local subprocess = require "process"
local core = require "core"
local style = require "core.style"
local config = require "core.config"
local common = require "core.common"
config.plugins.fontconfig = common.merge({ prefix = "" }, config.plugins.fontconfig)
--[[
Example config (put it in user module):
```
local fontconfig = require "plugins.fontconfig"
fontconfig.use {
font = { name = 'sans', size = 13 * SCALE },
code_font = { name = 'monospace', size = 13 * SCALE },
}
```
if you want the fonts to load instantaneously on startup,
you can try your luck on fontconfig.use_blocking. I won't be responsible for
the slow startup time.
]]
local function resolve_font(spec)
local scan_rate = 1 / config.fps
local proc = subprocess.start({ config.plugins.fontconfig.prefix .. "fc-match", "-s", "-f", "%{file}\n", spec }, {
stdin = subprocess.REDIRECT_DISCARD,
stdout = subprocess.REDIRECT_PIPE,
stderr = subprocess.REDIRECT_STDOUT
})
local prev
local lines = {}
while true do
coroutine.yield(scan_rate)
local buf = proc:read_stdout()
if not buf then break end
local last_line_start = 1
for line, ln in string.gmatch(buf, "([^\n]-)\n()") do
last_line_start = ln
if prev then line = prev .. line end
table.insert(lines, line)
end
prev = last_line_start < #buf and string.sub(buf, last_line_start)
end
if prev then table.insert(lines, prev) end
if proc:returncode() ~= 0 or #lines < 1 then
error(string.format("Cannot find a font matching the given specs: %q", spec), 0)
end
return lines[1]
end
local M = {}
function M.load(font_name, font_size, font_opt)
local font_file = resolve_font(font_name)
return renderer.font.load(font_file, font_size, font_opt)
end
function M.load_blocking(font_name, font_size, font_opt)
local co = coroutine.create(function()
return M.load(font_name, font_size, font_opt)
end)
local result
while coroutine.status(co) ~= "dead" do
local ok, err = coroutine.resume(co)
if not ok then error(err) end
result = err
end
return result
end
function M.load_group_blocking(group, font_size, font_opt)
local fonts = {}
for i in ipairs(group) do
local co = coroutine.create(function()
return M.load(group[i], font_size, font_opt)
end)
local result
while coroutine.status(co) ~= "dead" do
local ok, err = coroutine.resume(co)
if not ok then error(err) end
result = err
end
table.insert(fonts, result)
end
return renderer.font.group(fonts)
end
function M.use(spec)
core.add_thread(function()
for key, value in pairs(spec) do
style[key] = M.load(value.name, value.size, value)
end
end)
end
-- there is basically no need for this, but for the sake of completeness
-- I'll leave this here
function M.use_blocking(spec)
for key, value in pairs(spec) do
local font
if value.group then
font = M.load_group_blocking(value.group, value.size, value)
else
font = M.load_blocking(value.name, value.size, value)
end
style[key] = font
end
end
return M
+51
View File
@@ -0,0 +1,51 @@
-- mod-version:3
local core = require "core"
local command = require "core.command"
local common = require "core.common"
local config = require "core.config"
local function exec(cmd)
local proc = process.start(cmd)
while proc:running() do
coroutine.yield(0.1)
end
if proc:returncode() > 0 then
core.error("ERROR - command: " .. table.concat(cmd, " "))
end
return proc:read_stdout() or ""
end
local function git_find_files_and_open(commit)
local git_root = exec({"git", "rev-parse", "--show-toplevel"}):match("^%s*(.-)%s*$")
local file_list_str = exec({"git", "show", "--name-only", "--pretty=format:", commit})
for str in string.gmatch(file_list_str, "([^\n]+)") do
-- Nomalize path as Git for Windows uses / as Unix based systems
local filename = common.normalize_path(git_root .. PATHSEP .. str)
-- Only open files within the commit whose names do not match the configured ignore file patterns
if not common.match_pattern(common.basename(filename), config.ignore_files) then
core.root_view:open_doc(core.open_doc(filename))
end
end
end
-- works in any context
command.add(nil, {
["gitopen:open-from-commit"] = function(dv)
core.command_view:enter("Which commit? (default=HEAD)", {
submit = function(commit)
if commit == nil or commit == "" then
commit = "HEAD"
end
-- open the files in the background, return immediately
core.add_thread(
function ()
git_find_files_and_open(commit)
end
)
end
})
end,
})
+155
View File
@@ -0,0 +1,155 @@
-- mod-version:3
local core = require "core"
local common = require "core.common"
local config = require "core.config"
local style = require "core.style"
local StatusView = require "core.statusview"
local TreeView = require "plugins.treeview"
config.plugins.gitstatus = common.merge({
color_icons = true,
recurse_submodules = true,
-- The config specification used by the settings gui
config_spec = {
name = "Git Status",
{
label = "Colorize icons",
description = "Colorize the icons as well",
path = "color_icons",
type = "toggle",
default = true
},
{
label = "Recurse Submodules",
description = "Also retrieve git stats from submodules.",
path = "recurse_submodules",
type = "toggle",
default = true
}
}
}, config.plugins.gitstatus)
style.gitstatus_addition = {common.color "#587c0c"}
style.gitstatus_modification = {common.color "#0c7d9d"}
style.gitstatus_deletion = {common.color "#94151b"}
local scan_rate = config.project_scan_rate or 5
local cached_color_for_item = {}
-- Override TreeView's get_item_text to add modification color
local treeview_get_item_text = TreeView.get_item_text
function TreeView:get_item_text(item, active, hovered)
local text, font, color = treeview_get_item_text(self, item, active, hovered)
if cached_color_for_item[item.abs_filename] then
color = cached_color_for_item[item.abs_filename]
end
return text, font, color
end
-- Override TreeView's get_item_icon to add modification color
local treeview_get_item_icon = TreeView.get_item_icon
function TreeView:get_item_icon(item, active, hovered)
local character, font, color = treeview_get_item_icon(self, item, active, hovered)
if config.plugins.gitstatus and config.plugins.gitstatus.color_icons and cached_color_for_item[item.abs_filename] then
color = cached_color_for_item[item.abs_filename]
end
return character, font, color
end
local git = {
branch = nil,
inserts = 0,
deletes = 0,
}
local function exec(cmd)
local proc = process.start(cmd)
-- Don't use proc:wait() here - that will freeze the app.
-- Instead, rely on the fact that this is only called within
-- a coroutine, and yield for a fraction of a second, allowing
-- other stuff to happen while we wait for the process to complete.
while proc:running() do
coroutine.yield(0.1)
end
return proc:read_stdout() or ""
end
core.add_thread(function()
while true do
if system.get_file_info(".git") then
-- get branch name
git.branch = exec({"git", "rev-parse", "--abbrev-ref", "HEAD"}):match("[^\n]*")
local inserts = 0
local deletes = 0
-- get diff
local diff = exec({"git", "diff", "--numstat"})
if
config.plugins.gitstatus.recurse_submodules
and
system.get_file_info(".gitmodules")
then
local diff2 = exec({"git", "submodule", "foreach", "git diff --numstat"})
diff = diff .. diff2
end
-- forget the old state
cached_color_for_item = {}
local folder = core.project_dir
for line in string.gmatch(diff, "[^\n]+") do
local submodule = line:match("^Entering '(.+)'$")
if submodule then
folder = core.project_dir .. PATHSEP .. submodule
else
local ins, dels, path = line:match("(%d+)%s+(%d+)%s+(.+)")
if path then
inserts = inserts + (tonumber(ins) or 0)
deletes = deletes + (tonumber(dels) or 0)
local abs_path = folder .. PATHSEP .. path
-- Color this file, and each parent folder,
-- so you can see at a glance which folders
-- have modified files in them.
while abs_path do
cached_color_for_item[abs_path] = style.gitstatus_modification
abs_path = common.dirname(abs_path)
end
end
end
end
git.inserts = inserts
git.deletes = deletes
else
git.branch = nil
end
coroutine.yield(scan_rate)
end
end)
core.status_view:add_item({
name = "status:git",
alignment = StatusView.Item.RIGHT,
get_item = function()
if not git.branch then
return {}
end
return {
(git.inserts ~= 0 or git.deletes ~= 0) and style.accent or style.text,
git.branch,
style.dim, " ",
git.inserts ~= 0 and style.accent or style.text, "+", git.inserts,
style.dim, " / ",
git.deletes ~= 0 and style.accent or style.text, "-", git.deletes,
}
end,
position = -1,
tooltip = "branch and changes",
separator = core.status_view.separator2
})
+39
View File
@@ -0,0 +1,39 @@
-- mod-version:3
local syntax = require "core.syntax"
syntax.add{
name = "R",
files = {"%.r$", "%.rds$", "%.rda$", "%.rdata$", "%.R$"},
comment = "#",
patterns = {
{pattern = {"#", "\n"}, type = "comment"},
{pattern = {'"', '"'}, type = "string"},
{pattern = {"'", "'"}, type = "string"},
{pattern = "[%a_][%w_]*%f[(]", type = "function"},
{pattern = "[%a_][%w_]*", type = "symbol"},
{pattern = "[%+%-=/%*%^%%<>!|&]", type = "operator"},
{pattern = "0x[%da-fA-F]+", type = "number"},
{pattern = "-?%d+[%d%.eE]*", type = "number"},
{pattern = "-?%.?%d+", type = "number"},
},
symbols = {
["TRUE"] = "literal",
["FALSE"] = "literal",
["NA"] = "literal",
["NULL"] = "literal",
["Inf"] = "literal",
["if"] = "keyword",
["else"] = "keyword",
["while"] = "keyword",
["function"] = "keyword",
["break"] = "keyword",
["next"] = "keyword",
["repeat"] = "keyword",
["in"] = "keyword",
["for"] = "keyword",
["NA_integer"] = "keyword",
["NA_complex"] = "keyword",
["NA_character"] = "keyword",
["NA_real"] = "keyword"
}
}
+88
View File
@@ -0,0 +1,88 @@
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "AngelScript",
files = { "%.as$", "%.asc$" },
comment = "//",
patterns = {
{ pattern = "//.-\n", type = "comment" },
{ pattern = { "/%*", "%*/" }, type = "comment" },
{ pattern = { "#", "[^\\]\n" }, type = "comment" },
{ pattern = { '"', '"', '\\' }, type = "string" },
{ pattern = { "'", "'", '\\' }, type = "string" },
{ pattern = "-?0[xX]%x+", type = "number" },
{ pattern = "-?0[bB][0-1]+", type = "number" },
{ pattern = "-?0[oO][0-7]+", type = "number" },
{ pattern = "-?%d+[%d%.eE]*f?", type = "number" },
{ pattern = "-?%.?%d+f?", type = "number" },
{ pattern = "&inout", type = "keyword" },
{ pattern = "&in", type = "keyword" },
{ pattern = "&out", type = "keyword" },
{ pattern = "[%a_][%w_]*@", type = "keyword2" },
{ pattern = "[%-%+!~@%?:&|%^<>%*/=%%]", type = "operator" },
{ pattern = "[%a_][%w_]*%f[(]", type = "function" },
{ pattern = "[%a_][%w_]*", type = "symbol" },
},
symbols = {
-- Common
["shared"] = "keyword",
["external"] = "keyword",
["private"] = "keyword",
["protected"] = "keyword",
["const"] = "keyword",
["final"] = "keyword",
["abstract"] = "keyword",
["class"] = "keyword",
["typedef"] = "keyword",
["namespace"] = "keyword",
["interface"] = "keyword",
["import"] = "keyword",
["enum"] = "keyword",
["funcdef"] = "keyword",
["get"] = "keyword",
["set"] = "keyword",
["mixin"] = "keyword",
["void"] = "keyword2",
["int"] = "keyword2",
["int8"] = "keyword2",
["int16"] = "keyword2",
["int32"] = "keyword2",
["int64"] = "keyword2",
["uint"] = "keyword2",
["uint8"] = "keyword2",
["uint16"] = "keyword2",
["uint32"] = "keyword2",
["uint64"] = "keyword2",
["float"] = "keyword2",
["double"] = "keyword2",
["bool"] = "keyword2",
["auto"] = "keyword",
["override"] = "keyword",
["explicit"] = "keyword",
["property"] = "keyword",
["break"] = "keyword",
["continue"] = "keyword",
["return"] = "keyword",
["switch"] = "keyword",
["case"] = "keyword",
["default"] = "keyword",
["for"] = "keyword",
["while"] = "keyword",
["do"] = "keyword",
["if"] = "keyword",
["else"] = "keyword",
["try"] = "keyword",
["catch"] = "keyword",
["cast"] = "keyword",
["function"] = "keyword",
["true"] = "literal",
["false"] = "literal",
["null"] = "literal",
["is"] = "operator",
["and"] = "operator",
["or"] = "operator",
["xor"] = "operator",
},
}
+538
View File
@@ -0,0 +1,538 @@
-- mod-version:3
-- Support for RISC-V assembly
-- Note: kinda conflicts with x86 asm, must uninstall it or use force-syntax plugin
-- https://github.com/cheyao
local syntax = require "core.syntax"
syntax.add {
name = "RISC-V Assembly",
files = { "%.asm$", "%.[sS]$" },
comment = "#",
patterns = {
{ pattern = "#.*\n", type = "comment" },
{ pattern = { '"', '"', '\\' }, type = "string" },
{ pattern = { "'", "'", '\\' }, type = "string" },
{ pattern = "0[bB][0-1]+%W", type = "number" },
{ pattern = "0[xX]%x+", type = "number" },
{ pattern = "%%+[%a_][%w_]*", type = "function" },
{ pattern = "[%a%._][%w%._]*:%W", type = "function" },
{ pattern = "[^%p%a]%-?%d[%d%.]*", type = "number" },
{ pattern = "[%+%-=/%*%^%%<>!~|&%$]", type = "operator" },
{ pattern = "[%a_][%w_]*", type = "symbol" },
{ pattern = "%.%a+", type = "normal" }
},
symbols = {
-- Integer Registers
["x0"] = "literal",
["x1"] = "literal",
["x2"] = "literal",
["x3"] = "literal",
["x4"] = "literal",
["x5"] = "literal",
["x6"] = "literal",
["x7"] = "literal",
["x8"] = "literal",
["x9"] = "literal",
["x10"] = "literal",
["x11"] = "literal",
["x12"] = "literal",
["x13"] = "literal",
["x14"] = "literal",
["x15"] = "literal",
["x16"] = "literal",
["x17"] = "literal",
["x18"] = "literal",
["x19"] = "literal",
["x20"] = "literal",
["x21"] = "literal",
["x22"] = "literal",
["x23"] = "literal",
["x24"] = "literal",
["x25"] = "literal",
["x26"] = "literal",
["x27"] = "literal",
["x28"] = "literal",
["x29"] = "literal",
["x30"] = "literal",
["x31"] = "literal",
["zero"] = "literal",
["ra"] = "literal",
["sp"] = "literal",
["gp"] = "literal",
["tp"] = "literal",
["t0"] = "literal",
["t1"] = "literal",
["t2"] = "literal",
["fp"] = "literal",
["s0"] = "literal",
["s1"] = "literal",
["a0"] = "literal",
["a1"] = "literal",
["a2"] = "literal",
["a3"] = "literal",
["a4"] = "literal",
["a5"] = "literal",
["a6"] = "literal",
["a7"] = "literal",
["s2"] = "literal",
["s3"] = "literal",
["s4"] = "literal",
["s5"] = "literal",
["s6"] = "literal",
["s7"] = "literal",
["s8"] = "literal",
["s9"] = "literal",
["s10"] = "literal",
["s11"] = "literal",
["t3"] = "literal",
["t4"] = "literal",
["t5"] = "literal",
["t6"] = "literal",
["pc"] = "literal",
-- Floating-point Registers
["f0"] = "literal",
["f1"] = "literal",
["f2"] = "literal",
["f3"] = "literal",
["f4"] = "literal",
["f5"] = "literal",
["f6"] = "literal",
["f7"] = "literal",
["f8"] = "literal",
["f9"] = "literal",
["f10"] = "literal",
["f11"] = "literal",
["f12"] = "literal",
["f13"] = "literal",
["f14"] = "literal",
["f15"] = "literal",
["f16"] = "literal",
["f17"] = "literal",
["f18"] = "literal",
["f19"] = "literal",
["f20"] = "literal",
["f21"] = "literal",
["f22"] = "literal",
["f23"] = "literal",
["f24"] = "literal",
["f25"] = "literal",
["f26"] = "literal",
["f27"] = "literal",
["f28"] = "literal",
["f29"] = "literal",
["f30"] = "literal",
["f31"] = "literal",
["ft0"] = "literal",
["ft1"] = "literal",
["ft2"] = "literal",
["ft3"] = "literal",
["ft4"] = "literal",
["ft5"] = "literal",
["ft6"] = "literal",
["ft7"] = "literal",
["fs0"] = "literal",
["fs1"] = "literal",
["fa0"] = "literal",
["fa1"] = "literal",
["fa2"] = "literal",
["fa3"] = "literal",
["fa4"] = "literal",
["fa5"] = "literal",
["fa6"] = "literal",
["fa7"] = "literal",
["fa2"] = "literal",
["fa3"] = "literal",
["fa4"] = "literal",
["fa5"] = "literal",
["fa6"] = "literal",
["fa7"] = "literal",
["fa8"] = "literal",
["fa9"] = "literal",
["fa10"] = "literal",
["fa11"] = "literal",
["ft8"] = "literal",
["ft9"] = "literal",
["ft10"] = "literal",
["ft11"] = "literal",
-- Vector Registers
["v0"] = "literal",
["v1"] = "literal",
["v2"] = "literal",
["v3"] = "literal",
["v4"] = "literal",
["v5"] = "literal",
["v6"] = "literal",
["v7"] = "literal",
["v8"] = "literal",
["v9"] = "literal",
["v10"] = "literal",
["v11"] = "literal",
["v12"] = "literal",
["v13"] = "literal",
["v14"] = "literal",
["v15"] = "literal",
["v16"] = "literal",
["v17"] = "literal",
["v18"] = "literal",
["v19"] = "literal",
["v20"] = "literal",
["v21"] = "literal",
["v22"] = "literal",
["v23"] = "literal",
["v24"] = "literal",
["v25"] = "literal",
["v26"] = "literal",
["v27"] = "literal",
["v28"] = "literal",
["v29"] = "literal",
["v30"] = "literal",
["v31"] = "literal",
["vl"] = "literal",
["vtype"] = "literal",
["vzrm"] = "literal",
["vxsat"] = "literal",
-- RV32I instructions
["lui"] = "keyword",
["auipc"] = "keyword",
["jal"] = "keyword",
["jalr"] = "keyword",
["beq"] = "keyword",
["bne"] = "keyword",
["blt"] = "keyword",
["bge"] = "keyword",
["bltu"] = "keyword",
["bgeu"] = "keyword",
["lb"] = "keyword",
["lh"] = "keyword",
["lw"] = "keyword",
["lbu"] = "keyword",
["lhu"] = "keyword",
["sb"] = "keyword",
["sh"] = "keyword",
["sw"] = "keyword",
["addi"] = "keyword",
["slti"] = "keyword",
["sltiu"] = "keyword",
["xori"] = "keyword",
["ori"] = "keyword",
["andi"] = "keyword",
["slli"] = "keyword",
["srli"] = "keyword",
["srai"] = "keyword",
["add"] = "keyword",
["sub"] = "keyword",
["sll"] = "keyword",
["slt"] = "keyword",
["sltu"] = "keyword",
["xor"] = "keyword",
["srl"] = "keyword",
["sra"] = "keyword",
["or"] = "keyword",
["and"] = "keyword",
["fence"] = "keyword",
["fence.tso"] = "keyword",
["pause"] = "keyword",
["ecall"] = "keyword",
["ebreak"] = "keyword",
-- RV64I instructions
["lwu"] = "keyword",
["ld"] = "keyword",
["sd"] = "keyword",
["slli"] = "keyword",
["srli"] = "keyword",
["srai"] = "keyword",
["addiw"] = "keyword",
["slliw"] = "keyword",
["srliw"] = "keyword",
["sraiw"] = "keyword",
["addw"] = "keyword",
["subw"] = "keyword",
["sllw"] = "keyword",
["srlw"] = "keyword",
["sraw"] = "keyword",
-- Zifencei instructions
["fence.i"] = "keyword",
-- Zicsr instructions
["csrrw"] = "keyword",
["csrrs"] = "keyword",
["csrrc"] = "keyword",
["csrrwi"] = "keyword",
["csrrsi"] = "keyword",
["csrrci"] = "keyword",
-- RV32M instructions
["mul"] = "keyword",
["mulh"] = "keyword",
["mulhsu"] = "keyword",
["mulhu"] = "keyword",
["div"] = "keyword",
["divu"] = "keyword",
["rem"] = "keyword",
["remu"] = "keyword",
-- RV64M instructions
["mulw"] = "keyword",
["divw"] = "keyword",
["divuw"] = "keyword",
["remw"] = "keyword",
["remuw"] = "keyword",
-- RV32A instructions
["lr.w"] = "keyword",
["sc.w"] = "keyword",
["amoswap.w"] = "keyword",
["amoadd.w"] = "keyword",
["amoxor.w"] = "keyword",
["amoand.w"] = "keyword",
["amoor.w"] = "keyword",
["amomin.w"] = "keyword",
["amomax.w"] = "keyword",
["amominu.w"] = "keyword",
["amomaxu.w"] = "keyword",
-- RV64A instructions
["lr.d"] = "keyword",
["sc.d"] = "keyword",
["amoswap.d"] = "keyword",
["amoadd.d"] = "keyword",
["amoxor.d"] = "keyword",
["amoand.d"] = "keyword",
["amoor.d"] = "keyword",
["amomin.d"] = "keyword",
["amomax.d"] = "keyword",
["amominu.d"] = "keyword",
["amomaxu.d"] = "keyword",
-- RV32F instructions
["flw"] = "keyword",
["fsw"] = "keyword",
["fmadd.s"] = "keyword",
["fmsub.s"] = "keyword",
["fnmsub.s"] = "keyword",
["fnmadd.s"] = "keyword",
["fadd.s"] = "keyword",
["fsub.s"] = "keyword",
["fmul.s"] = "keyword",
["fdiv.s"] = "keyword",
["fsqrt.s"] = "keyword",
["fsgnj.s"] = "keyword",
["fsgnjn.s"] = "keyword",
["fsgnjx.s"] = "keyword",
["fmin.s"] = "keyword",
["fmax.s"] = "keyword",
["fcvt.w.s"] = "keyword",
["fcvt.wu.s"] = "keyword",
["fmv.x.w"] = "keyword",
["feq.s"] = "keyword",
["flt.s"] = "keyword",
["fle.s"] = "keyword",
["fclass.s"] = "keyword",
["fcvt.s.w"] = "keyword",
["fcvt.s.wu"] = "keyword",
["fmv.w.x"] = "keyword",
-- RV64F instructions
["fcvt.l.s"] = "keyword",
["fcvt.lu.s"] = "keyword",
["fcvt.s.l"] = "keyword",
["fcvt.s.lu"] = "keyword",
-- RV32D instructions
["fld"] = "keyword",
["fsd"] = "keyword",
["fmadd.d"] = "keyword",
["fmsub.d"] = "keyword",
["fnmsub.d"] = "keyword",
["fnmadd.d"] = "keyword",
["fadd.d"] = "keyword",
["fsub.d"] = "keyword",
["fmul.d"] = "keyword",
["fdiv.d"] = "keyword",
["fsqrt.d"] = "keyword",
["fsgnj.d"] = "keyword",
["fsgnjn.d"] = "keyword",
["fsgnjx.d"] = "keyword",
["fmin.d"] = "keyword",
["fmax.d"] = "keyword",
["fcvt.s.d"] = "keyword",
["fcvt.d.s"] = "keyword",
["feq.d"] = "keyword",
["flt.d"] = "keyword",
["fle.d"] = "keyword",
["fclass.d"] = "keyword",
["fcvt.w.d"] = "keyword",
["fcvt.wu.d"] = "keyword",
["fcvt.d.w"] = "keyword",
["fcvt.d.wu"] = "keyword",
-- RV64D instructions
["fcvt.l.d"] = "keyword",
["fcvt.lu.d"] = "keyword",
["fmv.x.d"] = "keyword",
["fcvt.d.l"] = "keyword",
["fcvt.d.lu"] = "keyword",
["fmv.d.x"] = "keyword",
-- RV32Q instructions
["flq"] = "keyword",
["fsq"] = "keyword",
["fmadd.q"] = "keyword",
["fmsub.q"] = "keyword",
["fnmsub.q"] = "keyword",
["fnmadd.q"] = "keyword",
["fadd.q"] = "keyword",
["fsub.q"] = "keyword",
["fmul.q"] = "keyword",
["fdiv.q"] = "keyword",
["fsqrt.q"] = "keyword",
["fsgnj.q"] = "keyword",
["fsgnjn.q"] = "keyword",
["fsgnjx.q"] = "keyword",
["fmin.q"] = "keyword",
["fmax.q"] = "keyword",
["fcvt.s.q"] = "keyword",
["fcvt.q.s"] = "keyword",
["fcvt.d.q"] = "keyword",
["fcvt.q.d"] = "keyword",
["feq.q"] = "keyword",
["flt.q"] = "keyword",
["fle.q"] = "keyword",
["fclass.q"] = "keyword",
["fcvt.w.q"] = "keyword",
["fcvt.wu.q"] = "keyword",
["fcvt.q.w"] = "keyword",
["fcvt.q.wu"] = "keyword",
-- RV64Q instructions
["fcvt.l.q"] = "keyword",
["fcvt.lu.q"] = "keyword",
["fcvt.q.l"] = "keyword",
["fcvt.q.lu"] = "keyword",
-- RV32Zfh instructions
["flh"] = "keyword",
["fsh"] = "keyword",
["fmadd.h"] = "keyword",
["fmsub.h"] = "keyword",
["fnmsub.h"] = "keyword",
["fnmadd.h"] = "keyword",
["fadd.h"] = "keyword",
["fsub.h"] = "keyword",
["fmul.h"] = "keyword",
["fdiv.h"] = "keyword",
["fsqrt.h"] = "keyword",
["fsgnj.h"] = "keyword",
["fsgnjn.h"] = "keyword",
["fsgnjx.h"] = "keyword",
["fmin.h"] = "keyword",
["fmax.h"] = "keyword",
["fcvt.s.h"] = "keyword",
["fcvt.h.s"] = "keyword",
["fcvt.d.h"] = "keyword",
["fcvt.h.d"] = "keyword",
["fcvt.q.h"] = "keyword",
["fcvt.h.q"] = "keyword",
["feq.h"] = "keyword",
["flt.h"] = "keyword",
["fle.h"] = "keyword",
["fclass.h"] = "keyword",
["fcvt.w.h"] = "keyword",
["fcvt.wu.h"] = "keyword",
["fmv.x.h"] = "keyword",
["fcvt.h.w"] = "keyword",
["fcvt.h.wu"] = "keyword",
["fmv.h.x"] = "keyword",
-- RV64Zfh instructions
["fcvt.l.h"] = "keyword",
["fcvt.lu.h"] = "keyword",
["fcvt.h.l"] = "keyword",
["fcvt.h.lu"] = "keyword",
-- Pesudo-instructions
["nop"] = "keyword",
["li"] = "keyword",
["mv"] = "keyword",
["not"] = "keyword",
["neg"] = "keyword",
["negw"] = "keyword",
["sext.w"] = "keyword",
["seqz"] = "keyword",
["snez"] = "keyword",
["sltz"] = "keyword",
["sgtz"] = "keyword",
["fmv.s"] = "keyword",
["fabs.s"] = "keyword",
["fneg.s"] = "keyword",
["fmv.d"] = "keyword",
["fabs.d"] = "keyword",
["fneg.d"] = "keyword",
["beqz"] = "keyword",
["bnez"] = "keyword",
["blez"] = "keyword",
["bgez"] = "keyword",
["bltz"] = "keyword",
["bgtz"] = "keyword",
["bgt"] = "keyword",
["ble"] = "keyword",
["bgtu"] = "keyword",
["bleu"] = "keyword",
["j"] = "keyword",
["jr"] = "keyword",
["ret"] = "keyword",
["call"] = "keyword",
["tail"] = "keyword",
-- Other
[".2byte"] = "keyword2",
[".4byte"] = "keyword2",
[".8byte"] = "keyword2",
[".half"] = "keyword2",
[".word"] = "keyword2",
[".dword"] = "keyword2",
[".byte"] = "keyword2",
[".dtpreldword"] = "keyword2",
[".dtprelword"] = "keyword2",
[".sleb128"] = "keyword2",
[".uleb128"] = "keyword2",
[".asciz"] = "keyword2",
[".string"] = "keyword2",
[".incbin"] = "keyword2",
[".zero"] = "keyword2",
[".align"] = "keyword2",
[".balign"] = "keyword2",
[".p2align"] = "keyword2",
[".globl"] = "keyword2",
[".local"] = "keyword2",
[".equ"] = "keyword2",
[".text"] = "keyword2",
[".data"] = "keyword2",
[".rodata"] = "keyword2",
[".bss"] = "keyword2",
[".comm"] = "keyword2",
[".common"] = "keyword2",
[".section"] = "keyword2",
[".option"] = "keyword2",
[".macro"] = "keyword2",
[".endm"] = "keyword2",
[".file"] = "keyword2",
[".ident"] = "keyword2",
[".size"] = "keyword2",
[".type"] = "keyword2",
},
}
File diff suppressed because it is too large Load Diff
+155
View File
@@ -0,0 +1,155 @@
-- mod-version:3
local syntax = require "core.syntax"
-- AHK has case insensitive grammer
local variables = {
"A_AhkPath", "A_AhkVersion", "A_AppData", "A_AppDataCommon", "A_AutoTrim",
"A_BatchLines", "A_CaretX", "A_CaretY", "A_Computername", "A_ControlDelay",
"A_Cursor", "A_DD", "A_DDD", "A_DDDD", "A_DefaultMouseSpeed",
"A_Desktop", "A_Desktopcommon", "A_Detecthiddentext", "A_Detecthiddenwindows", "A_Endchar",
"A_EventInfo", "A_ExitReason", "A_FileEncoding", "A_FormatFloat", "A_FormatInteger",
"A_Gui", "A_GuiControl", "A_GuiControlEvent", "A_GuiEvent", "A_GuiHeight",
"A_GuiWidth", "A_GuiX", "A_GuiY", "A_Hour", "A_IconFile",
"A_IconHidden", "A_IconNumber", "A_IconTip", "A_Index", "A_IpAddress1",
"A_IpAddress2", "A_IpAddress3", "A_IpAddress4", "A_Is64bitOS", "A_IsAdmin",
"A_IsCompiled", "A_IsCritical", "A_IsPaused", "A_IsSuspended", "A_IsUnicode",
"A_KeyDelay", "A_Language", "A_LastError", "A_LineFile", "A_LineNumber",
"A_LoopField", "A_LoopFileAttrib", "A_LoopFileDir", "A_LoopFileExt", "A_LoopFileFullPath",
"A_LoopFileLongPath", "A_LoopFileName", "A_LoopFileShortName", "A_LoopFileShortPath", "A_LoopFileSize",
"A_LoopFileSizeKB", "A_LoopFileSizeMB", "A_LoopFileTimeAccessed", "A_LoopFileTimeCreated", "A_LoopFileTimeModified",
"A_LoopReadLine", "A_LoopRegKey", "A_LoopRegName", "A_LoopRegSubKey", "A_LoopRegTimeModified",
"A_LoopRegType", "A_MDay", "A_Min", "A_MM", "A_MMM",
"A_MMMM", "A_Mon", "A_MouseDelay", "A_MSec", "A_MyDocuments",
"A_Now", "A_NowUTC", "A_NumBatchLines", "A_OSType", "A_OSVersion",
"A_PriorHotkey", "A_PriorKey", "A_ProgramFiles", "A_Programs", "A_ProgramsCommon",
"A_PtrSize", "A_RegView", "A_ScreenDpi", "A_ScreenHeight", "A_ScreenWidth",
"A_ScriptDir", "A_ScriptFullPath", "A_ScriptHwnd", "A_ScriptName", "A_Sec",
"A_Space", "A_StartMenu", "A_StartMenuCommon", "A_StartUp", "A_StartUpCommon",
"A_StringCaseSense", "A_Tab", "A_Temp", "A_ThisFunc", "A_ThisHotkey",
"A_ThisLabel", "A_ThisMenu", "A_ThisMenuItem", "A_ThisMenuItemPos", "A_TickCount",
"A_TimeIdle", "A_TimeIdlePhysical", "A_TimeSincePriorHotkey", "A_TimeSinceThisHotkey", "A_TitleMatchMode",
"A_TitleMatchModeSpeed", "A_UserName", "A_WDay", "A_WinDelay", "A_WinDir",
"A_WorkingDir", "A_YDay", "A_Year", "A_YWeek", "A_YYYY",
"CipboardAll", "Clipboard", "ComSpec", "ErrorLevel", "False",
"ProgramFiles", "True",
}
local keywords = {
"Break", "ByRef", "Case", "Catch", "Class",
"Continue", "Else", "Else", "Exit", "ExitApp",
"Finally", "For", "Global", "Gosub", "Goto",
"If", "Local", "Loop", "OnExit", "Pause",
"Return", "Sleep", "static", "suspend", "Switch",
"Throw", "Try", "Until", "While",
}
local functions = {
"_NewEnum", "Abs", "ACos", "Array", "Asc",
"ASin", "ATan", "Ceil", "Chr", "ComObjActive",
"ComObjArray", "ComObjConnect", "ComObjCreate", "ComObject", "ComObjError",
"ComObjFlags", "ComObjGet", "ComObjQuery", "ComObjType", "ComObjValue",
"Cos", "DllCall", "Exception", "Exp", "FileExist",
"FileOpen", "Floor", "Format", "Func", "GetKeyName",
"GetKeySC", "GetKeyState", "GetKeyVK", "IL_Add", "IL_Create",
"IL_Destroy", "InStr", "IsByRef", "IsFunc", "IsLabel",
"IsObject", "Ln", "Log", "LTrim", "LV_Add",
"LV_Delete", "LV_DeleteCol", "LV_GetCount", "LV_GetNext", "LV_GetText",
"LV_Insert", "LV_InsertCol", "LV_Modify", "LV_ModifyCol", "LV_SetImageList",
"Mod", "NumGet", "NumPut", "ObjAddRef", "ObjClone",
"Object", "ObjGetAddress", "ObjGetCapacity", "ObjHasKey", "ObjInsert",
"ObjMaxIndex", "ObjMinIndex", "ObjNewEnum", "ObjRelease", "ObjRemove",
"ObjSetCapacity", "OnMessage", "RegExMatch", "RegExReplace", "RegisterCallback",
"Round", "RTrim", "SB_SetIcon", "SB_SetParts", "SB_SetText",
"Sin", "Sqrt", "StrGet", "StrLen", "StrPut",
"StrReplace", "StrSplit", "SubStr", "Tan", "Trim",
"TV_Add", "TV_Delete", "TV_Get", "TV_GetChild", "TV_GetCount",
"TV_GetNext", "TV_GetParent", "TV_GetPrev", "TV_GetSelection", "TV_GetText",
"TV_Modify", "TV_SetImageList", "VarSetCapacity", "WinActive", "WinExist",
}
local commands = {
"AutoTrim", "BlockInput", "Click", "ClipWait", "Control",
"ControlClick", "ControlFocus", "ControlGet", "ControlGetFocus", "ControlGetPos",
"ControlGetText", "ControlMove", "ControlSend", "ControlSendRaw", "ControlSetText",
"CoordMode", "Critical", "DetectHiddenText", "DetectHiddenWindows", "Drive",
"DriveGet", "DriveSpaceFree", "Edit", "EnvAdd", "EnvGet",
"EnvSet", "EnvSub", "EnvUpdate", "FileAppend", "FileCopy",
"FileCopyDir", "FileCreateDir", "FileCreateShortcut", "FileDelete", "FileEncoding",
"FileGetAttrib", "FileGetShortcut", "FileGetSize", "FileGetTime", "FileGetVersion",
"FileInstall", "FileMove", "FileMoveDir", "FileRead", "FileReadLine",
"FileRecycle", "FileRecycleEmpty", "FileRemoveDir", "FileSelectFile", "FileSelectFolder",
"FileSetAttrib", "FileSetTime", "FormatTime", "GroupActivate", "GroupAdd",
"GroupClose", "GroupDeactivate", "Gui", "GuiControl", "GuiControlGet",
"Hotkey", "ImageSearch", "IniDelete", "IniRead", "IniWrite",
"Input", "InputBox", "KeyHistory", "KeyWait", "ListHotkeys",
"ListLines", "ListVars", "Menu", "MouseClick", "MouseClickDrag",
"MouseGetPos", "MouseMove", "MsgBox", "OutputDebug", "PixelGetColor",
"PixelSearch", "PostMessage", "Process", "Random", "RegDelete",
"RegRead", "RegWrite", "Reload", "Run", "RunAs",
"RunWait", "Send", "SendEvent", "SendInput", "SendLevel",
"SendMessage", "SendMode", "SendPlay", "SendRaw", "SetBatchLines",
"SetCapsLockState", "SetControlDelay", "SetDefaultMouseSpeed", "SetEnv", "SetKeyDelay",
"SetMouseDelay", "SetNumLockState", "SetRegView", "SetScrollLockState", "SetStoreCapsLockMode",
"SetTimer", "SetTitleMatchMode", "SetWinDelay", "SetWorkingDir", "Shutdown",
"Sort", "SoundBeep", "SoundGet", "SoundGetWaveVolume", "SoundPlay",
"SoundSet", "SoundSetWaveVolume", "Splitpath", "StatusBarGetText", "StatusBarWait",
"StringCaseSense", "StringLower", "StringUpper", "SysGet", "Thread",
"ToolTip", "Transform", "TrayTip", "UrlDownloadToFile", "WinActivate",
"WinActivateBottom", "WinClose", "WinGet", "WinGetActiveStats", "WinGetActiveTitle",
"WinGetClass", "WinGetPos", "WinGetText", "WinGetTitle", "WinHide",
"WinKill", "WinMaximize", "WinMenuSelectItem", "WinMinimize", "WinMinimizeAll",
"WinMinimizeAllUndo", "WinMove", "WinRestore", "WinSet", "WinSetTitle",
"WinShow", "WinWait", "WinWaitActive", "WinWaitClose", "WinWaitNotActive",
}
local symbols = {}
for _, elementVar in ipairs(variables) do
symbols[string.lower(elementVar)] = "operator" --a_year
symbols[string.upper(elementVar)] = "operator" --A_YEAR
symbols[string.format("%s%s", string.sub(elementVar, 1, 1), string.lower(string.sub(elementVar, 2)))] = "operator" --A_year
symbols[elementVar] = "operator" --A_Year
end
for _, elementKeyword in ipairs(keywords) do
symbols[string.lower(elementKeyword)] = "function" --byref
symbols[string.upper(elementKeyword)] = "function" --BYREF
symbols[string.format("%s%s", string.sub(elementKeyword, 1, 1), string.lower(string.sub(elementKeyword, 2)))] = "function" --Byref
symbols[elementKeyword] = "function" --ByRef
end
for _, elementFunction in ipairs(functions) do
symbols[string.lower(elementFunction)] = "keyword2" --lv_modifycol()
symbols[string.upper(elementFunction)] = "keyword2" --LV_MODIFYCOL()
symbols[string.format("%s%s", string.sub(elementFunction, 1, 1), string.lower(string.sub(elementFunction, 2)))] = "keyword2" --Lv_modifycol()
symbols[elementFunction] = "keyword2" --LV_ModifyCol()
end
for _, elementCommands in ipairs(commands) do
symbols[string.lower(elementCommands)] = "keyword" --fileencoding
symbols[string.upper(elementCommands)] = "keyword" --FILEENCODING
symbols[string.format("%s%s", string.sub(elementCommands, 1, 1), string.lower(string.sub(elementCommands, 2)))] = "keyword" --Fileencoding
symbols[elementCommands] = "keyword" --FileEncoding
end
syntax.add {
name = "AutoHotkey",
files = { "%.ahk$"},
comment = ";",
patterns = {
{ pattern = { ";", "\n" }, type = "comment" },
{ pattern = { "/%*", "*%/" }, type = "comment" },
{ pattern = { "[ruU]?%%", "[%% ]", '\\' }, type = "operator" },
{ pattern = { "[ruU]?%%", "[ ,]", '\\' }, type = "normal" },
{ pattern = { '[ruU]?"""', '"""'; '\\' }, type = "string" },
{ pattern = { '[ruU]?"', '"', '\\' }, type = "string" },
{ pattern = "0x[%da-fA-F]+", type = "number" },
{ pattern = "-?%d+[%d%.eE]*", type = "number" },
{ pattern = "-?%.?%d+", type = "number" },
{ pattern = "[%+%-=/%*%^<>!~|&]", type = "operator" },
{ pattern = ":=", type = "operator" },
{ pattern = ".=", type = "operator" },
{ pattern = "[%a_][%w_]*%f[(]", type = "function" },
{ pattern = "[%a_][%w_]*", type = "symbol" },
},
symbols = symbols,
}
+110
View File
@@ -0,0 +1,110 @@
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "Awk script",
files = "%.awk$",
headers = "^#!.*bin.*awk",
comment = "#",
patterns = {
-- $# is a awk special variable and the '#' shouldn't be interpreted
-- as a comment.
{ pattern = "%$[%a_@*#][%w_]*", type = "keyword2" },
-- Comments
{ pattern = "#.*", type = "comment" },
-- Strings
{ pattern = { '"', '"', '\\' }, type = "string" },
{ pattern = { "'", "'", '\\' }, type = "string" },
{ pattern = { '`', '`', '\\' }, type = "string" },
-- Ignore numbers that start with dots or slashes
{ pattern = "%f[%w_%.%/]%d[%d%.]*%f[^%w_%.]", type = "number" },
-- Operators
{ pattern = "[!<>|&%[%]:=*]", type = "operator" },
-- Match parameters
{ pattern = "%f[%S][%+%-][%w%-_:]+", type = "function" },
{ pattern = "%f[%S][%+%-][%w%-_]+%f[=]", type = "function" },
-- Prevent parameters with assignments from been matched as variables
{
pattern = "%s%-%a[%w_%-]*()%s+()%d[%d%.]+",
type = { "function", "normal", "number" }
},
{
pattern = "%s%-%a[%w_%-]*()%s+()%a[%a%-_:=]+",
type = { "function", "normal", "symbol" }
},
-- Match variable assignments
{ pattern = "[_%a][%w_]+%f[%+=]", type = "keyword2" },
-- Match variable expansions
{ pattern = "%${.-}", type = "keyword2" },
{ pattern = "%$[%d%$%a_@*][%w_]*", type = "keyword2" },
-- Functions
{ pattern = "[%a_%-][%w_%-]*()%s*%f[(]", type = { "function", "normal" } },
-- Everything else
{ pattern = "[%a_][%w_]*", type = "symbol" },
},
symbols = {
["break"] = "keyword",
["continue"] = "keyword",
["do"] = "keyword",
["delete"] = "keyword",
["else"] = "keyword",
["exit"] = "keyword",
["for"] = "keyword",
["function"] = "keyword",
["getline"] = "keyword",
["if"] = "keyword",
["next"] = "keyword",
["nextfile"] = "keyword",
["print"] = "keyword",
["printf"] = "keyword",
["return"] = "keyword",
["while"] = "keyword",
["gsub"] = "keyword",
["index"] = "keyword",
["length"] = "keyword",
["match"] = "keyword",
["split"] = "keyword",
["sprintf"] = "keyword",
["sub"] = "keyword",
["substr"] = "keyword",
["tolower"] = "keyword",
["toupper"] = "keyword",
["atan2"] = "keyword",
["cos"] = "keyword",
["exp"] = "keyword",
["int"] = "keyword",
["log"] = "keyword",
["rand"] = "keyword",
["sin"] = "keyword",
["sqrt"] = "keyword",
["srand"] = "keyword",
["BEGIN"] = "keyword",
["END"] = "keyword",
["ARGC"] = "keyword",
["ARGV"] = "keyword",
["FILENAME"] = "keyword",
["FNR"] = "keyword",
["FS"] = "keyword",
["NF"] = "keyword",
["NR"] = "keyword",
["OFMT"] = "keyword",
["OFS"] = "keyword",
["ORS"] = "keyword",
["RLENGTH"] = "keyword",
["RS"] = "keyword",
["RSTART"] = "keyword",
["SUBSEP"] = "keyword",
["ARGIND"] = "keyword",
["BINMODE"] = "keyword",
["CONVFMT"] = "keyword",
["ENVIRON"] = "keyword",
["ERRNO"] = "keyword",
["FIELDWIDTHS"] = "keyword",
["IGNORECASE"] = "keyword",
["LINT"] = "keyword",
["PROCINFO"] = "keyword",
["RT"] = "keyword",
["RLENGTH"] = "keyword",
["TEXTDOMAIN"] = "keyword"
}
}
+63
View File
@@ -0,0 +1,63 @@
-- mod-version:3
local syntax = require "core.syntax"
-- batch syntax for lite <liqube>
-- windows batch files use caseless matching for symbols
local symtable = {
["keyword"] = {
"if", "else", "not", "for", "do", "in",
"equ", "neq", "lss", "leq", "gtr", "geq", -- == != < <= > >=
"nul", "con", "prn", "prn", "lpt1", "com1", "com2", "com3", "com4",
"exist", "defined",
"errorlevel", "cmdextversion",
"goto", "call", "verify",
},
["function"] = {
"set", "setlocal", "endlocal", "enabledelayedexpansion",
"echo", "type",
"cd", "chdir",
"md", "mkdir",
"pause", "choice", "exit",
"del", "rd", "rmdir",
"copy", "xcopy",
"move", "ren",
"find", "findstr",
"sort", "shift", "attrib",
"cmd", "command",
"forfiles",
},
}
-- prepare a mixed symbol list
local function prepare_symbols(symtable)
local symbols = { }
for symtype, symlist in pairs(symtable) do
for _, symname in ipairs(symlist) do
symbols[symname:lower()] = symtype
symbols[symname:upper()] = symtype
end
end
return symbols
end
syntax.add {
name = "Batch",
files = { "%.bat$", "%.cmd$" },
comment = "rem",
patterns = {
{ pattern = "@echo off\n", type = "keyword" },
{ pattern = "@echo on\n", type = "keyword" },
{ pattern = "rem.-\n", type = "comment" }, -- rem comment line, rem, rem.
{ pattern = "REM.-\n", type = "comment" },
{ pattern = "%s*:[%w%-]+", type = "symbol" }, -- :labels
{ pattern = "%:%:.-\n", type = "comment" }, -- :: comment line
{ pattern = "%%%w+%%", type = "symbol" }, -- %variable%
{ pattern = "%%%%?~?[%w:]+", type = "symbol" }, -- %1, %~dpn1, %~1:2, %%i, %%~i
{ pattern = "[!=()%>&%^/\\@]", type = "operator" }, -- operators
{ pattern = "-?%.?%d+f?", type = "number" }, -- integer numbers
{ pattern = { '"', '"', '\\' }, type = "string" }, -- "strings"
{ pattern = "[%a_][%w_]*", type = "normal" },
{ pattern = ":eof", type = "keyword" }, -- not quite as intended, but ok for now
},
symbols = prepare_symbols(symtable),
}
+65
View File
@@ -0,0 +1,65 @@
-- Author: Rohan Vashisht https://github.com/RohanVashisht1234
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "Bend",
files = { "%.bend$" },
comment = "#",
patterns = {
{ pattern = "#.*", type = "comment" },
{ pattern = { '"', '"' }, type = "string" },
{ pattern = { "'", "'" }, type = "string" },
{ pattern = "[%a_][%w_]*%f[(]", type = "function" },
{ pattern = "[%a_][%w_]*", type = "symbol" },
{ pattern = "[%+%-=/%*%^%%<>!|&]", type = "operator" },
{ pattern = "def()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok
{ pattern = "data()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok
{ pattern = "let()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok
{ pattern = "Some()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok
{ pattern = "bend()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok
{ pattern = "object()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok
{ pattern = "fold()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok
{ pattern = "open()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok
{ pattern = "do()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok
{ pattern = "identity()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok
{ pattern = "lambda()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok
{ pattern = "0x[%da-fA-F]+", type = "number" },
{ pattern = "-?%d+[%d%.eE]*", type = "number" },
{ pattern = "-?%.?%d+", type = "number" },
},
symbols = {
["def"] = "keyword",
["switch"] = "keyword",
["case"] = "keyword",
["return"] = "keyword",
["if"] = "keyword",
["else"] = "keyword",
["when"] = "keyword",
["match"] = "keyword",
["λ"] = "keyword",
["Some"] = "keyword",
["data"] = "keyword",
["let"] = "keyword",
["use"] = "keyword",
["object"] = "keyword",
["fold"] = "keyword",
["open"] = "keyword",
["do"] = "keyword",
["bind"] = "keyword",
["Name"] = "keyword",
["identity"] = "keyword",
["Bool"] = "keyword",
["ask"] = "keyword",
["with"] = "keyword",
["bend"] = "keyword2",
["None"] = "keyword2",
["Nil"] = "keyword2",
["Result"] = "keyword2",
["type"] = "keyword2",
["true"] = "literal",
["false"] = "literal",
}
}
+23
View File
@@ -0,0 +1,23 @@
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "BibTeX",
files = { "%.bib$" },
comment = "%%",
patterns = {
{ pattern = {"%%", "\n"}, type = "comment" },
{ pattern = "@%a+", type = "keyword" },
{ pattern = "%a+%s=", type = "keyword2" },
},
symbols = {
["author"] = "keyword",
["doi"] = "keyword",
["issue"] = "keyword",
["journal"] = "keyword",
["month"] = "keyword",
["numpages"] = "keyword",
["pages"] = "keyword",
["publisher"] = "keyword",
}
}
+57
View File
@@ -0,0 +1,57 @@
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "Blade",
files = { "%.b$" },
comment = "#",
patterns = {
{ pattern = "#.*", type = "comment" },
{ pattern = { "/%*", "%*/" }, type = "comment" },
{ pattern = { '"', '"', '\\' }, type = "string" },
{ pattern = { "'", "'", '\\' }, type = "string" },
{ pattern = "%d+%.%d+", type = "number" },
{ pattern = "0x%x+", type = "number" },
{ pattern = "0c[0-8]+", type = "number" },
{ pattern = "0c[01]+", type = "number" },
{ pattern = "%d+", type = "number" },
{ pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" },
{ pattern = "[%a_][%w_]*%f[(]", type = "function" },
{ pattern = "%a[%w_]+", type = "symbol" },
},
-- https://bladelang.com/tutorial/reserved.html#reserved-words
symbols = {
["and"] = "keyword",
["continue"] = "keyword",
["else"] = "keyword",
["in"] = "keyword",
["self"] = "keyword2",
["when"] = "keyword",
["as"] = "keyword",
["def"] = "keyword",
["iter"] = "keyword",
["static"] = "keyword",
["while"] = "keyword",
["assert"] = "keyword",
["default"] = "keyword",
["finally"] = "keyword",
["break"] = "keyword",
["die"] = "keyword",
["for"] = "keyword",
["or"] = "keyword",
["try"] = "keyword",
["catch"] = "keyword",
["do"] = "keyword",
["if"] = "keyword",
["parent"] = "keyword",
["using"] = "keyword",
["class"] = "keyword",
["echo"] = "function",
["import"] = "keyword",
["return"] = "keyword",
["var"] = "keyword",
["true"] = "literal",
["false"] = "literal",
["nil"] = "literal",
},
}
+90
View File
@@ -0,0 +1,90 @@
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "Blueprint",
files = { "%.blp$", },
comment = "//",
block_comment = {"/*", "*/"},
patterns = {
-- Comments
{ pattern = "//.*", type = "comment" },
{ pattern = { "/%*", "%*/" }, type = "comment" },
-- Strings
{ pattern = { "'", "'", "\\"}, type = "string" },
{ pattern = { '"', '"', "\\" }, type = "string" },
-- Numbers
{ pattern = "%.?%d+", type = "number" },
-- Child type
{ pattern = "%[.*%]", type = "literal" },
-- Operators
{ pattern = "%$", type = "operator" },
{ pattern = "=>%s*%$().*()%(%)", type = { "operator", "function", "normal" } },
-- Properties
{ pattern = "[%w-_]+()%s*:", type = { "keyword", "normal" } },
-- Classes
{ pattern = "[%w_-%.]+%s*(){", type = { "keyword2", "normal"} },
{ pattern = "[%w_-%.]+%s*()[%w_-]+%s*{", type = { "keyword2", "normal"} },
-- Symbols
{ pattern = "[%w-_]+", type = "symbol" },
},
symbols = {
["true"] = "literal",
["false"] = "literal",
["null"] = "literal",
-- Import statements
["using"] = "keyword",
-- Keywords
["after"] = "keyword",
["bidirectional"] = "keyword",
["bind-property"] = "keyword",
["bind"] = "keyword",
["default"] = "keyword",
["destructive"] = "keyword",
["disabled"] = "keyword",
["inverted"] = "keyword",
["no-sync-create"] = "keyword",
["suggested"] = "keyword",
["swapped"] = "keyword",
["sync-create"] = "keyword",
["template"] = "keyword",
-- Menus
["menu"] = "keyword",
["submenu"] = "keyword",
["section"] = "keyword",
-- Nested blocks
["responses"] = "keyword2",
["items"] = "keyword2",
["mime-types"] = "keyword2",
["patterns"] = "keyword2",
["suffixes"] = "keyword2",
["marks"] = "keyword2",
["widgets"] = "keyword2",
["strings"] = "keyword2",
["styles"] = "keyword2",
["accessibility"] = "keyword2",
["setters"] = "keyword2",
["layout"] = "keyword2",
["item"] = "keyword2",
["condition"] = "keyword2",
["mark"] = "keyword2",
-- Translated strings
["_"] = "operator",
["C_"] = "operator",
}
}
+23
View File
@@ -0,0 +1,23 @@
-- Author: Rohan Vashisht: https://github.com/RohanVashisht1234/
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "Brainfuck", -- tested ok
files = {
"%.bf$", -- tested ok
},
patterns = {
{ pattern = '%[', type = 'operator' }, -- tested ok
{ pattern = '%]', type = 'operator' }, -- tested ok
{ pattern = '%-', type = 'keyword' }, -- tested ok
{ pattern = '<', type = 'keyword2' }, -- tested ok
{ pattern = '>', type = 'keyword2' }, -- tested ok
{ pattern = '+', type = 'string' }, -- tested ok
{ pattern = ',', type = 'literal' }, -- tested ok
{ pattern = '%.', type = 'string' }, -- tested ok
{ pattern = '[^%-%.<>%+,%[%]]+', type = 'comment' }, -- tested ok
},
symbols = {},
}
+76
View File
@@ -0,0 +1,76 @@
-- Author: Rohan Vashisht: https://github.com/rohanvashisht1234/
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "Buzz", -- tested ok
files = { "%.buzz$" }, -- tested ok
comment = "|", -- tested ok
patterns = {
{ pattern = { '"', '"', '\\' }, type = "string" }, -- tested ok
{ pattern = "|.*", type = "comment" }, -- tested ok
{ pattern = "[!%-/*?:=><]", type = "operator" }, -- tested ok
{ pattern = "[%a_][%w_]*%f[(]", type = "function" }, -- tested ok
{ pattern = "const()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok
{ pattern = "object()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok
{ pattern = "var()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok
{ pattern = "-?%d+[%d%.eE_]*", type = "number" }, -- tested ok
{ pattern = "-?%.?%d+", type = "number" }, -- tested ok
{ pattern = "[%a_][%w_]*", type = "normal" }, -- tested ok
},
symbols = {
["bool"] = "keyword", -- tested ok
["ud"] = "keyword", -- tested ok
["float"] = "keyword", -- tested ok
["zdef"] = "keyword", -- tested ok
["resolve"] = "keyword", -- tested ok
["yield"] = "keyword", -- tested ok
["resume"] = "keyword", -- tested ok
["export"] = "keyword", -- tested ok
["void"] = "keyword", -- tested ok
["protocol"] = "keyword", -- tested ok
["do"] = "keyword", -- tested ok
["enum"] = "keyword", -- tested ok
["test"] = "keyword", -- tested ok
["extern"] = "keyword", -- tested ok
["object"] = "keyword", -- tested ok
["foreach"] = "keyword", -- tested ok
["is"] = "keyword", -- tested ok
["return"] = "keyword", -- tested ok
["continue"] = "keyword", -- tested ok
["for"] = "keyword", -- tested ok
["lambda"] = "keyword", -- tested ok
["try"] = "keyword", -- tested ok
["fun"] = "keyword", -- tested ok
["type"] = "keyword", -- tested ok
["while"] = "keyword", -- tested ok
["and"] = "keyword", -- tested ok
["global"] = "keyword", -- tested ok
["not"] = "keyword2", -- tested ok
["any"] = "keyword", -- tested ok
["as"] = "keyword", -- tested ok
["if"] = "keyword", -- tested ok
["or"] = "keyword", -- tested ok
["else"] = "keyword", -- tested ok
["match"] = "keyword", -- tested ok
["pat"] = "keyword", -- tested ok
["import"] = "keyword", -- tested ok
["str"] = "keyword", -- tested ok
["var"] = "keyword", -- tested ok
["catch"] = "keyword", -- tested ok
["typeof"] = "keyword", -- tested ok
["int"] = "keyword", -- tested ok
["const"] = "keyword", -- tested ok
["namespace"] = "keyword", -- tested ok
["this"] = "keyword2", -- tested ok
["null"] = "literal", -- tested ok
["true"] = "literal", -- tested ok
["false"] = "literal", -- tested ok
["in"] = "literal", -- tested ok
["static"] = "keyword2", -- tested ok
["std"] = "keyword2", -- tested ok
["io"] = "keyword2", -- tested ok
}
}
+80
View File
@@ -0,0 +1,80 @@
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "cel7",
files = "%.c7$",
comment = ";",
patterns = {
{ pattern = ";.*", type = "comment" },
{ pattern = { '"', '"', '\\' }, type = "string" },
{ pattern = "0x4000", type = "literal" },
{ pattern = "0x4040", type = "literal" },
{ pattern = "0x52a0", type = "literal" },
{ pattern = "0x[%da-fA-F]+", type = "number" },
{ pattern = "-?%d+[%d%.]*", type = "number" },
{ pattern = "-?%.?%d+", type = "number" },
{ pattern = "'", type = "symbol" },
{ pattern = "=", type = "symbol" },
{ pattern = "<=?", type = "symbol" },
{ pattern = "[%+-%*/]", type = "symbol" },
{ pattern = "//", type = "keyword2" },
{ pattern = "%%", type = "keyword2" },
{ pattern = "%f[^(][^()'%s\"]+", type = "function" },
{ pattern = "[^()'%s\"]+", type = "symbol" },
},
symbols = {
["let"] = "keyword",
["="] = "operator",
["if"] = "keyword",
["fn"] = "keyword",
["mac"] = "keyword",
["while"] = "keyword",
["quote"] = "keyword",
["'"] = "keyword",
["and"] = "keyword",
["or"] = "keyword",
["do"] = "keyword",
["cons"] = "keyword",
["car"] = "keyword",
["cdr"] = "keyword",
["setcar"] = "keyword",
["setcdr"] = "keyword",
["list"] = "keyword",
["not"] = "keyword",
["is"] = "keyword",
["atom"] = "keyword",
["print"] = "keyword",
["<"] = "operator",
["<="] = "operator",
["="] = "operator",
["+"] = "operator",
["-"] = "operator",
["*"] = "operator",
["/"] = "operator",
["nil"] = "literal",
["t"] = "literal",
-- reserved variables (config)
["title"] = "keyword2",
["width"] = "keyword2",
["height"] = "keyword2",
["debug"] = "keyword2",
-- callbacks
["init"] = "keyword2",
["step"] = "keyword2",
["keydown"] = "keyword2",
["keyup"] = "keyword2",
-- built-in functions
["quit"] = "keyword2",
["rand"] = "keyword2",
["poke"] = "keyword2",
["peek"] = "keyword2",
["color"] = "keyword2",
["put"] = "keyword2",
["get"] = "keyword2",
["fill"] = "keyword2",
}
}
+104
View File
@@ -0,0 +1,104 @@
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
files = { PATHSEP .. "Caddyfile$" },
comment = "#",
patterns = {
{ pattern = "#.*", type = "comment" },
{ pattern = { '"', '"', '\\' }, type = "string" },
-- Matcher definition
{ pattern = "@[%w_]+", type = "operator" },
-- Snippet
{ pattern = "%(%g+%)", type = "operator" },
-- Properties
{ pattern = "^[%a_][%w_]*()%s+%f[%g]",
type = { "function", "normal" }
},
{ pattern = "^[%a_][%w_]*()%s+$",
type = { "function", "normal" }
},
{ pattern = "^%s*()[%a_][%w_]*()%s+$",
type = { "normal", "function", "normal" }
},
{ pattern = "^%s*()[%a_][%w_]*()%s+%f[%g]",
type = { "normal", "function", "normal" }
},
-- Environment variables
{ pattern = "{()%$[%w_]+():()[%w_]+()}",
type = { "operator", "keyword2", "operator", "keyword2", "operator" }
},
{ pattern = "{()%$[%w_]+()}",
type = { "operator", "keyword2", "operator" }
},
-- Place holder
{ pattern = "{%g-}", type = "keyword2" },
-- Operators
{ pattern = "[+%-,:]", type = "operator" },
-- IP Address
{ pattern = "%d+%.%d+%.%d+%.%d+", type = "literal" },
-- Path /path/subpath
{ pattern = "/[%w%./]+", type = "literal" },
-- Wildcard domain *.levels
{ pattern = "%*()[%w.]+",
type = { "operator", "literal" }
},
-- Match Operator
{ pattern = "%*+", type = "operator" },
-- Domain leve1.level2
{ pattern = "https?://[%w%./%*]+", type = "literal" },
-- Domain leve1.level2
{ pattern = "%w+%.[%w%.]+", type = "literal" },
-- Number
{ pattern = "%d+[mhskbi]*", type = "number" },
-- Everything else for symbols to work
{ pattern = "[%a_][%w_]*", type = "symbol" },
},
symbols = {
["true"] = "literal",
["false"] = "literal",
["localhost"] = "literal",
-- built-in directives
["abort"] = "keyword",
["acme_server"] = "keyword",
["basicauth"] = "keyword",
["bind"] = "keyword",
["encode"] = "keyword",
["error"] = "keyword",
["file_server"] = "keyword",
["forward_auth"] = "keyword",
["handle"] = "keyword",
["handle_errors"] = "keyword",
["handle_path"] = "keyword",
["header"] = "keyword",
["import"] = "keyword",
["log"] = "keyword",
["method"] = "keyword",
["map"] = "keyword",
["metrics"] = "keyword",
["php_fastcgi"] = "keyword",
["push"] = "keyword",
["redir"] = "keyword",
["request_body"] = "keyword",
["request_header"] = "keyword",
["respond"] = "keyword",
["reverse_proxy"] = "keyword",
["rewrite"] = "keyword",
["root"] = "keyword",
["route"] = "keyword",
["templates"] = "keyword",
["tls"] = "keyword",
["tracing"] = "keyword",
["try_files"] = "keyword",
["uri"] = "keyword",
["vars"] = "keyword",
-- Module directives
["cgi"] = "keyword",
["ssh"] = "keyword",
["exec"] = "keyword",
["supervisor"] = "keyword",
["layer4"] = "keyword",
},
}
+83
View File
@@ -0,0 +1,83 @@
-- Author: Rohan Vashisht: https://github.com/rohanvashisht1234/
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "Carbon", -- tested ok
files = {
"%.carbon$" -- tested ok
},
comment = "//", -- tested ok
patterns = {
{ pattern = { '"', '"', '\\' }, type = "string" }, -- tested ok
{ pattern = { '"""', '"""', '\\' }, type = "string" }, -- tested ok
{ pattern = { "'''", "'''", '\\' }, type = "string" }, -- tested ok
{ pattern = "//.*", type = "comment" }, -- tested ok
{ pattern = "[!%-/*?:=><+]", type = "operator" }, -- tested ok
{ pattern = "[%a_][%w_]*%f[(]", type = "function" }, -- tested ok
{ pattern = "packages()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok
{ pattern = "let()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok
{ pattern = "import()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok
{ pattern = "impl()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok
{ pattern = "class()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok
{ pattern = "var()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok
{ pattern = "package()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok
{ pattern = "-?%d+[%d%.eE_]*", type = "number" }, -- tested ok
{ pattern = "-?%.?%d+", type = "number" }, -- tested ok
{ pattern = "[%a_][%w_]*", type = "normal" }, -- tested ok
},
symbols = {
["package"] = "keyword", -- tested ok
["import"] = "keyword", -- tested ok
["fn"] = "keyword", -- tested ok
["var"] = "keyword", -- tested ok
["for"] = "keyword", -- tested ok
["return"] = "keyword", -- tested ok
["class"] = "keyword", -- tested ok
["api"] = "keyword", -- tested ok
["i8"] = "keyword", -- tested ok
["i16"] = "keyword", -- tested ok
["i32"] = "keyword", -- tested ok
["i64"] = "keyword", -- tested ok
["i128"] = "keyword", -- tested ok
["i256"] = "keyword", -- tested ok
["u8"] = "keyword", -- tested ok
["u16"] = "keyword", -- tested ok
["u32"] = "keyword", -- tested ok
["u64"] = "keyword", -- tested ok
["u128"] = "keyword", -- tested ok
["u256"] = "keyword", -- tested ok
["f8"] = "keyword", -- tested ok
["f16"] = "keyword", -- tested ok
["f32"] = "keyword", -- tested ok
["f64"] = "keyword", -- tested ok
["f128"] = "keyword", -- tested ok
["if"] = "keyword", -- tested ok
["else"] = "keyword", -- tested ok
["auto"] = "keyword", -- tested ok
["let"] = "keyword", -- tested ok
["File"] = "keyword", -- tested ok
["while"] = "keyword", -- tested ok
["match"] = "keyword", -- tested ok
["case"] = "keyword", -- tested ok
["default"] = "keyword", -- tested ok
["returned"] = "keyword", -- tested ok
["base"] = "keyword", -- tested ok
["bool"] = "keyword", -- tested ok
["virtual"] = "keyword", -- tested ok
["abstract"] = "keyword", -- tested ok
["String"] = "keyword", -- tested ok
["impl"] = "keyword2", -- tested ok
["extend"] = "keyword", -- tested ok
["partial"] = "keyword2", -- tested ok
["Self"] = "keyword", -- tested ok
["Int"] = "keyword", -- tested ok
["UInt"] = "keyword", -- tested ok
["Base"] = "keyword", -- tested ok
["template"] = "keyword2", -- tested ok
["true"] = "keyword2", -- tested ok
["false"] = "keyword2", -- tested ok
}
}
+56
View File
@@ -0,0 +1,56 @@
-- Author: Rohan Vashisht: https://github.com/RohanVashisht1234/
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "Clojure",
comment = ";;",
files = {
"%.clj$",
"%.cljs$",
"%.clc$",
"%.edn$",
},
patterns = {
{ pattern = ';;.*', type = 'comment' }, -- Single-line Comment
{ pattern = ';.*', type = 'comment' }, -- Single-line Comment
{ pattern = { '#"', '"', '\\' }, type = 'string' }, -- Multiline String
{ pattern = { '"', '"', '\\' }, type = 'string' }, -- Multiline String
{ pattern = { '"""', '"""', '\\' }, type = 'string' }, -- Multiline String
{ pattern = ':[%a_][%w_/%-]*', type = 'keyword2' }, -- word after ':' a.k.a (Var metadata)
{ pattern = '[%a_][%w_]*()%.()[%a_][%w_/%-]*', type = { 'keyword', 'operator', 'keyword2' } }, -- Things like something.something
{ pattern = "%(()def()%s+()[%a_][%w_%-]*", type = { "normal", "keyword", "literal", 'literal' } }, -- function definition
{ pattern = "%(()def[%a_][%w_]*()%s+()[%a_][%w_%-]*", type = { "normal", "keyword", "literal", 'literal' } }, -- function definition but with something along with def like: defn, defmacro etc.
{ pattern = '%(()require()%s+()[%a_][%w_]*', type = { 'normal', 'keyword', 'literal', 'literal' } }, -- highlight the word after require keyword
{ pattern = '%(()[%a_][%w_/]*', type = { 'normal', 'literal' } }, -- patterns that are like this: (my_function/subdir_1)
{ pattern = '-?0x%x+', type = 'number' }, -- Hexadecimal
{ pattern = '-?%d+[%d%.eE]*f?', type = 'number' }, -- Floating-point numbers
{ pattern = '-?%.?%d+f?', type = 'number' }, -- Floating-point numbers
{ pattern = '[!%#%$%%&*+./%<=>%?@\\%^|%-~:]', type = 'operator' }, -- Character classes
{ pattern = "[%a_'][%w_']*", type = 'normal' }, -- Normal
},
symbols = {
['def'] = 'keyword', -- tested ok
['defn'] = 'keyword', -- tested ok
['str'] = 'keyword', -- tested ok
['fn'] = 'keyword', -- tested ok
['println'] = 'keyword', -- tested ok
['if'] = 'keyword', -- tested ok
['cond'] = 'keyword', -- tested ok
['vector'] = 'keyword', -- tested ok
['apply'] = 'keyword', -- tested ok
['String'] = 'keyword', -- tested ok
['ns'] = 'keyword', -- tested ok
['try'] = 'keyword', -- tested ok
['let'] = 'keyword', -- tested ok
['get'] = 'keyword', -- tested ok
['catch'] = 'keyword', -- tested ok
['Retention'] = 'keyword', -- tested ok
['Deprecated'] = 'keyword', -- tested ok
['require'] = 'keyword2', -- tested ok
['true'] = 'keyword2', -- tested ok
['false'] = 'keyword2', -- tested ok
['nil'] = 'literal', -- tested ok
['int'] = 'literal', -- tested ok
},
}
+19
View File
@@ -0,0 +1,19 @@
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "CMake",
files = { "%.cmake$", PATHSEP .. "CMakeLists%.txt$" },
comment = "#",
block_comment = { "#[[", "]]" },
patterns = {
{ pattern = { '#%[=*%[', '%]=*%]' }, type = "comment" },
{ pattern = "#.*", type = "comment" },
{ pattern = { '%[=*%[', '%]=*%]' }, type = "string" },
{ pattern = { '"', '"', '\\' }, type = "string" },
{ pattern = "[%a_][%w_]*%f[(]", type = "function" },
{ pattern = "[%a_][%w_]*", type = "normal" },
{ pattern = "%${[%a_][%w_]*%}", type = "operator" },
},
symbols = {},
}
+122
View File
@@ -0,0 +1,122 @@
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "C#",
files = "%.cs$",
comment = "//",
patterns = {
{ pattern = "//.-\n", type = "comment" },
{ pattern = { "/%*", "%*/" }, type = "comment" },
{ pattern = { '"', '"', '\\' }, type = "string" },
{ pattern = { "[%$%@]?\"", '"', '\\' }, type = "string" }, -- string interpolation and verbatim
{ pattern = "'\\x%x?%x?%x?%x'", type = "string" }, -- character hexadecimal escape sequence
{ pattern = "'\\u%x%x%x%x'", type = "string" }, -- character unicode escape sequence
{ pattern = "'\\?.'", type = "string" }, -- character literal
{ pattern = "-?0x%x+", type = "number" },
{ pattern = "-?%d+[%d%.eE]*f?", type = "number" },
{ pattern = "-?%.?%d+f?", type = "number" },
{ pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" },
{ pattern = "%?%?", type = "operator" }, -- ?? null-coalescing
{ pattern = "%?%.", type = "operator" }, -- ?. null-conditional
{ pattern = "[%a_][%w_]*%f[(]", type = "function" },
{ pattern = "[%a_][%w_]*", type = "symbol" },
},
symbols = {
-- keywords and contextual keywords
["abstract"] = "keyword",
["as"] = "keyword",
["add"] = "keyword",
["await"] = "keyword",
["base"] = "keyword",
["break"] = "keyword",
["case"] = "keyword",
["catch"] = "keyword",
["checked"] = "keyword",
["class"] = "keyword",
["record"] = "keyword",
["const"] = "keyword",
["continue"] = "keyword",
["default"] = "keyword",
["delegate"] = "keyword",
["do"] = "keyword",
["else"] = "keyword",
["enum"] = "keyword",
["event"] = "keyword",
["explicit"] = "keyword",
["extern"] = "keyword",
["finally"] = "keyword",
["fixed"] = "keyword",
["for"] = "keyword",
["foreach"] = "keyword",
["get"] = "keyword",
["goto"] = "keyword",
["if"] = "keyword",
["implicit"] = "keyword",
["in"] = "keyword",
["interface"] = "keyword",
["internal"] = "keyword",
["is"] = "keyword",
["lock"] = "keyword",
["namespace"] = "keyword",
["new"] = "keyword",
["operator"] = "keyword",
["out"] = "keyword",
["override"] = "keyword",
["remove"] = "keyword",
["params"] = "keyword",
["partial"] = "keyword",
["private"] = "keyword",
["protected"] = "keyword",
["dynamic"] = "keyword",
["public"] = "keyword",
["readonly"] = "keyword",
["ref"] = "keyword",
["return"] = "keyword",
["sealed"] = "keyword",
["set"] = "keyword",
["sizeof"] = "keyword",
["stackalloc"] = "keyword",
["static"] = "keyword",
["struct"] = "keyword",
["switch"] = "keyword",
["this"] = "keyword",
["throw"] = "keyword",
["try"] = "keyword",
["typeof"] = "keyword",
["unchecked"] = "keyword",
["unsafe"] = "keyword",
["using"] = "keyword",
["var"] = "keyword",
["value"] = "keyword",
["global"] = "keyword",
["virtual"] = "keyword",
["void"] = "keyword",
["volatile"] = "keyword",
["where"] = "keyword",
["when"] = "keyword",
["while"] = "keyword",
["yield"] = "keyword",
-- types
["bool"] = "keyword2",
["byte"] = "keyword2",
["char"] = "keyword2",
["decimal"] = "keyword2",
["double"] = "keyword2",
["float"] = "keyword2",
["int"] = "keyword2",
["long"] = "keyword2",
["object"] = "keyword2",
["sbyte"] = "keyword2",
["short"] = "keyword2",
["string"] = "keyword2",
["uint"] = "keyword2",
["ulong"] = "keyword2",
["ushort"] = "keyword2",
-- literals
["true"] = "literal",
["false"] = "literal",
["null"] = "literal",
},
}
+41
View File
@@ -0,0 +1,41 @@
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "CUE",
files = "%.cue$",
comment = "//",
patterns = {
{ pattern = "//.*", type = "comment" },
{ pattern = { '"', '"', '\\' }, type = "string" },
{ pattern = { "`", "`", '\\' }, type = "string" },
{ pattern = { "'", "'", '\\' }, type = "string" },
{ pattern = "0[oO_][0-7]+i?", type = "number" },
{ pattern = "-?0x[%x_]+i?", type = "number" },
{ pattern = "-?%d+_%di?", type = "number" },
{ pattern = "-?%d+[%d%.eE]*f?i?", type = "number" },
{ pattern = "-?%.?%d+f?i?", type = "number" },
{ pattern = "[%a_][%w_]*%.", type = "literal" },
{ pattern = "[%a_][%w_]*", type = "symbol" },
{ pattern = "#[%a][%w_]*", type = "keyword2" },
-- operators
{ pattern = "[%+%-=/%*%^%%<>!~|&%?:%.]", type = "operator" },
},
symbols = {
["package"] = "keyword",
["import"] = "keyword",
["let"] = "keyword",
["for"] = "keyword",
["true"] = "literal",
["false"] = "literal",
["string"] = "keyword2",
["bool"] = "keyword2",
["number"] = "keyword2",
["uint32"] = "keyword2",
["int32"] = "keyword2",
["uint16"] = "keyword2",
["int16"] = "keyword2",
["uint8"] = "keyword2",
["float"] = "keyword2",
}
}
+135
View File
@@ -0,0 +1,135 @@
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "D",
files = { "%.d$", "%.di$" },
comment = "//",
patterns = {
{ pattern = "//.-\n", type = "comment" },
{ pattern = { "/%*", "%*/" }, type = "comment" },
{ pattern = { "/%+", "%+/" }, type = "comment" },
{ pattern = { '`', '`', '\\' }, type = "string" },
{ pattern = { '"', '"', '\\' }, type = "string" },
{ pattern = { "'", "'", '\\' }, type = "string" },
{ pattern = "-?0x[%x_]+", type = "number" },
{ pattern = "-?[%d_]+[%d%.eE]*f?", type = "number" },
{ pattern = "-?%.?%d+f?", type = "number" },
{ pattern = "[%+%-=/%*%^%%<>!~|&%$]+", type = "operator" },
{ pattern = "[%a_][%w_]*!?()[%(.]", type = {"function", "normal"} }, -- highlight templates
{ pattern = "@safe", type = "keyword" },
{ pattern = "@trusted", type = "keyword" },
{ pattern = "@nogc", type = "keyword" },
},
symbols = {
["abstract"] = "keyword",
["alias"] = "keyword",
["align"] = "keyword",
["asm"] = "keyword",
["assert"] = "keyword",
["auto"] = "keyword",
["body"] = "keyword",
["bool"] = "keyword2",
["break"] = "keyword",
["byte"] = "keyword2",
["case"] = "keyword",
["cast"] = "keyword",
["catch"] = "keyword",
["cdouble"] = "keyword2",
["cent"] = "keyword2",
["cfloat"] = "keyword2",
["char"] = "keyword2",
["class"] = "keyword",
["const"] = "keyword",
["continue"] = "keyword",
["creal"] = "keyword2",
["dchar"] = "keyword2",
["debug"] = "keyword",
["default"] = "keyword",
["delegate"] = "keyword",
["deprecated"] = "keyword",
["do"] = "keyword",
["double"] = "keyword2",
["else"] = "keyword",
["enum"] = "keyword",
["export"] = "keyword",
["extern"] = "keyword",
["false"] = "literal",
["final"] = "keyword",
["finally"] = "keyword",
["float"] = "keyword2",
["for"] = "keyword",
["foreach"] = "keyword",
["foreach_reverse"] = "keyword",
["function"] = "keyword",
["goto"] = "keyword",
["idouble"] = "keyword2",
["if"] = "keyword",
["ifloat"] = "keyword2",
["immutable"] = "keyword",
["import"] = "keyword",
["in"] = "keyword",
["inout"] = "keyword",
["int"] = "keyword2",
["interface"] = "keyword",
["invariant"] = "keyword",
["ireal"] = "keyword2",
["is"] = "keyword",
["lazy"] = "keyword",
["long"] = "keyword2",
["macro"] = "keyword",
["mixin"] = "keyword",
["module"] = "keyword",
["new"] = "keyword",
["nothrow"] = "keyword",
["null"] = "literal",
["out"] = "keyword",
["override"] = "keyword",
["package"] = "keyword",
["pragma"] = "keyword",
["private"] = "keyword",
["protected"] = "keyword",
["public"] = "keyword",
["pure"] = "keyword",
["real"] = "keyword2",
["ref"] = "keyword",
["return"] = "keyword",
["scope"] = "keyword",
["shared"] = "keyword",
["short"] = "keyword2",
["static"] = "keyword",
["struct"] = "keyword",
["super"] = "keyword",
["switch"] = "keyword",
["synchronized"] = "keyword",
["template"] = "keyword",
["this"] = "keyword",
["throw"] = "keyword",
["true"] = "literal",
["try"] = "keyword",
["typeid"] = "keyword",
["typeof"] = "keyword",
["ubyte"] = "keyword2",
["ucent"] = "keyword2",
["uint"] = "keyword2",
["ulong"] = "keyword2",
["union"] = "keyword",
["unittest"] = "keyword",
["ushort"] = "keyword2",
["version"] = "keyword",
["void"] = "keyword",
["wchar"] = "keyword2",
["while"] = "keyword",
["with"] = "keyword",
["__FILE__"] = "keyword",
["__FILE_FULL_PATH__"] = "keyword",
["__MODULE__"] = "keyword",
["__LINE__"] = "keyword",
["__FUNCTION__"] = "keyword",
["__PRETTY_FUNCTION__"] = "keyword",
["__gshared"] = "keyword",
["__traits"] = "keyword",
["__vector"] = "keyword",
["__parameters"] = "keyword",
},
}
+64
View File
@@ -0,0 +1,64 @@
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "Dart",
files = { "%.dart$" },
comment = "//",
patterns = {
{ pattern = "//.-\n", type = "comment" },
{ pattern = "///.-\n", type = "comment" },
{ pattern = { "/%*", "%*/" }, type = "comment" },
{ pattern = { '"', '"', '\\' }, type = "string" },
{ pattern = { "'", "'", '\\' }, type = "string" },
{ pattern = "-?0x%x+", type = "number" },
{ pattern = "-?%d+[%d%.eE]*f?", type = "number" },
{ pattern = "-?%.?%d+f?", type = "number" },
{ pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" },
{ pattern = "%?%?", type = "operator" },
{ pattern = "%?%.", type = "operator" },
{ pattern = { "[%$%@]?\"", '"', '\\' }, type = "string" },
{ pattern = "'\\x%x?%x?%x?%x'", type = "string" },
{ pattern = "[%a_][%w_]*%f[(]", type = "function" },
{ pattern = "[%a_][%w_]*", type = "symbol" },
},
symbols = {
["await"] = "keyword",
["bool"] = "keyword2",
["break"] = "keyword",
["case"] = "keyword",
["class"] = "keyword",
["const"] = "keyword",
["continue"] = "keyword",
["default"] = "keyword",
["do"] = "keyword",
["double"] = "keyword2",
["dynamic"] = "keyword2",
["else"] = "keyword",
["enum"] = "keyword",
["false"] = "literal",
["final"] = "keyword",
["finally"] = "keyword",
["for"] = "keyword",
["Function"] = "keyword2",
["if"] = "keyword",
["in"] = "keyword",
["int"] = "keyword2",
["List"] = "keyword2",
["Map"] = "keyword2",
["new"] = "keyword",
["null"] = "literal",
["part of"] = "keyword",
["print"] = "keyword",
["return"] = "keyword",
["static"] = "keyword",
["String"] = "keyword2",
["switch"] = "keyword",
["then"] = "keyword",
["this"] = "keyword2",
["true"] = "literal",
["void"] = "keyword",
["while"] = "keyword",
},
}
+70
View File
@@ -0,0 +1,70 @@
-- mod-version:3
local syntax = require "core.syntax"
local style = require "core.style"
local common = require "core.common"
-- we need these symbol types to have uniform colors
style.syntax["diff_add"] = { common.color "#72b886" }
style.syntax["diff_del"] = { common.color "#F36161" }
syntax.add {
name = "Diff",
files = { "%.diff$", "%.patch$", "%.rej$" },
headers = "^diff %-",
patterns = {
-- Method the patch was generated with and source/target files
{ regex = "^diff .+", type = "function" },
-- Seen for changing the file permissions
{ regex = "^new .+", type = "comment" },
-- Usually holds starting and ending commit
{ regex = "^index .+", type = "comment" },
-- Position to patch
{
pattern = "@@.-@@ ().+", --with heading
type = { "number", "string" }
},
{
regex = "^@@ [\\d,\\-\\+ ]+ @@\n", --wihtout heading
type = "number"
},
-- Other position to patch formats
{
regex = "^-{3} [\\d]+,[\\d]+ \\-{4}\n",
type = "number"
},
{
regex = "^\\*{3} [\\d]+,[\\d]+ \\*{4}\n",
type = "number"
},
-- Source and target file
{ regex = "^-{3} .+", type = "keyword" },
{ regex = "^\\+{3} .+", type = "keyword" },
-- Rarely used source file indicator
{ regex = "^\\*{3} .+", type = "keyword" },
-- git patches seem to add 3 dashes to separate message from changed files
{ regex = "^-{3}\n", type = "normal" },
-- Addition and deletion of lines
{ regex = "^-.*", type = "diff_del" },
{ regex = "^\\+.*", type = "diff_add" },
{ regex = "^<.*", type = "diff_del" },
{ regex = "^>.*", type = "diff_add" },
-- Change between two lines
{ regex = "^!.*", type = "number" },
-- Stuff usually found on a authored patch heading
{
pattern = "From ()[a-fA-F0-9]+ ().+",
type = { "keyword", "number", "string" }
},
{ regex = "^[a-zA-Z\\-]+: ", type = "keyword" },
-- Diff stats
{ regex = "^ [\\d]+ files? changed", type = "function" },
{ regex = "[\\d]+ insertions?\\(\\+\\)", type = "diff_add" },
{ regex = "[\\d]+ deletions?\\(\\-\\)", type = "diff_del" },
-- Match e-mail
{
pattern = ".*()<[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+%.[a-zA-Z0-9-.]+>",
type = {"string", "keyword2"}
},
},
symbols = {}
}
+645
View File
@@ -0,0 +1,645 @@
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "FreeFEM++",
files = {
"%.edp$", "%.ffp$"
},
comment = "//",
block_comment = { "/*", "*/" },
patterns = {
{ pattern = "//.*", type = "comment" },
{ pattern = { "/%*", "%*/" }, type = "comment" },
{ pattern = { '"', '"', '\\' }, type = "string" },
{ pattern = "0x%x+[%x']*", type = "number" },
{ pattern = "%d+[%d%.'eE]*f?", type = "number" },
{ pattern = "%.?%d+[%d']*f?", type = "number" },
{ pattern = "[%+%-=/%*%^%%<>!~|:&]", type = "operator" },
{ pattern = "##", type = "operator" },
{ pattern = "struct%s()[%a_][%w_]*", type = { "keyword", "keyword2" } },
{ pattern = "class%s()[%a_][%w_]*", type = { "keyword", "keyword2" } },
{ pattern = "union%s()[%a_][%w_]*", type = { "keyword", "keyword2" } },
{ pattern = "namespace%s()[%a_][%w_]*", type = { "keyword", "keyword2" } },
-- static declarations
{
pattern = "static()%s+()inline",
type = { "keyword", "normal", "keyword" }
},
{
pattern = "static()%s+()const",
type = { "keyword", "normal", "keyword" }
},
{
pattern = "static()%s+()[%a_][%w_]*",
type = { "keyword", "normal", "literal" }
},
-- match method type declarations
{
pattern = "[%a_][%w_]*()%s*()%**()%s*()[%a_][%w_]*()%s*()::",
type = {
"literal", "normal", "operator", "normal",
"literal", "normal", "operator"
}
},
-- match function type declarations
{
pattern = "[%a_][%w_]*()%*+()%s+()[%a_][%w_]*%f[%(]",
type = { "literal", "operator", "normal", "function" }
},
{
pattern = "[%a_][%w_]*()%s+()%*+()[%a_][%w_]*%f[%(]",
type = { "literal", "normal", "operator", "function" }
},
{
pattern = "[%a_][%w_]*()%s+()[%a_][%w_]*%f[%(]",
type = { "literal", "normal", "function" }
},
-- match variable type declarations
{
pattern = "[%a_][%w_]*()%*+()%s+()[%a_][%w_]*",
type = { "literal", "operator", "normal", "normal" }
},
{
pattern = "[%a_][%w_]*()%s+()%*+()[%a_][%w_]*",
type = { "literal", "normal", "operator", "normal" }
},
{
pattern = "[%a_][%w_]*()%s+()[%a_][%w_]*()%s*()[;,%[%)]",
type = { "literal", "normal", "normal", "normal", "normal" }
},
{
pattern = "[%a_][%w_]*()%s+()[%a_][%w_]*()%s*()=",
type = { "literal", "normal", "normal", "normal", "operator" }
},
{
pattern = "[%a_][%w_]*()&()%s+()[%a_][%w_]*",
type = { "literal", "operator", "normal", "normal" }
},
{
pattern = "[%a_][%w_]*()%s+()&()[%a_][%w_]*",
type = { "literal", "normal", "operator", "normal" }
},
-- Match scope operator element access
{
pattern = "[%a_][%w_]*()%s*()::",
type = { "literal", "normal", "operator" }
},
-- Uppercase constants of at least 2 chars in len
{
pattern = "_?%u[%u_][%u%d_]*%f[%s%+%*%-%.%)%]}%?%^%%=/<>~|&;:,!]",
type = "number"
},
-- Magic constants
{ pattern = "__[%u%l]+__", type = "number" },
-- all other functions
{ pattern = "[%a_][%w_]*%f[(]", type = "function" },
-- Macros
{
pattern = "^%s*#%s*define%s+()[%a_][%a%d_]*",
type = { "keyword", "symbol" }
},
{
pattern = "#%s*include%s+()<.->",
type = { "keyword", "string" }
},
{ pattern = "%f[#]#%s*[%a_][%w_]*", type = "keyword" },
-- Everything else to make the tokenizer work properly
{ pattern = "[%a_][%w_]*", type = "symbol" },
},
symbols = {
["alignof"] = "keyword",
["alignas"] = "keyword",
["and"] = "keyword",
["and_eq"] = "keyword",
["not"] = "keyword",
["not_eq"] = "keyword",
["or"] = "keyword",
["or_eq"] = "keyword",
["xor"] = "keyword",
["xor_eq"] = "keyword",
["private"] = "keyword",
["protected"] = "keyword",
["public"] = "keyword",
["register"] = "keyword",
["nullptr"] = "keyword",
["operator"] = "keyword",
["asm"] = "keyword",
["bitand"] = "keyword",
["bitor"] = "keyword",
["catch"] = "keyword",
["throw"] = "keyword",
["try"] = "keyword",
["class"] = "keyword",
["compl"] = "keyword",
["explicit"] = "keyword",
["export"] = "keyword",
["concept"] = "keyword",
["consteval"] = "keyword",
["constexpr"] = "keyword",
["constinit"] = "keyword",
["const_cast"] = "keyword",
["dynamic_cast"] = "keyword",
["reinterpret_cast"] = "keyword",
["static_cast"] = "keyword",
["static_assert"] = "keyword",
["template"] = "keyword",
["this"] = "keyword",
["thread_local"] = "keyword",
["requires"] = "keyword",
["co_wait"] = "keyword",
["co_return"] = "keyword",
["co_yield"] = "keyword",
["decltype"] = "keyword",
["delete"] = "keyword",
["friend"] = "keyword",
["typeid"] = "keyword",
["typename"] = "keyword",
["mutable"] = "keyword",
["override"] = "keyword",
["virtual"] = "keyword",
["using"] = "keyword",
["namespace"] = "keyword",
["new"] = "keyword",
["noexcept"] = "keyword",
["if"] = "keyword",
["then"] = "keyword",
["else"] = "keyword",
["elseif"] = "keyword",
["do"] = "keyword",
["while"] = "keyword",
["for"] = "keyword",
["break"] = "keyword",
["continue"] = "keyword",
["return"] = "keyword",
["goto"] = "keyword",
["struct"] = "keyword",
["union"] = "keyword",
["typedef"] = "keyword",
["enum"] = "keyword",
["extern"] = "keyword",
["static"] = "keyword",
["volatile"] = "keyword",
["const"] = "keyword",
["inline"] = "keyword",
["case"] = "keyword",
["default"] = "keyword",
["auto"] = "keyword",
["void"] = "keyword2",
["int"] = "keyword2",
["short"] = "keyword2",
["long"] = "keyword2",
["float"] = "keyword2",
["double"] = "keyword2",
["char"] = "keyword2",
["unsigned"] = "keyword2",
["bool"] = "keyword2",
["true"] = "literal",
["false"] = "literal",
["NULL"] = "literal",
["wchar_t"] = "keyword2",
["char8_t"] = "keyword2",
["char16_t"] = "keyword2",
["char32_t"] = "keyword2",
["#include"] = "keyword",
["#if"] = "keyword",
["#ifdef"] = "keyword",
["#ifndef"] = "keyword",
["#elif"] = "keyword",
["#else"] = "keyword",
["#elseif"] = "keyword",
["#endif"] = "keyword",
["#define"] = "keyword",
["#warning"] = "keyword",
["#error"] = "keyword",
["#pragma"] = "keyword",
["end"] = "keyword",
["element"] = "keyword",
["label"] = "keyword",
["measure"] = "keyword",
["mesure"] = "keyword",
["Element"] = "keyword",
["whoinElement"] = "keyword",
["region"] = "keyword",
["R3"] = "keyword",
["vertex"] = "keyword",
["im"] = "keyword",
["l1"] = "keyword",
["l2"] = "keyword",
["linfty"] = "keyword",
["max"] = "keyword",
["min"] = "keyword",
["re"] = "keyword",
["sum"] = "keyword",
["quantile"] = "keyword",
["sort"] = "keyword",
["x"] = "keyword",
["y"] = "keyword",
["z"] = "keyword",
["length"] = "keyword",
["area"] = "keyword",
["coef"] = "keyword",
["diag"] = "keyword",
["m"] = "keyword",
["n"] = "keyword",
["nbcoef"] = "keyword",
["nnz"] = "keyword",
["resize"] = "keyword",
["size"] = "keyword",
["imax"] = "keyword",
["imin"] = "keyword",
["N"] = "keyword",
["P"] = "keyword",
["nuTriangle"] = "keyword",
["ndof"] = "keyword",
["ndofK"] = "keyword",
["nt"] = "keyword",
["be"] = "keyword",
["hmax"] = "keyword",
["hmin"] = "keyword",
["nbe"] = "keyword",
["nv"] = "keyword",
["bordermesure"] = "keyword",
["eof"] = "keyword",
["good"] = "keyword",
["fixed"] = "keyword",
["flush"] = "keyword",
["noshowbase"] = "keyword",
["noshowpos"] = "keyword",
["precision"] = "keyword",
["scientific"] = "keyword",
["seekp"] = "keyword",
["showbase"] = "keyword",
["showpos"] = "keyword",
["tellp"] = "keyword",
["ARGV"] = "keyword",
["CG"] = "keyword",
["CPUTime"] = "keyword",
["Cholesky"] = "keyword",
["Cofactor"] = "keyword",
["Crout"] = "keyword",
["Edge03d"] = "keyword",
["GMRES"] = "keyword",
["HaveUMFPACK"] = "keyword",
["LU"] = "keyword",
["NaN"] = "keyword",
["P0"] = "keyword",
["P03d"] = "keyword",
["P0VF"] = "keyword",
["P0edge"] = "keyword",
["P1"] = "keyword",
["P13d"] = "keyword",
["P1b"] = "keyword",
["P1b3d"] = "keyword",
["P1dc"] = "keyword",
["P1nc"] = "keyword",
["P2"] = "keyword",
["P23d"] = "keyword",
["P2b"] = "keyword",
["P2dc"] = "keyword",
["P2h"] = "keyword",
["RT0"] = "keyword",
["RT03d"] = "keyword",
["RT0Ortho"] = "keyword",
["RTmodif"] = "keyword",
["UMFPACK"] = "keyword",
["append"] = "keyword",
["binary"] = "keyword",
["hTriangle"] = "keyword",
["havesparsesolver"] = "keyword",
["inside"] = "keyword",
["lenEdge"] = "keyword",
["nTonEdge"] = "keyword",
["nuEdge"] = "keyword",
["pi"] = "keyword",
["qf1pE"] = "keyword",
["qf1pElump"] = "keyword",
["qf1pT"] = "keyword",
["qf1pTlump"] = "keyword",
["qf2pE"] = "keyword",
["qf2pT"] = "keyword",
["qf2pT4P1"] = "keyword",
["qf3pE"] = "keyword",
["qf4pE"] = "keyword",
["qf5pE"] = "keyword",
["qf5pT"] = "keyword",
["qf7pT"] = "keyword",
["qf9pT"] = "keyword",
["qfV1"] = "keyword",
["qfV1lump"] = "keyword",
["qfV2"] = "keyword",
["qfV5"] = "keyword",
["searchMethod"] = "keyword",
["sparsesolver"] = "keyword",
["sparsesolverSym"] = "keyword",
["storagetotal"] = "keyword",
["storageused"] = "keyword",
["verbosity"] = "keyword",
["version"] = "keyword",
["volume"] = "keyword",
["volumelevelset"] = "keyword",
["wait"] = "keyword",
["ShowAlloc"] = "keyword",
["Newton"] = "keyword",
["NoGraphicWindow"] = "keyword",
["NoUseOfWait"] = "keyword",
["SameMesh"] = "keyword",
["Unique"] = "keyword",
["arealevelset"] = "keyword",
["average"] = "keyword",
["chtmpdir"] = "keyword",
["time"] = "keyword",
["fill"] = "keyword",
["value"] = "keyword",
["nbiso"] = "keyword",
["coeff"] = "keyword",
["dataname"] = "keyword",
["order"] = "keyword",
["mpirank"] = "keyword",
["mpiCommWorld"] = "keyword",
["mpiGroup"] = "keyword",
["mpiRequest"] = "keyword",
["sparams"] = "keyword",
["mpisize"] = "keyword",
["mpiUndefined"] = "keyword",
["mpiAnySource"] = "keyword",
["communicator"] = "keyword",
["worker"] = "keyword",
["dim"] = "keyword",
["cmm"] = "keyword",
["solver"] = "keyword",
["aniso"] = "keyword",
["nbvx"] = "keyword",
["abserror"] = "keyword",
["anisomax"] = "keyword",
["cutoff"] = "keyword",
["err"] = "keyword",
["errg"] = "keyword",
["inquire"] = "keyword",
["IsMetric"] = "keyword",
["iso"] = "keyword",
["keepbackvertices"] = "keyword",
["maxsubdiv"] = "keyword",
["metric"] = "keyword",
["nbjacoby"] = "keyword",
["nbsmooth"] = "keyword",
["nomeshgeneration"] = "keyword",
["omega"] = "keyword",
["periodic"] = "keyword",
["powerin"] = "keyword",
["ratio"] = "keyword",
["rescaling"] = "keyword",
["splitin2"] = "keyword",
["splitpbedge"] = "keyword",
["thetamax"] = "keyword",
["uniform"] = "keyword",
["fixedborder"] = "keyword",
["flags"] = "keyword",
["ivalue"] = "keyword",
["maxit"] = "keyword",
["mode"] = "keyword",
["ncv"] = "keyword",
["nev"] = "keyword",
["rawvector"] = "keyword",
["sigma"] = "keyword",
["sym"] = "keyword",
["tol"] = "keyword",
["vector"] = "keyword",
["which"] = "keyword",
["op"] = "keyword",
["t"] = "keyword",
["eps"] = "keyword",
["nbiter"] = "keyword",
["precon"] = "keyword",
["veps"] = "keyword",
["tgv"] = "keyword",
["tolpivot"] = "keyword",
["meditff"] = "keyword",
["save"] = "keyword",
["orientation"] = "keyword",
["ptmerge"] = "keyword",
["transfo"] = "keyword",
["optimize"] = "keyword",
["aspectratio"] = "keyword",
["bb"] = "keyword",
["boundary"] = "keyword",
["bw"] = "keyword",
["cut"] = "keyword",
["grey"] = "keyword",
["hsv"] = "keyword",
["nbarrow"] = "keyword",
["ps"] = "keyword",
["varrow"] = "keyword",
["viso"] = "keyword",
["init"] = "keyword",
["strategy"] = "keyword",
["tolpivotsym"] = "keyword",
["facetcl"] = "keyword",
["holelist"] = "keyword",
["nboffacetcl"] = "keyword",
["nbofregions"] = "keyword",
["regionlist"] = "keyword",
["switch"] = "keyword",
["refface"] = "keyword",
["split"] = "keyword",
["zbound"] = "keyword",
["labeldown"] = "keyword",
["labelmid"] = "keyword",
["labelup"] = "keyword",
["opt"] = "keyword",
["mpiMAX"] = "keyword",
["mpiMIN"] = "keyword",
["mpiSUM"] = "keyword",
["mpiPROD"] = "keyword",
["mpiLAND"] = "keyword",
["mpiLOR"] = "keyword",
["mpiLXOR"] = "keyword",
["mpiBAND"] = "keyword",
["mpiBXOR"] = "keyword",
["border"] = "keyword2",
["Cmapmatrix"] = "keyword2",
["Cmatrix"] = "keyword2",
["complex"] = "keyword2",
["fespace"] = "keyword2",
["func"] = "keyword2",
["ifstream"] = "keyword2",
["mapmatrix"] = "keyword2",
["matrix"] = "keyword2",
["mesh"] = "keyword2",
["mesh3"] = "keyword2",
["ofstream"] = "keyword2",
["problem"] = "keyword2",
["real"] = "keyword2",
["solve"] = "keyword2",
["string"] = "keyword2",
["varf"] = "keyword2",
["macro"] = "keyword2",
["dmatrix"] = "keyword2",
["adj"] = "function",
["find"] = "function",
["rfind"] = "function",
["seekg"] = "function",
["tellg"] = "function",
["AddLayers"] = "function",
["AffineCG"] = "function",
["AffineGMRES"] = "function",
["BFGS"] = "function",
["EigenValue"] = "function",
["LinearCG"] = "function",
["LinearGMRES"] = "function",
["NLCG"] = "function",
["abs"] = "function",
["acos"] = "function",
["acosh"] = "function",
["adaptmesh"] = "function",
["arg"] = "function",
["asin"] = "function",
["asinh"] = "function",
["assert"] = "function",
["atan"] = "function",
["atan2"] = "function",
["atanh"] = "function",
["atof"] = "function",
["atoi"] = "function",
["boundingbox"] = "function",
["buildmesh"] = "function",
["buildmeshborder"] = "function",
["ceil"] = "function",
["change"] = "function",
["checkmovemesh"] = "function",
["clock"] = "function",
["complexEigenValue"] = "function",
["conj"] = "function",
["convect"] = "function",
["cos"] = "function",
["cosh"] = "function",
["defaultoUMFPACK"] = "function",
["defaultsolver"] = "function",
["defaulttoCG"] = "function",
["defaulttoGMRES"] = "function",
["defaulttoUMFPACK"] = "function",
["det"] = "function",
["dumptable"] = "function",
["dx"] = "function",
["dxx"] = "function",
["dxy"] = "function",
["dxz"] = "function",
["dy"] = "function",
["dyx"] = "function",
["dyy"] = "function",
["dyz"] = "function",
["dz"] = "function",
["dzx"] = "function",
["dzy"] = "function",
["dzz"] = "function",
["emptymesh"] = "function",
["erf"] = "function",
["erfc"] = "function",
["exec"] = "function",
["exit"] = "function",
["exp"] = "function",
["floor"] = "function",
["getline"] = "function",
["hypot"] = "function",
["imag"] = "function",
["int1d"] = "function",
["int2d"] = "function",
["int3d"] = "function",
["intallVFedges"] = "function",
["intalledges"] = "function",
["intallfaces"] = "function",
["interplotematrix"] = "function",
["interpolate"] = "function",
["isInf"] = "function",
["isNaN"] = "function",
["isNormal"] = "function",
["j0"] = "function",
["j1"] = "function",
["jn"] = "function",
["jump"] = "function",
["lgamma"] = "function",
["log"] = "function",
["log10"] = "function",
["lrint"] = "function",
["lround"] = "function",
["ltime"] = "function",
["mean"] = "function",
["movemesh"] = "function",
["newconvect"] = "function",
["norm"] = "function",
["on"] = "function",
["otherside"] = "function",
["plot"] = "function",
["polar"] = "function",
["pow"] = "function",
["randinit"] = "function",
["randint31"] = "function",
["randint32"] = "function",
["randreal1"] = "function",
["randreal2"] = "function",
["randreal3"] = "function",
["randres53"] = "function",
["readmesh"] = "function",
["readmesh3"] = "function",
["renumbering"] = "function",
["restrict"] = "function",
["rint"] = "function",
["round"] = "function",
["savemesh"] = "function",
["savesurfacemesh"] = "function",
["set"] = "function",
["setw"] = "function",
["showCPU"] = "function",
["sin"] = "function",
["sinh"] = "function",
["splitmesh"] = "function",
["sqr"] = "function",
["sqrt"] = "function",
["square"] = "function",
["system"] = "function",
["tan"] = "function",
["tanh"] = "function",
["tgamma"] = "function",
["toCarray"] = "function",
["toRarray"] = "function",
["toZarray"] = "function",
["trace"] = "function",
["triangulate"] = "function",
["trunc"] = "function",
["y0"] = "function",
["y1"] = "function",
["yn"] = "function",
["savevtk"] = "function",
["mshmet"] = "function",
["savesol"] = "function",
["gmshload"] = "function",
["gmshload3"] = "function",
["mpiBarrier"] = "function",
["mpiSize"] = "function",
["Irecv"] = "function",
["Isend"] = "function",
["processor"] = "function",
["mpiWaitAny"] = "function",
["mpiWait"] = "function",
["mpiRank"] = "function",
["metis"] = "function",
["metisdual"] = "function",
["broadcast"] = "function",
["scotch"] = "function",
["parmetis"] = "function",
["mpiWtime"] = "function",
["buildlayers"] = "function",
["mmg3d"] = "function",
["processorblock"] = "function",
["mpiWaitAll"] = "function",
["mpiWtick"] = "function",
["Send"] = "function",
["Recv"] = "function",
["mpiAlltoall"] = "function",
["mpiGather"] = "function",
["mpiScatter"] = "function",
["mpiReduce"] = "function",
["mpiAllReduce"] = "function",
["mpiReduceScatter"] = "function",
},
}
+51
View File
@@ -0,0 +1,51 @@
-- mod-version:3
-- Embedded JavaScript templating
-- provides .ejs syntax support (fork of language_html.lua).
local syntax = require "core.syntax"
syntax.add {
name = "EJS",
files = { "%.ejs$" },
block_comment = { "<!--", "-->" },
patterns = {
{
pattern = {
"<%%",
"%%>"
},
syntax = '.js',
type = "function"
},
{
pattern = {
"<%s*[sS][cC][rR][iI][pP][tT]%f[%s>].->",
"<%s*/%s*[sS][cC][rR][iI][pP][tT]%s*>"
},
syntax = ".js",
type = "function"
},
{
pattern = {
"<%s*[sS][tT][yY][lL][eE]%f[%s>].->",
"<%s*/%s*[sS][tT][yY][lL][eE]%s*>"
},
syntax = ".css",
type = "function"
},
{ pattern = { "<!%-%-", "%-%->" }, type = "comment" },
{ pattern = { '%f[^>][^<]', '%f[<]' }, type = "normal" },
{ pattern = { '"', '"', '\\' }, type = "string" },
{ pattern = { "'", "'", '\\' }, type = "string" },
{ pattern = "0x[%da-fA-F]+", type = "number" },
{ pattern = "-?%d+[%d%.]*f?", type = "number" },
{ pattern = "-?%.?%d+f?", type = "number" },
{ pattern = "%f[^<]![%a_][%w_]*", type = "keyword2" },
{ pattern = "%f[^<][%a_][%w_]*", type = "function" },
{ pattern = "%f[^<]/[%a_][%w_]*", type = "function" },
{ pattern = "[%a_][%w_]*", type = "keyword" },
{ pattern = "[/<>=]", type = "operator" },
},
symbols = {},
}
+95
View File
@@ -0,0 +1,95 @@
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "Elixir",
files = { "%.ex$", "%.exs$"},
comment = "#",
patterns = {
{ pattern = "#.*\n", type = "comment" },
{ pattern = { ':"', '"', '\\' }, type = "number" },
{ pattern = { '"""', '"""', '\\' }, type = "string" },
{ pattern = { '"', '"', '\\' }, type = "string" },
{ pattern = { "'", "'", '\\' }, type = "string" },
{ pattern = { '~%a"""', '"""' }, type = "string" },
{ pattern = { '~%a[/"|\'%(%[%{<]', '[/"|\'%)%]%}>]', '\\' }, type = "string"},
{ pattern = "-?0x%x+", type = "number" },
{ pattern = "-?%d+[%d%.eE]*f?", type = "number" },
{ pattern = "-?%.?%d+f?", type = "number" },
{ pattern = ':"?[%a_][%w_]*"?', type = "number" },
{ pattern = "[%a][%w_!?]*%f[(]", type = "function" },
{ pattern = "%u%w+", type = "normal" },
{ pattern = "@[%a_][%w_]*", type = "keyword2" },
{ pattern = "_%a[%w_]*", type = "keyword2" },
{ pattern = "[%+%-=/%*<>!|&]", type = "operator" },
{ pattern = "[%a_][%w_]*", type = "symbol" },
},
symbols = {
["def"] = "keyword",
["defp"] = "keyword",
["defguard"] = "keyword",
["defguardp"] = "keyword",
["defmodule"] = "keyword",
["defprotocol"] = "keyword",
["defimpl"] = "keyword",
["defrecord"] = "keyword",
["defrecordp"] = "keyword",
["defmacro"] = "keyword",
["defmacrop"] = "keyword",
["defdelegate"] = "keyword",
["defoverridable"] = "keyword",
["defexception"] = "keyword",
["defcallback"] = "keyword",
["defstruct"] = "keyword",
["for"] = "keyword",
["case"] = "keyword",
["when"] = "keyword",
["with"] = "keyword",
["cond"] = "keyword",
["if"] = "keyword",
["unless"] = "keyword",
["try"] = "keyword",
["receive"] = "keyword",
["after"] = "keyword",
["raise"] = "keyword",
["rescue"] = "keyword",
["catch"] = "keyword",
["else"] = "keyword",
["quote"] = "keyword",
["unquote"] = "keyword",
["super"] = "keyword",
["unquote_splicing"] = "keyword",
["do"] = "keyword",
["end"] = "keyword",
["fn"] = "keyword",
["import"] = "keyword2",
["alias"] = "keyword2",
["use"] = "keyword2",
["require"] = "keyword2",
["and"] = "operator",
["or"] = "operator",
["true"] = "literal",
["false"] = "literal",
["nil"] = "literal",
},
}
syntax.add {
files = { "%.l?eex$", "%.h?eex$" },
patterns = {
{ pattern = { "<!%-%-", "%-%->" }, type = "comment" },
{ pattern = { '%f[^>][^<]', '%f[<]' }, type = "normal" },
{ pattern = { '<%%=?', '%%>' }, type = "normal" },
{ pattern = { '"', '"', '\\' }, type = "string" },
{ pattern = { "'", "'", '\\' }, type = "string" },
{ pattern = "0x[%da-fA-F]+", type = "number" },
{ pattern = "-?%d+[%d%.]*f?", type = "number" },
{ pattern = "-?%.?%d+f?", type = "number" },
{ pattern = "%f[^<]![%a_][%w_]*", type = "keyword2" },
{ pattern = "%f[^<][%a_][%w_]*", type = "function" },
{ pattern = "%f[^<]/[%a_][%w_]*", type = "function" },
{ pattern = "[%a_][%w_]*", type = "keyword" },
{ pattern = "[/<>=]", type = "operator" },
},
symbols = {},
}
+49
View File
@@ -0,0 +1,49 @@
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "Elm",
files = { "%.elm$" },
comment = "%-%-",
patterns = {
{ pattern = {"%-%-", "\n"}, type = "comment" },
{ pattern = { "{%-", "%-}" }, type = "comment" },
{ pattern = { '"', '"', '\\' }, type = "string" },
{ pattern = { '"""', '"""', '\\' }, type = "string" },
{ pattern = { "'", "'", '\\' }, type = "string" },
{ pattern = "-?0x%x+", type = "number" },
{ pattern = "-?%d+[%d%.eE]*f?", type = "number" },
{ pattern = "-?%.?%d+f?", type = "number" },
{ pattern = "%.%.", type = "operator" },
{ pattern = "[=:|&<>%+%-%*\\/%^%%]", type = "operator" },
{ pattern = "[%a_'][%w_']*", type = "symbol" },
},
symbols = {
["as"] = "keyword",
["case"] = "keyword",
["of"] = "keyword",
["if"] = "keyword",
["then"] = "keyword",
["else"] = "keyword",
["import"] = "keyword",
["module"] = "keyword",
["exposing"] = "keyword",
["let"] = "keyword",
["in"] = "keyword",
["type"] = "keyword",
["alias"] = "keyword",
["port"] = "keyword",
["and"] = "keyword",
["or"] = "keyword",
["xor"] = "keyword",
["not"] = "keyword",
["number"] = "keyword2",
["Bool"] = "keyword2",
["Char"] = "keyword2",
["Float"] = "keyword2",
["Int"] = "keyword2",
["String"] = "keyword2",
["True"] = "literal",
["False"] = "literal",
},
}
+68
View File
@@ -0,0 +1,68 @@
-- mod-version:3
local syntax = require "core.syntax"
local key_pattern = '[a-zA-Z_]+[a-zA-Z0-9_]*'
local unicode_sequence = "'?\\u%x%x%x%x'?"
local escaped_literals = "\\[nrtfb\\\"']"
local null_pattern = '%s*[Nn][Uu][Ll][Ll]%s*'
local true_pattern = '%s*[Tt][Rr][Uu][Ee]%s*'
local false_pattern = '%s*[Ff][Aa][Ll][Ss][Ee]%s*'
local synt_key = {
symbols = {},
patterns = {
{ type = "keyword2", pattern = key_pattern },
},
}
local synt_dqs = {
symbols = {},
patterns = {
{ pattern = { "%${", "}" }, type = "keyword", syntax = synt_key },
{ pattern = "0[bB][%d]+", type = "number" },
{ pattern = "0[xX][%da-fA-F]+", type = "number" },
{ pattern = "[-+]?%.?%d+", type = "number" },
{ pattern = escaped_literals, type = "literal" }, -- escaped chars
{ pattern = unicode_sequence, type = "literal" }, -- unicode sequence
{ pattern = '[%w%p%s]', type = "string" },
},
}
syntax.add {
name = "language_env",
files = { "%.env$" },
comment = '#',
symbols = {},
patterns = {
{ pattern = "#.*$", type = "comment" },
{ pattern = "export", type = "function" },
{ pattern = null_pattern, type = "literal" },
{ pattern = true_pattern, type = "literal" },
{ pattern = false_pattern, type = "literal" },
{ pattern = escaped_literals, type = "literal" },
{ pattern = unicode_sequence, type = "literal" },
-- interpolation
{ pattern = { "%${", "}" }, type = "keyword", syntax = synt_key },
-- numbers
{ pattern = "0[bB][%d]+", type = "number" },
{ pattern = "0[xX][%da-fA-F]+", type = "number" },
{ pattern = "[-+]?%.?%d+", type = "number" },
-- keys
{ pattern = '[\'"].*[\'"]%s*=.*', type = "normal" },
-- {
-- pattern = '[\'"]?'..escaped_literals..'[\'"]?%s*=.*',
-- type = "normal"
-- },
-- {
-- pattern = '[\'"]?'..null_pattern..'[\'"]?%s*=.*',
-- type = "normal"
-- },
{ pattern = key_pattern..'%s*()=%s*', type = { "keyword2", "operator" }},
-- quoted strings
{ pattern = {'"', '"', '\\'}, type = "string", syntax = synt_dqs},
{ pattern = {"'", "'", '\\'}, type = "string" },
{ pattern = {'"""', '"""', '\\'}, type = "string" },
{ pattern = {"'''", "'''", '\\'}, type = "string" },
},
}
+55
View File
@@ -0,0 +1,55 @@
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "html-eruby",
files = { PATHSEP .. "%.html?%.erb$", "%.erb$" },
block_comment = { "<!--", "-->" },
patterns = {
{
pattern = {
"<%s*[sS][cC][rR][iI][pP][tT]%f[%s>].->",
"<%s*/%s*[sS][cC][rR][iI][pP][tT]%s*>"
},
syntax = ".js",
type = "function"
},
{
pattern = {
"<%s*[sS][tT][yY][lL][eE]%f[%s>].->",
"<%s*/%s*[sS][tT][yY][lL][eE]%s*>"
},
syntax = ".css",
type = "function"
},
{
pattern = {
"<%%",
"%%>"
},
syntax = ".rb",
type = "function"
},
{
pattern = {
"<%%=",
"%%>"
},
syntax = ".rb",
type = "function"
},
{ pattern = { "<!%-%-", "%-%->" }, type = "comment" },
{ pattern = { '%f[^>][^<]', '%f[<]' }, type = "normal" },
{ pattern = { '"', '"', '\\' }, type = "string" },
{ pattern = { "'", "'", '\\' }, type = "string" },
{ pattern = "0x[%da-fA-F]+", type = "number" },
{ pattern = "-?%d+[%d%.]*f?", type = "number" },
{ pattern = "-?%.?%d+f?", type = "number" },
{ pattern = "%f[^<]![%a_][%w_]*", type = "keyword2" },
{ pattern = "%f[^<][%a_][%w_]*", type = "function" },
{ pattern = "%f[^<]/[%a_][%w_]*", type = "function" },
{ pattern = "[%a_][%w_]*", type = "keyword" },
{ pattern = "[/<>=]", type = "operator" },
},
symbols = {},
}
+52
View File
@@ -0,0 +1,52 @@
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "fe",
files = "%.fe$",
comment = ";",
patterns = {
{ pattern = ";.*", type = "comment" },
{ pattern = { '"', '"', '\\' }, type = "string" },
{ pattern = "0x[%da-fA-F]+", type = "number" },
{ pattern = "-?%d+[%d%.]*", type = "number" },
{ pattern = "-?%.?%d+", type = "number" },
{ pattern = "'", type = "symbol" },
{ pattern = "=", type = "symbol" },
{ pattern = "<=?", type = "symbol" },
{ pattern = "[%+-%*/]", type = "symbol" },
{ pattern = "%f[^(][^()'%s\"]+", type = "function" },
{ pattern = "[^()'%s\"]+", type = "symbol" },
},
symbols = {
["let"] = "keyword",
["if"] = "keyword",
["fn"] = "keyword",
["mac"] = "keyword",
["while"] = "keyword",
["quote"] = "keyword",
["'"] = "keyword",
["and"] = "keyword",
["or"] = "keyword",
["do"] = "keyword",
["cons"] = "keyword",
["car"] = "keyword",
["cdr"] = "keyword",
["setcar"] = "keyword",
["setcdr"] = "keyword",
["list"] = "keyword",
["not"] = "keyword",
["is"] = "keyword",
["atom"] = "keyword",
["print"] = "keyword",
["<"] = "operator",
["<="] = "operator",
["="] = "operator",
["+"] = "operator",
["-"] = "operator",
["*"] = "operator",
["/"] = "operator",
["nil"] = "literal",
["t"] = "literal",
}
}
+268
View File
@@ -0,0 +1,268 @@
-- mod-version:3
-- Support for the Fennel programming language: https://fennel-lang.org
-- Covers all the keywords up to Fennel version 1.2.0
-- Currently only covers highlighting, not indentation, delimiter
-- matching, or evaluation.
local syntax = require("core.syntax")
syntax.add({
comment = ";",
files = "%.fnl$",
name = "Fennel",
patterns = {
{ pattern = ";.-\n", type = "comment" },
{ pattern = { '"', '"', "\\" }, type = "string" },
{ pattern = "0x[%da-fA-F]+", type = "number" },
{ pattern = "-?%d+[%d%.]*", type = "number" },
{ pattern = "-?%.?%d+", type = "number" },
{ pattern = "%f[^(][^()'%s\"]+", type = "function" },
{ pattern = "[^()'%s\"]+", type = "symbol" },
},
symbols = {
["#"] = "keyword",
["%"] = "keyword",
["*"] = "keyword",
["+"] = "keyword",
["-"] = "keyword",
["->"] = "keyword",
["->>"] = "keyword",
["-?>"] = "keyword",
["-?>>"] = "keyword",
["."] = "keyword",
[".."] = "keyword",
["/"] = "keyword",
["//"] = "keyword",
[":"] = "keyword",
["<"] = "keyword",
["<="] = "keyword",
["="] = "keyword",
[">"] = "keyword",
[">="] = "keyword",
["?."] = "keyword",
["^"] = "keyword",
_G = "keyword",
accumulate = "keyword2",
["and"] = "keyword2",
arg = "keyword2",
assert = "keyword2",
band = "keyword2",
bit32 = "keyword2",
["bit32.arshift"] = "keyword2",
["bit32.band"] = "keyword2",
["bit32.bnot"] = "keyword2",
["bit32.bor"] = "keyword2",
["bit32.btest"] = "keyword2",
["bit32.bxor"] = "keyword2",
["bit32.extract"] = "keyword2",
["bit32.lrotate"] = "keyword2",
["bit32.lshift"] = "keyword2",
["bit32.replace"] = "keyword2",
["bit32.rrotate"] = "keyword2",
["bit32.rshift"] = "keyword2",
bnot = "keyword2",
bor = "keyword2",
bxor = "keyword2",
collect = "keyword2",
collectgarbage = "keyword2",
comment = "keyword2",
coroutine = "keyword2",
["coroutine.create"] = "keyword2",
["coroutine.resume"] = "keyword2",
["coroutine.running"] = "keyword2",
["coroutine.status"] = "keyword2",
["coroutine.wrap"] = "keyword2",
["coroutine.yield"] = "keyword2",
debug = "keyword2",
["debug.debug"] = "keyword2",
["debug.gethook"] = "keyword2",
["debug.getinfo"] = "keyword2",
["debug.getlocal"] = "keyword2",
["debug.getmetatable"] = "keyword2",
["debug.getregistry"] = "keyword2",
["debug.getupvalue"] = "keyword2",
["debug.getuservalue"] = "keyword2",
["debug.sethook"] = "keyword2",
["debug.setlocal"] = "keyword2",
["debug.setmetatable"] = "keyword2",
["debug.setupvalue"] = "keyword2",
["debug.setuservalue"] = "keyword2",
["debug.traceback"] = "keyword2",
["debug.upvalueid"] = "keyword2",
["debug.upvaluejoin"] = "keyword2",
["do"] = "keyword2",
dofile = "keyword2",
doto = "keyword2",
each = "keyword2",
error = "keyword2",
["eval-compiler"] = "keyword2",
["false"] = "literal",
fcollect = "keyword2",
fn = "keyword2",
["for"] = "keyword2",
getmetatable = "keyword2",
global = "keyword2",
hashfn = "keyword2",
icollect = "keyword2",
["if"] = "keyword2",
["import-macros"] = "keyword2",
include = "keyword2",
io = "keyword2",
["io.close"] = "keyword2",
["io.flush"] = "keyword2",
["io.input"] = "keyword2",
["io.lines"] = "keyword2",
["io.open"] = "keyword2",
["io.output"] = "keyword2",
["io.popen"] = "keyword2",
["io.read"] = "keyword2",
["io.tmpfile"] = "keyword2",
["io.type"] = "keyword2",
["io.write"] = "keyword2",
ipairs = "keyword2",
lambda = "keyword2",
length = "keyword2",
let = "keyword2",
load = "keyword2",
loadfile = "keyword2",
loadstring = "keyword2",
["local"] = "keyword2",
lshift = "keyword2",
lua = "keyword2",
macro = "keyword2",
macrodebug = "keyword2",
macros = "keyword2",
match = "keyword2",
["match-try"] = "keyword2",
math = "keyword2",
["math.abs"] = "keyword2",
["math.acos"] = "keyword2",
["math.asin"] = "keyword2",
["math.atan"] = "keyword2",
["math.atan2"] = "keyword2",
["math.ceil"] = "keyword2",
["math.cos"] = "keyword2",
["math.cosh"] = "keyword2",
["math.deg"] = "keyword2",
["math.exp"] = "keyword2",
["math.floor"] = "keyword2",
["math.fmod"] = "keyword2",
["math.frexp"] = "keyword2",
["math.ldexp"] = "keyword2",
["math.log"] = "keyword2",
["math.log10"] = "keyword2",
["math.max"] = "keyword2",
["math.min"] = "keyword2",
["math.modf"] = "keyword2",
["math.pow"] = "keyword2",
["math.rad"] = "keyword2",
["math.random"] = "keyword2",
["math.randomseed"] = "keyword2",
["math.sin"] = "keyword2",
["math.sinh"] = "keyword2",
["math.sqrt"] = "keyword2",
["math.tan"] = "keyword2",
["math.tanh"] = "keyword2",
module = "keyword2",
next = "keyword2",
["nil"] = "literal",
["not"] = "keyword2",
["not="] = "keyword2",
["or"] = "keyword2",
os = "keyword2",
["os.clock"] = "keyword2",
["os.date"] = "keyword2",
["os.difftime"] = "keyword2",
["os.execute"] = "keyword2",
["os.exit"] = "keyword2",
["os.getenv"] = "keyword2",
["os.remove"] = "keyword2",
["os.rename"] = "keyword2",
["os.setlocale"] = "keyword2",
["os.time"] = "keyword2",
["os.tmpname"] = "keyword2",
package = "keyword2",
["package.loadlib"] = "keyword2",
["package.searchpath"] = "keyword2",
["package.seeall"] = "keyword2",
pairs = "keyword2",
partial = "keyword2",
pcall = "keyword2",
["pick-args"] = "keyword2",
["pick-values"] = "keyword2",
print = "keyword2",
quote = "keyword2",
rawequal = "keyword2",
rawget = "keyword2",
rawlen = "keyword2",
rawset = "keyword2",
require = "keyword2",
["require-macros"] = "keyword2",
rshift = "keyword2",
select = "keyword2",
set = "keyword2",
["set-forcibly!"] = "keyword2",
setmetatable = "keyword2",
string = "keyword2",
["string.byte"] = "keyword2",
["string.char"] = "keyword2",
["string.dump"] = "keyword2",
["string.find"] = "keyword2",
["string.format"] = "keyword2",
["string.gmatch"] = "keyword2",
["string.gsub"] = "keyword2",
["string.len"] = "keyword2",
["string.lower"] = "keyword2",
["string.match"] = "keyword2",
["string.rep"] = "keyword2",
["string.reverse"] = "keyword2",
["string.sub"] = "keyword2",
["string.upper"] = "keyword2",
table = "keyword2",
["table.concat"] = "keyword2",
["table.insert"] = "keyword2",
["table.maxn"] = "keyword2",
["table.pack"] = "keyword2",
["table.remove"] = "keyword2",
["table.sort"] = "keyword2",
["table.unpack"] = "keyword2",
tonumber = "keyword2",
tostring = "keyword2",
["true"] = "literal",
tset = "keyword2",
type = "keyword2",
unpack = "keyword2",
values = "keyword2",
var = "keyword2",
when = "keyword2",
["while"] = "keyword2",
["with-open"] = "keyword2",
xpcall = "keyword2",
["~="] = "keyword",
["λ"] = "keyword",
},
})
-- To regenerate the syntax from the compiler:
-- (macro s []
-- (let [{: syntax} (require :fennel)
-- symbols {:nil :literal
-- :true :literal
-- :false :literal}]
-- `(syntax.add {:name "Fennel"
-- :files "%.fnl$"
-- :comment ";"
-- :patterns [{:type :comment :pattern ";.-\n"}
-- {:type :string :pattern {1 "\"" 2 "\"" 3 "\\"}}
-- {:type :number :pattern "0x[%da-fA-F]+"}
-- {:type :number :pattern "-?%d+[%d%.]*"}
-- {:type :number :pattern "-?%.?%d+"}
-- {:type :function :pattern "%f[^(][^()'%s\"]+"}
-- {:type :symbol :pattern "[^()'%s\"]+"}]
-- :symbols ,(collect [name (pairs (syntax)) :into symbols]
-- (values name
-- (if (name:find "[a-z]")
-- :keyword2 :keyword)))}))) (s)
-- and reformat the output, of course
+85
View File
@@ -0,0 +1,85 @@
-- Author: Rohan Vashisht: https://github.com/rohanvashisht1234/
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "Fortran", -- tested ok
files = {
"%.f$", -- tested ok
"%.f90$", -- tested ok
"%.f95$" -- tested ok
},
comment = "!", -- tested ok
patterns = {
{ pattern = { "'", "'", '\\' }, type = "string" }, -- tested ok
{ pattern = { '"', '"', '\\' }, type = "string" }, -- tested ok
{ pattern = "!.*", type = "comment" }, -- tested ok
{ pattern = "%.[%a_][%w_]+%.", type = "normal" }, -- tested ok
{ pattern = "[!%-/*?:=><+]", type = "operator" }, -- tested ok
{ pattern = "[%a_][%w_]*%f[(]", type = "function" }, -- tested ok
{ pattern = "program()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok
{ pattern = "module()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok
{ pattern = "use()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok
{ pattern = "struct()%s+()[%a_][%w_]*", type = { "keyword", "normal", "literal" } }, -- tested ok
{ pattern = "-?%d+[%d%.eE_]*", type = "number" }, -- tested ok
{ pattern = "-?%.?%d+", type = "number" }, -- tested ok
{ pattern = "[%a_][%w_]*", type = "normal" }, -- tested ok
},
symbols = {
["end"] = "keyword", -- tested ok
["program"] = "keyword", -- tested ok
["write"] = "keyword", -- tested ok
["print"] = "keyword", -- tested ok
["implicit"] = "keyword", -- tested ok
["integer"] = "keyword", -- tested ok
["real"] = "keyword", -- tested ok
["complex"] = "keyword", -- tested ok
["character"] = "keyword", -- tested ok
["logical"] = "keyword", -- tested ok
["allocatable"] = "keyword", -- tested ok
["subroutine"] = "keyword", -- tested ok
["do"] = "keyword", -- tested ok
["call"] = "keyword", -- tested ok
["extends"] = "keyword", -- tested ok
["protected"] = "keyword", -- tested ok
["contains"] = "keyword", -- tested ok
["else"] = "keyword", -- tested ok
["then"] = "keyword", -- tested ok
["if"] = "keyword", -- tested ok
["cycle"] = "keyword", -- tested ok
["parameter"] = "keyword", -- tested ok
["concurrent"] = "keyword", -- tested ok
["function"] = "keyword", -- tested ok
["private"] = "keyword", -- tested ok
["public"] = "keyword", -- tested ok
["module"] = "keyword", -- tested ok
["use"] = "keyword", -- tested ok
["type"] = "keyword", -- tested ok
["sequence"] = "keyword", -- tested ok
["struct"] = "keyword", -- tested ok
["result"] = "keyword", -- tested ok
["stop"] = "keyword", -- tested ok
["only"] = "keyword", -- tested ok
["none"] = "keyword2", -- tested ok
["len"] = "keyword2", -- tested ok
[".false."] = "keyword2", -- tested ok
[".true."] = "keyword2", -- tested ok
[".eq."] = "keyword2", -- tested ok
[".ne."] = "keyword2", -- tested ok
[".gt."] = "keyword2", -- tested ok
[".lt."] = "keyword2", -- tested ok
[".ge"] = "keyword2", -- tested ok
[".not."] = "keyword2", -- tested ok
[".le."] = "keyword2", -- tested ok
[".or."] = "keyword2", -- tested ok
[".and."] = "keyword2", -- tested ok
[".eqv."] = "keyword2", -- tested ok
[".neqv."] = "keyword2", -- tested ok
}
}
+99
View File
@@ -0,0 +1,99 @@
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "fstab",
files = { PATHSEP .. "fstab$" },
comment = '#',
patterns = {
-- Only lines that start with a # are comments; you can have #'s in fuse
-- filesystem strings that aren't comments, so shouldn't be highlighted as such.
{ regex = "^#.*", type = "comment" },
{ pattern = "[=/:.,]+", type = "operator" },
{ pattern = "/.*/", type = "string" },
{ pattern = "#", type = "operator" },
-- {
-- pattern = "%g+%s+()%g+%s+()%g+%s+()%g+%s+()[01]%s+()[012]%s*",
-- type = {
-- -- filesystem
-- "keyword",
-- -- mount point
-- "keyword2",
-- -- fs type
-- "symbol",
-- -- options
-- "keyword2",
-- -- dump frequency
-- "keyword",
-- -- pass number
-- "keyword2",
-- }
-- },
-- UUID
{ pattern = "%w-%-%w-%-%w-%-%w-%-%w- ", type = "string" },
-- IPv4 Address
{ pattern = "%d+%.%d+%.%d+%.%d+", type = "string" },
{ pattern = " %d+ ", type = "number" },
{ pattern = "[%w_]+", type = "symbol" },
},
symbols = {
["none"] = "literal",
["LABEL"] = "keyword",
["UUID"] = "keyword",
-- filesystems
["aufs"] = "keyword2",
["autofs"] = "keyword2",
["bdev"] = "keyword2",
["binder"] = "keyword2",
["binfmt_misc"] = "keyword2",
["bpf"] = "keyword2",
["btrfs"] = "keyword2",
["cgroup"] = "keyword2",
["cgroup2"] = "keyword2",
["configfs"] = "keyword2",
["cpuset"] = "keyword2",
["debugfs"] = "keyword2",
["devpts"] = "keyword2",
["devtmpfs"] = "keyword2",
["ecryptfs"] = "keyword2",
["ext2"] = "keyword2",
["ext3"] = "keyword2",
["ext4"] = "keyword2",
["fuse"] = "keyword2",
["fuseblk"] = "keyword2",
["fusectl"] = "keyword2",
["hfs"] = "keyword2",
["hfsplus"] = "keyword2",
["hugetlbfs"] = "keyword2",
["jfs"] = "keyword2",
["minix"] = "keyword2",
["mqueue"] = "keyword2",
["msdos"] = "keyword2",
["nfs"] = "keyword2",
["nfs4"] = "keyword2",
["nfsd"] = "keyword2",
["ntfs"] = "keyword2",
["pipefs"] = "keyword2",
["proc"] = "keyword2",
["pstore"] = "keyword2",
["qnx4"] = "keyword2",
["ramfs"] = "keyword2",
["rpc_pipefs"] = "keyword2",
["securityfs"] = "keyword2",
["sockfs"] = "keyword2",
["squashfs"] = "keyword2",
["swap"] = "keyword2",
["sysfs"] = "keyword2",
["tmpfs"] = "keyword2",
["tracefs"] = "keyword2",
["ufs"] = "keyword2",
["vfat"] = "keyword2",
["xfs"] = "keyword2",
},
}
+19
View File
@@ -0,0 +1,19 @@
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "GABC",
files = { "%.gabc$" },
comment = "%%",
patterns = {
{ pattern = "%%.*", type = "comment" },
{ pattern = "^%w+:", type = "keyword2" },
{ pattern = "[%*{}]", type = "operator" },
{ pattern = "<[^>]*>", type = "function" },
{ pattern = "-?%.?%d+", type = "number" },
{ pattern = { "|", "%)" }, type = "keyword2" },
{ pattern = "%([^%)|]*%)?", type = "keyword" },
},
symbols = {}
}
+101
View File
@@ -0,0 +1,101 @@
-- mod-version:3
-- Support for the GDScript programming language: https://godotengine.org/
-- Covers the most used keywords up to Godot version 3.2.x
local syntax = require "core.syntax"
syntax.add {
name = "GDScript",
files = { "%.gd$" },
comment = "#",
patterns = {
{ pattern = "#.-\n", type = "comment" },
{ pattern = { '"', '"', '\\' }, type = "string" },
{ pattern = { "'", "'", '\\' }, type = "string" },
{ pattern = "-?0x%x*", type = "number" },
{ pattern = "-?%d+[%d%.e]*", type = "number" },
{ pattern = "-?%.?%d+", type = "number" },
{ pattern = "[%+%:%-=/%*%^%%<>!~|&]", type = "operator" },
{ pattern = "[%a_][%w_]*%f[(]", type = "function" },
{ pattern = "[%a_][%w_]*", type = "symbol" },
},
symbols = {
-- keywords
["if"] = "keyword",
["elif"] = "keyword",
["else"] = "keyword",
["for"] = "keyword",
["while"] = "keyword",
["match"] = "keyword",
["break"] = "keyword",
["continue"] = "keyword",
["pass"] = "keyword",
["return"] = "keyword",
["class"] = "keyword",
["class_name"] = "keyword",
["extends"] = "keyword",
["is"] = "keyword",
["in"] = "keyword",
["as"] = "keyword",
["and"] = "keyword",
["or"] = "keyword",
["not"] = "keyword",
["self"] = "keyword",
["tool"] = "keyword",
["signal"] = "keyword",
["func"] = "keyword",
["static"] = "keyword",
["const"] = "keyword",
["enum"] = "keyword",
["var"] = "keyword",
["onready"] = "keyword",
["export"] = "keyword",
["setget"] = "keyword",
["breakpoint"] = "keyword",
["preload"] = "keyword",
["yield"] = "keyword",
["assert"] = "keyword",
["remote"] = "keyword",
["master"] = "keyword",
["puppet"] = "keyword",
["remotesync"] = "keyword",
["mastersync"] = "keyword",
["puppetsync"] = "keyword",
-- types
["void"] = "keyword2",
["int"] = "keyword2",
["float"] = "keyword2",
["bool"] = "keyword2",
["String"] = "keyword2",
["Vector2"] = "keyword2",
["Rect2"] = "keyword2",
["Vector3"] = "keyword2",
["Transform2D"] = "keyword2",
["Plane"] = "keyword2",
["Quat"] = "keyword2",
["AABB"] = "keyword2",
["Basis"] = "keyword2",
["Transform"] = "keyword2",
["Color"] = "keyword2",
["NodePath"] = "keyword2",
["RID"] = "keyword2",
["Object"] = "keyword2",
["Array"] = "keyword2",
["PoolByteArray"] = "keyword2",
["PoolIntArray"] = "keyword2",
["PoolRealArray"] = "keyword2",
["PoolStringArray"] = "keyword2",
["PoolVector2Array"] = "keyword2",
["PoolVector3Array"] = "keyword2",
["PoolColorArray"] = "keyword2",
["Dictionary"] = "keyword2",
-- literals
["null"] = "literal",
["true"] = "literal",
["false"] = "literal",
["PI"] = "literal",
["TAU"] = "literal",
["INF"] = "literal",
["NAN"] = "literal",
},
}
+389
View File
@@ -0,0 +1,389 @@
-- mod-version:3
local style = require "core.style"
local common = require "core.common"
local syntax = require "core.syntax"
syntax.add {
name = "GLSL",
files = { "%.glsl$", "%.frag$", "%.vert$", },
comment = "//",
patterns = {
{ pattern = "//.-\n", type = "comment" },
{ pattern = { "/%*", "%*/" }, type = "comment" },
{ pattern = { "#", "[^\\]\n" }, type = "comment" },
{ pattern = { '"', '"', '\\' }, type = "string" },
{ pattern = { "'", "'", '\\' }, type = "string" },
{ pattern = "-?0x%x+", type = "number" },
{ pattern = "-?%d+[%d%.eE]*f?", type = "number" },
{ pattern = "-?%.?%d+f?", type = "number" },
{ pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" },
{ pattern = "ivec[2-4]", type = "keyword2" },
{ pattern = "bvec[2-4]", type = "keyword2" },
{ pattern = "uvec[2-4]", type = "keyword2" },
{ pattern = "vec[2-4]", type = "keyword2" },
{ pattern = "dmat[2-4]x[2-4]", type = "keyword2" },
{ pattern = "dmat[2-4]", type = "keyword2" },
{ pattern = "mat[2-4]x[2-4]", type = "keyword2" },
{ pattern = "mat[2-4]", type = "keyword2" },
{ pattern = "[%a_][%w_]*%f[(]", type = "function" },
{ pattern = "[%a_][%w_]*", type = "symbol" },
},
symbols = {
--https://www.khronos.org/registry/OpenGL/specs/gl/GLSLangSpec.4.60.pdf
--The symbols are added here in the order they appear in the spec
["if"] = "keyword",
["else"] = "keyword",
["do"] = "keyword",
["while"] = "keyword",
["for"] = "keyword",
["break"] = "keyword",
["continue"] = "keyword",
["return"] = "keyword",
["const"] = "keyword",
["switch"] = "keyword",
["case"] = "keyword",
["default"] = "keyword",
["const"] = "keyword",
["void"] = "keyword",
["bool"] = "keyword2",
["int"] = "keyword2",
["uint"] = "keyword2",
["float"] = "keyword2",
["double"] = "keyword2",
["true"] = "literal",
["false"] = "literal",
["NULL"] = "literal",
["attribute"] = "keyword",
["varying"] = "keyword",
["uniform"] = "keyword",
["buffer"] = "keyword",
["shared"] = "keyword",
["layout"] = "keyword",
["centroid"] = "keyword",
["flat"] = "keyword",
["smooth"] = "keyword",
["noperspective"]= "keyword",
["patch"] = "keyword",
["sample"] = "keyword",
["in"] = "keyword",
["out"] = "keyword",
["inout"] = "keyword",
["invariant"] = "keyword",
["precise"] = "keyword",
["lowp"] = "keyword",
["mediump"] = "keyword",
["highp"] = "keyword",
["precision"] = "keyword",
["struct"] = "keyword",
["subroutine"] = "keyword",
["coherent"] = "keyword",
["volatile"] = "keyword",
["readonly"] = "keyword",
["writeonly"] = "keyword",
["sampler1D"] = "keyword2",
["sampler2D"] = "keyword2",
["sampler3D"] = "keyword2",
["samplerCube"] = "keyword2",
["sampler1DShadow"] = "keyword2",
["sampler2DShadow"] = "keyword2",
["samplerCubeShadow"] = "keyword2",
["sampler1DArray"] = "keyword2",
["sampler2DArray"] = "keyword2",
["samplerCubeArray"] = "keyword2",
["sampler1DArrayShadow"] = "keyword2",
["sampler2DArrayShadow"] = "keyword2",
["samplerCubeArrayShadow"]= "keyword2",
["isampler1D"] = "keyword2",
["isampler2D"] = "keyword2",
["isampler3D"] = "keyword2",
["isamplerCube"] = "keyword2",
["sampler2DMS"] = "keyword2",
["isampler2DMS"] = "keyword2",
["usampler2DMS"] = "keyword2",
["sampler2DMSArray"] = "keyword2",
["isampler2DMSArray"] = "keyword2",
["usampler2DMSArray"] = "keyword2",
["isampler1DArray"] = "keyword2",
["isampler2DArray"] = "keyword2",
["usampler1D"] = "keyword2",
["usampler2D"] = "keyword2",
["usampler3D"] = "keyword2",
["usamplerCube"] = "keyword2",
["usampler1DArray"] = "keyword2",
["usampler2DArray"] = "keyword2",
["sampler2DRect"] = "keyword2",
["sampler2DRectShadow"] = "keyword2",
["isampler2DRect"] = "keyword2",
["usampler2DRect"] = "keyword2",
["samplerBuffer"] = "keyword2",
["isamplerBuffer"] = "keyword2",
["usamplerBuffer"] = "keyword2",
["image1D"] = "keyword2",
["iimage1D"] = "keyword2",
["uimage1D"] = "keyword2",
["image1DArray"] = "keyword2",
["iimage1DArray"] = "keyword2",
["uimage1DArray"] = "keyword2",
["image2D"] = "keyword2",
["iimage2D"] = "keyword2",
["uimage2D"] = "keyword2",
["image2DArray"] = "keyword2",
["iimage2DArray"] = "keyword2",
["uimage2DArray"] = "keyword2",
["image2DRect"] = "keyword2",
["iimage2DRect"] = "keyword2",
["uimage2DRect"] = "keyword2",
["image2DMS"] = "keyword2",
["iimage2DMS"] = "keyword2",
["uimage2DMS"] = "keyword2",
["image2DMSArray"] = "keyword2",
["iimage2DMSArray"]= "keyword2",
["uimage2DMSArray"]= "keyword2",
["image3D"] = "keyword2",
["iimage3D"] = "keyword2",
["uimage3D"] = "keyword2",
["imageCube"] = "keyword2",
["iimageCube"] = "keyword2",
["uimageCube"] = "keyword2",
["imageCubeArray"] = "keyword2",
["iimageCubeArray"]= "keyword2",
["uimageCubeArray"]= "keyword2",
["imageBuffer"] = "keyword2",
["iimageBuffer"] = "keyword2",
["uimageBuffer"] = "keyword2",
["atomic_uint"] = "keyword2",
["radians"] = "keyword",
["degrees"] = "keyword",
["sin"] = "keyword",
["cos"] = "keyword",
["tan"] = "keyword",
["asin"] = "keyword",
["acos"] = "keyword",
["atan"] = "keyword",
["sinh"] = "keyword",
["cosh"] = "keyword",
["tanh"] = "keyword",
["asinh"] = "keyword",
["acosh"] = "keyword",
["pow"] = "keyword",
["exp"] = "keyword",
["exp2"] = "keyword",
["log2"] = "keyword",
["sqrt"] = "keyword",
["inversesqrt"] = "keyword",
["abs"] = "keyword",
["sign"] = "keyword",
["floor"] = "keyword",
["trunc"] = "keyword",
["round"] = "keyword",
["roundEven"] = "keyword",
["ceil"] = "keyword",
["fract"] = "keyword",
["mod"] = "keyword",
["modf"] = "keyword",
["min"] = "keyword",
["max"] = "keyword",
["clamp"] = "keyword",
["mix"] = "keyword",
["step"] = "keyword",
["smoothstep"] = "keyword",
["isnan"] = "keyword",
["isinf"] = "keyword",
["floatBitsToInt"] = "keyword",
["floatBitsToUint"] = "keyword",
["intBitsToFloat"] = "keyword",
["uintBitsToFloat"] = "keyword",
["fma"] = "keyword",
["frexp"] = "keyword",
["ldexp"] = "keyword",
["packUnorm2x16"] = "keyword",
["packSnorm2x16"] = "keyword",
["packUnorm4x8"] = "keyword",
["packSnorm4x8"] = "keyword",
["unpackUnorm2x16"] = "keyword",
["unpackSnorm2x16"] = "keyword",
["unpackUnorm4x8"] = "keyword",
["unpackSnorm4x8"] = "keyword",
["packHalf2x16"] = "keyword",
["unpackHalf2x16"] = "keyword",
["packDouble2x32"] = "keyword",
["unpackDouble2x32"] = "keyword",
["length"] = "keyword",
["distance"] = "keyword",
["dot"] = "keyword",
["cross"] = "keyword",
["normalize"] = "keyword",
["ftransform"] = "keyword",
["faceforward"] = "keyword",
["reflect"] = "keyword",
["refract"] = "keyword",
["matrixCompMult"] = "keyword",
["outerProduct"] = "keyword",
["transpose"] = "keyword",
["determinant"] = "keyword",
["inverse"] = "keyword",
["lessThan"] = "keyword",
["lessThanEqual"] = "keyword",
["greaterThan"] = "keyword",
["greaterThanEqual"] = "keyword",
["equal"] = "keyword",
["notEqual"] = "keyword",
["any"] = "keyword",
["all"] = "keyword",
["not"] = "keyword",
["uaddCarry"] = "keyword",
["usubBorrow"] = "keyword",
["umulExtended"] = "keyword",
["imulExtended"] = "keyword",
["bitfieldExtract"] = "keyword",
["bitfieldInsert"] = "keyword",
["bitfieldReverse"] = "keyword",
["bitCount"] = "keyword",
["findLSB"] = "keyword",
["findMSB"] = "keyword",
["textureSize"] = "keyword",
["textureQueryLod"] = "keyword",
["textureQueryLevels"] = "keyword",
["textureSamples"] = "keyword",
["texture"] = "keyword",
["textureProj"] = "keyword",
["textureLod"] = "keyword",
["textureOffset"] = "keyword",
["texelFetch"] = "keyword",
["texelFetchOffset"] = "keyword",
["textureProjOffset"] = "keyword",
["textureLodOffset"] = "keyword",
["textureProjLod"] = "keyword",
["textureProjLodOffset"] = "keyword",
["textureGrad"] = "keyword",
["textureGradOffset"] = "keyword",
["textureProjGrad"] = "keyword",
["textureProjGradOffset"]= "keyword",
["textureGather"] = "keyword",
["textureGatherOffset"] = "keyword",
["textureGatherOffsets"] = "keyword",
--Atomic Counter Functions
["atomicCounterIncrement"]= "keyword",
["atomicCounterDecrement"]= "keyword",
["atomicCounter"] = "keyword",
["atomicCounterAdd"] = "keyword",
["atomicCounterSubtract"] = "keyword",
["atomicCounterMin"] = "keyword",
["atomicCounterMax"] = "keyword",
["atomicCounterAnd"] = "keyword",
["atomicCounterOr"] = "keyword",
["atomicCounterXor"] = "keyword",
["atomicCounterExchange"] = "keyword",
["atomicCounterCompSwap"] = "keyword",
--Atomic Memory Functions
["atomicAdd"] = "keyword",
["atomicMin"] = "keyword",
["atomicMax"] = "keyword",
["atomicAnd"] = "keyword",
["atomicOr"] = "keyword",
["atomicXor"] = "keyword",
["atomicExchange"]= "keyword",
["atomicCompSwap"]= "keyword",
--Image Functions
["imageSize"] = "keyword",
["imageSamples"] = "keyword",
["imageLoad"] = "keyword",
["imageStore"] = "keyword",
["imageAtomicAdd"] = "keyword",
["imageAtomicMin"] = "keyword",
["imageAtomicMax"] = "keyword",
["imageAtomicAnd"] = "keyword",
["imageAtomicOr"] = "keyword",
["imageAtomicXor"] = "keyword",
["imageAtomicExchange"]= "keyword",
["imageAtomicCompSwap"]= "keyword",
--Geometry Shader Functions
["EmitStreamVertex"] = "keyword",
["EndStreamPrimitive"] = "keyword",
["EmitVertex"] = "keyword",
["EndPrimitive"] = "keyword",
--Fragment Processing Functions
["dFdx"] = "keyword",
["dFdy"] = "keyword",
["dFdxFine"] = "keyword",
["dFdyFine"] = "keyword",
["dFdxCoarse"] = "keyword",
["dFdyCoarse"] = "keyword",
["fwidth"] = "keyword",
["fwidthFine"] = "keyword",
["fwidthCoarse"] = "keyword",
["interpolateAtCentroid"]= "keyword",
["interpolateAtSample"] = "keyword",
["interpolateAtOffset"] = "keyword",
--Shader Invocation Control Functions
["barrier"] = "keyword",
--Shader Memory Control Functions
["memoryBarrier"] = "keyword",
["memoryBarrierAtomicCounter"]= "keyword",
["memoryBarrierBuffer"] = "keyword",
["memoryBarrierShared"] = "keyword",
["memoryBarrierImage"] = "keyword",
["groupMemoryBarrier"] = "keyword",
--Subpass-Input Functions
["subpassLoad"] = "keyword",
--Shader Invocation Group Functions
["anyInvocation"] = "keyword",
["allInvocations"] = "keyword",
["allInvocationsEqual"]= "keyword",
--"In addition, when targeting Vulkan, the following keywords also exist:"
["texture1D"] = "keyword",
["texture1DArray"] = "keyword",
["itexture1D"] = "keyword",
["itexture1DArray"] = "keyword",
["utexture1D"] = "keyword",
["utexture1DArray"] = "keyword",
["texture2D"] = "keyword",
["texture2DArray"] = "keyword",
["itexture2D"] = "keyword",
["itexture2DArray"] = "keyword",
["utexture2D"] = "keyword",
["utexture2DArray"] = "keyword",
["texture2DRect"] = "keyword",
["itexture2DRect"] = "keyword",
["utexture2DRect"] = "keyword",
["texture2DMS"] = "keyword",
["itexture2DMS"] = "keyword",
["utexture2DMS"] = "keyword",
["texture2DMSArray"] = "keyword",
["itexture2DMSArray"]= "keyword",
["utexture2DMSArray"]= "keyword",
["texture3D"] = "keyword",
["itexture3D"] = "keyword",
["utexture3D"] = "keyword",
["textureCube"] = "keyword",
["itextureCube"] = "keyword",
["utextureCube"] = "keyword",
["textureCubeArray"] = "keyword",
["itextureCubeArray"]= "keyword",
["utextureCubeArray"]= "keyword",
["textureBuffer"] = "keyword",
["itextureBuffer"] = "keyword",
["utextureBuffer"] = "keyword",
["sampler"] = "keyword2",
["samplerShadow"] = "keyword2",
["subpassInput"] = "keyword2",
["isubpassInput"] = "keyword2",
["usubpassInput"] = "keyword2",
["subpassInputMS"] = "keyword2",
["isubpassInputMS"] = "keyword2",
["usubpassInputMS"] = "keyword2",
},
}
+21
View File
@@ -0,0 +1,21 @@
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "Gemtext",
files = { "%.gmi$" },
patterns = {
{ pattern = { "```", "```" }, type = "string" },
{ pattern = "#.*", type = "keyword" },
{ pattern = "%*%s", type = "keyword2" },
{ pattern = "=>", type = "function" },
{ pattern = "https?://%S+", type = "literal" },
{ pattern = "gemini?://%S+", type = "literal" },
{ pattern = ">.*", type = "comment" },
{ pattern = ".*[>*#]", type = "normal" },
{ pattern = ".*=>", type = "normal" }
},
symbols = { },
}
+232
View File
@@ -0,0 +1,232 @@
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "Go",
files = { "%.go$" },
comment = "//",
block_comment = {"/*", "*/"},
patterns = {
{ pattern = "//.-\n", type = "comment" },
{ pattern = { "/%*", "%*/" }, type = "comment" },
{ pattern = { '"', '"', '\\' }, type = "string" },
{ pattern = { "`", "`", '\\' }, type = "string" },
{ pattern = { "'", "'", '\\' }, type = "string" },
{ pattern = "0[oO_][0-7]+i?", type = "number" },
{ pattern = "-?0x[%x_]+i?", type = "number" },
{ pattern = "-?%d+_%di?", type = "number" },
{ pattern = "-?%d+[%d%.eE]*f?i?", type = "number" },
{ pattern = "-?%.?%d+f?i?", type = "number" },
-- goto label
{ pattern = "^%s+()[%a_][%w%_]*()%s*:%s$", -- this is to fix `default:`
type = { "normal", "function", "normal" }
},
{ pattern = "^%s*[%a_][%w%_]*()%s*:%s$",
type = { "function", "normal" }
},
-- pointer, generic and reference type
{ pattern = "[%*~&]()[%a_][%w%_]*",
type = { "operator", "keyword2" }
},
-- slice type
{ pattern = "%[%]()[%a_][%w%_]*",
type = { "operator", "keyword2" }
},
-- type coerce
{
pattern = "%.%(()[%a_][%w_]*()%)",
type = { "normal", "keyword2", "normal" }
},
-- struct literal
{ pattern = "[%a_][%w%_]*()%s*{%s*",
type = { "keyword2", "normal" }
},
-- operators
{ pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" },
{ pattern = ":=", type = "operator" },
-- function calls
{ pattern = "func()%s*[%a_][%w_]*()%f[%[(]", -- function statement
type = {"keyword", "function", "normal"}
},
{ pattern = "[%a_][%w_]*%f[(]", type = "function" },
{ pattern = "%.()[%a_][%w_]*%f[(]",
type = { "normal", "function" }
},
-- type declaration
{ pattern = "type()%s+()[%a_][%w%_]*",
type = { "keyword", "normal", "keyword2" }
},
-- variable declaration
{ pattern = "var()%s+()[%a_][%w%_]*",
type = { "keyword", "normal", "symbol" }
},
-- goto
{ pattern = "goto()%s+()[%a_][%w%_]*",
type = { "keyword", "normal", "function" }
},
-- if fix
{ pattern = "if()%s+%f[%a_]",
type = { "keyword", "normal" }
},
-- for fix
{ pattern = "for()%s+%f[%a_]",
type = { "keyword", "normal" }
},
-- return fix
{ pattern = "return()%s+%f[%a_]",
type = { "keyword", "normal" }
},
-- range fix
{ pattern = "range()%s+%f[%a_]",
type = { "keyword", "normal" }
},
-- func fix
{ pattern = "func()%s+%f[%a_]",
type = { "keyword", "normal" }
},
-- switch fix
{ pattern = "switch()%s+%f[%a_]",
type = { "keyword", "normal" }
},
-- case fix
{ pattern = "case()%s+%f[%a_]",
type = { "keyword", "normal" }
},
-- break fix
{ pattern = "break()%s+%f[%a_]",
type = { "keyword", "normal" }
},
-- continue fix
{ pattern = "continue()%s+%f[%a_]",
type = { "keyword", "normal" }
},
-- package fix
{ pattern = "package()%s+%f[%a_]",
type = { "keyword", "normal" }
},
-- go fix
{ pattern = "go()%s+%f[%a_]",
type = { "keyword", "normal" }
},
-- chan fix
{ pattern = "chan()%s+%f[%a_]",
type = { "keyword", "normal" }
},
-- defer fix
{ pattern = "defer()%s+%f[%a_]",
type = { "keyword", "normal" }
},
-- field declaration
{ pattern = "[%a_][%w%_]*()%s*():%s*%f[%w%p]",
type = { "function", "normal", "operator" }
},
-- parameters or declarations
{ pattern = "[%a_][%w%_]*()%s+()[%*~&]?()[%a_][%w%_]*",
type = { "literal", "normal", "operator", "keyword2" }
},
{ pattern = "[%a_][%w_]*()%s+()%[%]()[%a_][%w%_]*",
type = { "literal", "normal", "normal", "keyword2" }
},
-- single return type
{
pattern = "%)%s+%(?()[%a_][%w%_]*()%)?%s+%{",
type = { "normal", "keyword2", "normal" }
},
-- sub fields
{ pattern = "%.()[%a_][%w_]*",
type = { "normal", "literal" }
},
-- every other symbol
{ pattern = "[%a_][%w_]*", type = "symbol" },
},
symbols = {
["if"] = "keyword",
["else"] = "keyword",
["elseif"] = "keyword",
["for"] = "keyword",
["continue"] = "keyword",
["return"] = "keyword",
["struct"] = "keyword",
["switch"] = "keyword",
["case"] = "keyword",
["default"] = "keyword",
["const"] = "keyword",
["package"] = "keyword",
["import"] = "keyword",
["func"] = "keyword",
["var"] = "keyword",
["type"] = "keyword",
["interface"] = "keyword",
["select"] = "keyword",
["break"] = "keyword",
["range"] = "keyword",
["chan"] = "keyword",
["defer"] = "keyword",
["go"] = "keyword",
["fallthrough"] = "keyword",
["goto"] = "keyword",
["iota"] = "keyword2",
["int"] = "keyword2",
["int64"] = "keyword2",
["int32"] = "keyword2",
["int16"] = "keyword2",
["int8"] = "keyword2",
["uint"] = "keyword2",
["uint64"] = "keyword2",
["uint32"] = "keyword2",
["uint16"] = "keyword2",
["uint8"] = "keyword2",
["uintptr"] = "keyword2",
["float64"] = "keyword2",
["float32"] = "keyword2",
["map"] = "keyword2",
["string"] = "keyword2",
["rune"] = "keyword2",
["bool"] = "keyword2",
["byte"] = "keyword2",
["error"] = "keyword2",
["complex64"] = "keyword2",
["complex128"] = "keyword2",
["true"] = "literal",
["false"] = "literal",
["nil"] = "literal",
},
}
syntax.add {
name = "Go",
files = { PATHSEP .. "go%.mod" },
comment = "//",
patterns = {
{ pattern = "//.-\n", type = "comment"},
{ pattern = "module() %S+()",
type = { "keyword", "string", "normal"}
},
{ pattern = "go() %S+()",
type = { "keyword", "string", "normal" }
},
{ pattern = "%S+() v%S+()",
type = { "string", "keyword", "normal" }
},
},
symbols = {
["require"] = "keyword",
["module"] = "keyword",
["go"] = "keyword",
}
}
syntax.add {
name = "Go",
files = { PATHSEP .. "go%.sum" },
patterns = {
{ pattern = "%S+() v[^/]-() h1:()%S+()=",
type = { "string", "keyword", "normal", "string", "normal" }
},
{ pattern = "%S+() v[^/]-()/%S+() h1:()%S+()=",
type = { "string", "keyword", "string", "normal", "string", "normal" }
},
},
symbols = {}
}
+42
View File
@@ -0,0 +1,42 @@
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "GraphQL",
files = { "%.graphql$", "%.gql$" },
comment = "#",
block_comment = { '"""', '"""' },
patterns = {
{ pattern = { '"""', '"""' }, type = "comment" },
{ pattern = "#.*", type = "comment" },
{ pattern = { '"', '"', "\\" }, type = "string" },
{ pattern = "-?%.?%d+", type = "number" },
{ pattern = "%s*[@]%s*[%a_][%w_]*", type = "function" },
{ pattern = "!", type = "operator" },
{ pattern = "%s*=%s*", type = "operator" },
{ pattern = "%s*%$[%a_][%w_]*:*", type = "literal" },
{ pattern = "query%s*()[%a_][%w_]*[(]", type = { "keyword", "function" } },
{ pattern = "mutation%s*()[%a_][%w_]*[(]", type = { "keyword", "function" } },
{ pattern = ":%s*%[*()[%a_,%s][%w_,%s]*()%]*()[!]*", type = { "symbol", "literal", "symbol", "operator" } },
},
symbols = {
["query"] = "keyword",
["mutation"] = "keyword",
["type"] = "keyword",
["interface"] = "keyword",
["input"] = "keyword",
["fragment"] = "keyword",
["directive"] = "keyword",
["extends"] = "keyword",
["implements"] = "keyword",
["on"] = "keyword",
["enum"] = "keyword",
["scalar"] = "keyword",
["union"] = "keyword",
["schema"] = "keyword",
["extend"] = "keyword2",
["true"] = "literal",
["false"] = "literal",
},
}
+98
View File
@@ -0,0 +1,98 @@
-- mod-version:3
local syntax = require 'core.syntax'
syntax.add {
name = "Gravity",
files = { "%.gravity$" },
comment = "//",
block_comment = {"/*", "*/"},
patterns = {
{ pattern = "#![^\n]+", type = "comment" },
{ pattern = "//[^\n]+", type = "comment" },
{ pattern = { "/%*", "%*/" }, type = "comment" },
{ pattern = { '"', '"', "\\" }, type = "string" },
{ pattern = "[~=!<>]=?", type = "operator" },
{ pattern = "[!=]==", type = "operator" },
{ pattern = "[%+%-%*/%%&|^]", type = "operator" },
{ pattern = "%.%.[%.<]", type = "operator" },
{ pattern = "0[bB][0-1]+%f[%D]", type = "number" },
{ pattern = "0[oO][0-7]+", type = "number" },
{ pattern = "0[xX]%x+", type = "number" },
{ pattern = "%.?%d+[eE]?%-?%d*", type = "number" },
{ pattern = "#%s*include%s*%f[\"]", type = "literal"},
{ pattern = "#%s*unittest%s*%f[{]", type = "literal"},
--{ pattern = "[%+%-%*/]%s*()%(", type = { "function", "normal" }},
{ pattern = "[%a_][%w_]+%s*%f[%(]", type = "function"},
{ pattern = "[%a_][%w_]*", type = "symbol" },
},
symbols = {
["true"] = "literal",
["false"] = "literal",
["null"] = "literal",
["self"] = "keyword2",
["Object"] = "literal",
["Int"] = "literal",
["Float"] = "literal",
["String"] = "literal",
["Bool"] = "literal",
["Null"] = "literal",
["Class"] = "literal",
["Function"] = "literal",
["Fiber"] = "literal",
["Instance"] = "literal",
["List"] = "literal",
["Map"] = "literal",
["Range"] = "literal",
["System"] = "literal",
["Math"] = "literal",
["File"] = "literal",
["ENV"] = "literal",
["if"] = "keyword",
["in"] = "keyword",
["or"] = "keyword",
["is"] = "operator",
["for"] = "keyword",
["var"] = "keyword",
["and"] = "keyword",
["not"] = "keyword",
["func"] = "keyword",
["else"] = "keyword",
["true"] = "keyword",
["enum"] = "keyword",
["case"] = "keyword",
["null"] = "keyword",
["file"] = "keyword",
["lazy"] = "keyword",
["super"] = "keyword",
["break"] = "keyword",
["while"] = "keyword",
["class"] = "keyword",
["const"] = "keyword",
["event"] = "keyword",
["_func"] = "keyword",
["_args"] = "keyword",
["struct"] = "keyword",
["repeat"] = "keyword",
["switch"] = "keyword",
["return"] = "keyword",
["public"] = "keyword",
["static"] = "keyword",
["extern"] = "keyword",
["import"] = "keyword",
["module"] = "keyword",
["default"] = "keyword",
["private"] = "keyword",
["continue"] = "keyword",
["internal"] = "keyword",
["undefined"] = "keyword",
}
}
+109
View File
@@ -0,0 +1,109 @@
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "Groovy",
files = { "%.groovy$", PATHSEP .. "Jenkinsfile$" },
comment = "//",
block_comment = { "/*", "*/" },
patterns = {
{ pattern = "//.*", type = "comment" }, -- Single-line comment
{ pattern = { "/%*", "%*/" }, type = "comment" }, -- Multi-line comment
{ pattern = { '"', '"', '\\' }, type = "string" }, -- String, double quotes
{ pattern = { "'", "'", '\\' }, type = "string" }, -- String, apices
{ pattern = { "%/", "%/", '\\' }, type = "string" }, -- Slashy string
{ pattern = { "%$%/", "%/%$", '\\' }, type = "string" }, -- Dollar slashy string
{ pattern = "'\\x%x?%x?%x?%x'", type = "string" }, -- character hexadecimal escape sequence
{ pattern = "'\\u%x%x%x%x'", type = "string" }, -- character unicode escape sequence
{ pattern = "'\\?.'", type = "string" }, -- character literal
{ pattern = "-?0x%x+", type = "number" }, -- ?
{ pattern = "-?%d+[%d%.eE]*[a-zA-Z]?", type = "number" }, -- ?
{ pattern = "-?%.?%d+", type = "number" }, -- ?
{ pattern = "-?[%d_+]+[a-zA-Z]?", type = "number" }, -- ?
{ pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" }, -- Operators
{ pattern = "[%a_][%w_]*%f[(]", type = "function" }, -- Function/Class/Method/...
{ pattern = "[%a_][%w_]*%f[%[]", type = "function" }, -- Custom Type
{ regex = "[A-Z]+_?[A-Z]+", type = "keyword2" }, -- Constants
{ pattern = "import()%s+()[%w_.]+", type = { "keyword", "normal", "normal" } },
{ pattern = "[%a_][%w_]*", type = "symbol" }, -- ?
{ pattern = "[a-zA-Z]+%.+", type = "function" }, -- Lib path
-- TODO: .class.
},
symbols = {
-- Reserved keywords
["abstract"] = "keyword",
["assert"] = "keyword",
["break"] = "keyword",
["case"] = "keyword",
["catch"] = "keyword",
["class"] = "keyword",
["const"] = "keyword",
["continue"] = "keyword",
["def"] = "keyword",
["default"] = "keyword",
["do"] = "keyword",
["else"] = "keyword",
["enum"] = "keyword",
["extends"] = "keyword",
["final"] = "keyword",
["finally"] = "keyword",
["for"] = "keyword",
["goto"] = "keyword",
["if"] = "keyword",
["implements"] = "keyword",
["import"] = "keyword",
["instanceof"] = "keyword",
["interface"] = "keyword",
["native"] = "keyword",
["new"] = "keyword",
["non-sealed"] = "keyword",
["package"] = "keyword",
["public"] = "keyword",
["protected"] = "keyword",
["private"] = "keyword",
["return"] = "keyword",
["static"] = "keyword",
["strictfp"] = "keyword",
["super"] = "keyword",
["switch"] = "keyword",
["synchronizedthis"] = "keyword",
["threadsafe"] = "keyword",
["throw"] = "keyword",
["throws"] = "keyword",
["transient"] = "keyword",
["try"] = "keyword",
["while"] = "keyword",
-- Contextual keywords
["as"] = "keyword",
["in"] = "keyword",
["permitsrecord"] = "keyword",
["sealed"] = "keyword",
["trait"] = "keyword",
["var"] = "keyword",
["yields"] = "keyword",
-- ?
["true"] = "literal",
["false"] = "literal",
["null"] = "literal",
["boolean"] = "literal",
-- Types
["char"] = "keyword",
["byte"] = "keyword",
["short"] = "keyword",
["int"] = "keyword",
["long"] = "keyword",
["float"] = "keyword",
["double"] = "keyword",
["Integer"] = "keyword",
["BigInteger"] = "keyword",
["Long"] = "keyword",
["Float"] = "keyword",
["BigDecimal"] = "keyword",
["Double"] = "keyword",
["String"] = "keyword",
},
}
+91
View File
@@ -0,0 +1,91 @@
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "Hare",
files = { "%.ha$" },
comment = "//",
patterns = {
{ pattern = "//.*", type = "comment" },
-- { pattern = { "/%*", "%*/" }, type = "comment" },
{ pattern = { '"', '"', '\\' }, type = "string" },
{ pattern = { "'", "'", '\\' }, type = "string" },
{ pattern = "-?0x%x+", type = "number" },
{ pattern = "-?%d+[%d%.eE]*f?", type = "number" },
{ pattern = "-?%.?%d+f?", type = "number" },
{ pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" },
{ pattern = "[%a_][%w_]*%f[(]", type = "function" },
{ pattern = "[%a_][%w_]*", type = "symbol" },
{ pattern = "^@", type = "keyword" },
},
symbols = {
["export"] = "keyword",
["fn"] = "keyword",
["use"] = "keyword",
["const"] = "keyword",
["let"] = "keyword",
["defer"] = "keyword",
["static"] = "keyword",
["yield"] = "keyword",
["case"] = "keyword",
["match"] = "keyword",
["return"] = "keyword",
["switch"] = "keyword",
["for"] = "keyword",
["if"] = "keyword",
["type"] = "keyword",
["abort"] = "keyword",
["align"] = "keyword",
["alloc"] = "keyword",
["break"] = "keyword",
["continue"] = "keyword",
["def"] = "keyword",
["delete"] = "keyword",
["else"] = "keyword",
["free"] = "keyword",
["insert"] = "keyword",
["is"] = "keyword",
["len"] = "keyword",
["offset"] = "keyword",
["vaarg"] = "keyword",
["vaend"] = "keyword",
["vastart"] = "keyword",
["fini"] = "keyword",
["init"] = "keyword",
["test"] = "keyword",
["nullable"] = "keyword2",
["str"] = "keyword2",
["void"] = "keyword2",
["int"] = "keyword2",
["uint"] = "keyword2",
["struct"] = "keyword2",
["union"] = "keyword2",
["enum"] = "keyword2",
["u8"] = "keyword2",
["u16"] = "keyword2",
["u32"] = "keyword2",
["u64"] = "keyword2",
["i8"] = "keyword2",
["i16"] = "keyword2",
["i32"] = "keyword2",
["i64"] = "keyword2",
["f32"] = "keyword2",
["f64"] = "keyword2",
["size"] = "keyword2",
["rune"] = "keyword2",
["bool"] = "keyword2",
["valist"] = "keyword2",
["uintptr"] = "keyword2",
["rconst"] = "keyword2",
["fconst"] = "keyword2",
["iconst"] = "keyword2",
["fmt"] = "literal",
["true"] = "literal",
["false"] = "literal",
["signed"] = "literal",
["unsigned"] = "literal",
["null"] = "literal",
},
}
+113
View File
@@ -0,0 +1,113 @@
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "Haxe Compiler Arguments",
files = "%.hxml$",
comment = "#",
patterns = {
{ pattern = "#.*", type = "comment"},
{ pattern = "%-[%-%w_]*", type="keyword"},
{ pattern = "%.()%u[%w_]*", type = {"normal", "keyword2"}},
},
symbols = {}
}
syntax.add {
name = "Haxe String Interpolation",
files = "%.hx__string_interp$",
patterns = {
{ pattern = {"%${", "}", "\\"}, type="keyword", syntax = ".hx" },
{ pattern = {"%$", "%s", "\\"}, type="keyword", syntax = ".hx" },
{ pattern = "[^ ]", type = "string"}
},
symbols = {}
}
syntax.add {
name = "Haxe Regular Expressions",
files = "%.hx__regex$",
patterns = {
{ pattern = "[%[%]%(%)]", type = "string" },
{ pattern = "[%.%*%+%?%^%$%|%-]", type = "operator" },
},
symbols = {}
}
syntax.add {
name = "Haxe",
files = "%.hx$",
comment = "//",
patterns = {
{ pattern = {"%~%/", "%/[igmsu]*"}, type = "keyword2", syntax = ".hx__regex" },
{ pattern = "%.%.%.", type = "operator" },
{ pattern = "%<()%u[%w_]*()%>*", type = {"operator", "keyword2", "operator"}},
{ pattern = "%#%s*[%a_]*().*\n", type = {"keyword", "normal"} },
{ pattern = "import%s+()%u[%w]*", type = {"keyword", "keyword2"}},
{ pattern = "import%s+()[%w%.]*%.()%u[%w]*", type = {"keyword", "normal", "keyword2"}},
{ pattern = "abstract%s+()%u[%w_]*%s*%(()%s*%u[%w_]*", type = {"keyword2", "normal", "keyword2"} },
{ pattern = "from%s+()%u[%w_]*%s+()to%s+()%u[%w_]*", type = {"keyword", "keyword2", "keyword", "keyword2"}},
{ pattern = "//.*\n", type = "comment" },
{ pattern = { "/%*", "%*/" }, type = "comment" },
{ pattern = { '"', '"', '\\' }, type = "string" },
{ pattern = { "'", "'", "\\" }, type = "string", syntax = ".hx__string_interp"},
{ pattern = "-?%.?%d+", type = "number" },
{ pattern = "-?0x%x+", type = "number" },
{ pattern = "-?%d+%.[%deE]+", type = "number" },
{ pattern = "-?%d+[%deE]+", type = "number" },
{ pattern = "[%+%-%.=/%*%^%%<>!~|&]", type = "operator" },
{ pattern = "[%a_][%w_]*()%s*%f[(]", type = {"function", "normal"} },
{ pattern = "[%a_][%w_]*", type = "symbol" },
{ pattern = ":()%u[%a_][%w_]*", type = {"normal", "keyword2"}},
{ pattern = "@:[%a_][%w_]*%f[(]", type = "keyword" },
{ pattern = "%$type", type = "keyword" },
},
symbols = {
["abstract"] = "keyword2",
["extends"] = "keyword2",
["typedef"] = "keyword2",
["implements"] = "keyword2",
["import"] = "keyword",
["package"] = "keyword",
["using"] = "keyword2",
["macro"] = "keyword2",
["class"] = "keyword",
["function"] = "keyword2",
["var"] = "keyword2",
["extern"] = "keyword2",
["in"] = "keyword",
["cast"] = "keyword",
["get"] = "keyword",
["set"] = "keyword",
["never"] = "keyword",
["inline"] = "keyword",
["trace"] = "keyword",
["final"] = "keyword",
["break"] = "keyword",
["case"] = "keyword",
["catch"] = "keyword",
["continue"] = "keyword",
["default"] = "keyword",
["do"] = "keyword",
["else"] = "keyword",
["enum"] = "keyword",
["for"] = "keyword",
["if"] = "keyword",
["interface"] = "keyword",
["new"] = "keyword",
["override"] = "keyword",
["private"] = "keyword",
["public"] = "keyword",
["return"] = "keyword",
["static"] = "keyword",
["switch"] = "keyword",
["this"] = "keyword",
["throw"] = "keyword",
["try"] = "keyword",
["while"] = "keyword",
["true"] = "literal",
["false"] = "literal",
["null"] = "literal",
},
}
+277
View File
@@ -0,0 +1,277 @@
-- mod-version:3
local style = require "core.style"
local common = require "core.common"
local syntax = require "core.syntax"
syntax.add {
name = "HLSL",
files = { "%.hlsl$", },
comment = "//",
patterns = {
{ pattern = "//.-\n", type = "comment" },
{ pattern = { "/%*", "%*/" }, type = "comment" },
{ pattern = { "#", "[^\\]\n" }, type = "comment" },
{ pattern = { '"', '"', '\\' }, type = "string" },
{ pattern = { "'", "'", '\\' }, type = "string" },
{ pattern = "-?0x%x+", type = "number" },
{ pattern = "-?%d+[%d%.eE]*f?", type = "number" },
{ pattern = "-?%.?%d+f?", type = "number" },
{ pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" },
{ pattern = "int[1-9]x[1-9]", type = "keyword2" },
{ pattern = "int1[0-6]x[1-9]", type = "keyword2" },
{ pattern = "int[1-9]x1[0-6]", type = "keyword2" },
{ pattern = "int1[0-6]x1[0-6]", type = "keyword2" },
{ pattern = "int[1-4]", type = "keyword2" },
{ pattern = "uint[1-9]x[1-9]", type = "keyword2" },
{ pattern = "uint1[0-6]x[1-9]", type = "keyword2" },
{ pattern = "uint[1-9]x1[0-6]", type = "keyword2" },
{ pattern = "uint1[0-6]x1[0-6]", type = "keyword2" },
{ pattern = "uint[1-4]", type = "keyword2" },
{ pattern = "dword[1-9]x[1-9]", type = "keyword2" },
{ pattern = "dword1[0-6]x[1-9]", type = "keyword2" },
{ pattern = "dword[1-9]x1[0-6]", type = "keyword2" },
{ pattern = "dword1[0-6]x1[0-6]", type = "keyword2" },
{ pattern = "dword[1-4]", type = "keyword2" },
{ pattern = "half[1-9]x[1-9]", type = "keyword2" },
{ pattern = "half1[0-6]x[1-9]", type = "keyword2" },
{ pattern = "half[1-9]x1[0-6]", type = "keyword2" },
{ pattern = "half1[0-6]x1[0-6]", type = "keyword2" },
{ pattern = "half[1-4]", type = "keyword2" },
{ pattern = "float[1-9]x[1-9]", type = "keyword2" },
{ pattern = "float1[0-6]x[1-9]", type = "keyword2" },
{ pattern = "float[1-9]x1[0-6]", type = "keyword2" },
{ pattern = "float1[0-6]x1[0-6]", type = "keyword2" },
{ pattern = "float[1-4]", type = "keyword2" },
{ pattern = "double[1-9]x[1-9]", type = "keyword2" },
{ pattern = "double1[0-6]x[1-9]", type = "keyword2" },
{ pattern = "double[1-9]x1[0-6]", type = "keyword2" },
{ pattern = "double1[0-6]x1[0-6]", type = "keyword2" },
{ pattern = "double[1-4]", type = "keyword2" },
{ pattern = "[%a_][%w_]*%f[(]", type = "function" },
{ pattern = "[%a_][%w_]*", type = "symbol" },
},
symbols = {
--https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-appendix-keywords
--The symbols are added in the order they appear on this webpage, which is alphabetically
["AppendStructuredBuffer"]= "keyword",
["asm"] = "keyword",
["asm_fragment"] = "keyword",
["BlendState"] = "keyword2",
["bool"] = "keyword2",
["break"] = "keyword",
["Buffer"] = "keyword2",
["ByteAddressBuffer"]= "keyword2",
["case"] = "keyword",
["cbuffer"] = "keyword2",
["centroid"] = "keyword2",
["class"] = "keyword",
["column_major"] = "keyword",
["compile"] = "keyword",
["compile_fragment"] = "keyword",
["CompileShader"] = "keyword",
["const"] = "keyword",
["continue"] = "keyword",
["ComputeShader"] = "keyword",
["ConsumeStructuredBuffer"]= "keyword",
["default"] = "keyword",
["DepthStencilState"]= "keyword",
["DepthStencilView"] = "keyword",
["discard"] = "keyword",
["do"] = "keyword",
["double"] = "keyword2",
["DomainShader"] = "keyword2",
["dword"] = "keyword2",
["else"] = "keyword",
["export"] = "keyword",
["extern"] = "keyword",
["false"] = "literal",
["float"] = "keyword2",
["for"] = "keyword",
["fxgroup"] = "keyword2",
["GeometryShader"] = "keyword2",
["groupshared"] = "keyword",
["half"] = "keyword2",
["HullShader"] = "keyword2",
["if"] = "keyword",
["in"] = "keyword",
["inline"] = "keyword",
["inout"] = "keyword",
["InputPatch"] = "keyword2",
["int"] = "keyword2",
["interface"] = "keyword",
["line"] = "keyword2",
["lineadj"] = "keyword2",
["linear"] = "keyword",
["LineStream"] = "keyword2",
["matrix"] = "keyword2",
["min16float"] = "keyword2",
["min10float"] = "keyword2",
["min16int"] = "keyword2",
["min12int"] = "keyword2",
["min16uint"] = "keyword2",
["namespace"] = "keyword",
["nointerpolation"] = "keyword",
["noperspective"] = "keyword",
["NULL"] = "literal",
["out"] = "keyword",
["OutputPatch"] = "keyword2",
["packoffset"] = "keyword",
["pass"] = "keyword",
["pixelfragment"] = "keyword",
["PixelShader"] = "keyword2",
["point"] = "keyword2",
["PointStream"] = "keyword2",
["precise"] = "keyword",
["RasterizerState"] = "keyword2",
["RenderTargetView"] = "keyword2",
["return"] = "keyword",
["register"] = "keyword",
["row_major"] = "keyword",
["RWBuffer"] = "keyword2",
["RWByteAddressBuffer"]= "keyword2",
["RWStructuredBuffer"]= "keyword2",
["RWTexture1D"] = "keyword2",
["RWTexture1DArray"] = "keyword2",
["RWTexture2D"] = "keyword2",
["RWTexture2DArray"] = "keyword2",
["RWTexture3D"] = "keyword2",
["sample"] = "keyword",
["sampler"] = "keyword2",
["SamplerState"] = "keyword2",
["SamplerComparisonState"]= "keyword2",
["shared"] = "keyword",
["snorm"] = "keyword",
["stateblock"] = "keyword",
["stateblock_state"] = "keyword",
["static"] = "keyword",
["string"] = "keyword2",
["struct"] = "keyword",
["switch"] = "keyword",
["StructuredBuffer"] = "keyword2",
["tbuffer"] = "keyword2",
["technique"] = "keyword2",
["technique10"] = "keyword2",
["technique11"] = "keyword2",
["texture"] = "keyword2",
["Texture1D"] = "keyword2",
["Texture1DArray"] = "keyword2",
["Texture2D"] = "keyword2",
["Texture2DArray"] = "keyword2",
["Texture2DMS"] = "keyword2",
["Texture2DMSArray"] = "keyword2",
["Texture3D"] = "keyword2",
["TextureCube"] = "keyword2",
["TextureCubeArray"] = "keyword2",
["true"] = "literal",
["typedef"] = "keyword",
["triangle"] = "keyword2",
["triangleadj"] = "keyword2",
["TriangleStream"] = "keyword2",
["uint"] = "keyword2",
["uniform"] = "keyword",
["unorm"] = "keyword",
["unsigned"] = "keyword",
["vector"] = "keyword2",
["vertexfragment"] = "keyword2",
["VertexShader"] = "keyword2",
["void"] = "keyword",
["volatile"] = "keyword",
["while"] = "keyword",
--https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-intrinsic-functions
--The symbols are added in the order they appear on this webpage, which is alphabetically
["abort"] = "keyword",
["abs"] = "keyword",
["acos"] = "keyword",
["all"] = "keyword",
["any"] = "keyword",
["asdouble"] = "keyword",
["asfloat"] = "keyword",
["asin"] = "keyword",
["asint"] = "keyword",
["asuint"] = "keyword",
["atan"] = "keyword",
["atan2"] = "keyword",
["ceil"] = "keyword",
["clamp"] = "keyword",
["clip"] = "keyword",
["cos"] = "keyword",
["cosh"] = "keyword",
["countbits"] = "keyword",
["cross"] = "keyword",
["ddx"] = "keyword",
["ddx_coarse"] = "keyword",
["ddx_fine"] = "keyword",
["ddy"] = "keyword",
["ddy_coarse"] = "keyword",
["ddy_fine"] = "keyword",
["degrees"] = "keyword",
["determinant"] = "keyword",
["distance"] = "keyword",
["dot"] = "keyword",
["dst"] = "keyword",
["errorf"] = "keyword",
["exp"] = "keyword",
["exp2"] = "keyword",
["f16tof32"] = "keyword",
["f32tof16"] = "keyword",
["faceforward"] = "keyword",
["firstbithigh"]= "keyword",
["firstbitlow"] = "keyword",
["floor"] = "keyword",
["fma"] = "keyword",
["fmod"] = "keyword",
["frac"] = "keyword",
["frexp"] = "keyword",
["fwidth"] = "keyword",
["isfinite"] = "keyword",
["isinf"] = "keyword",
["isnan"] = "keyword",
["ldexp"] = "keyword",
["length"] = "keyword",
["lerp"] = "keyword",
["lit"] = "keyword",
["log"] = "keyword",
["log10"] = "keyword",
["log2"] = "keyword",
["mad"] = "keyword",
["max"] = "keyword",
["min"] = "keyword",
["modf"] = "keyword",
["msad4"] = "keyword",
["mul"] = "keyword",
["noise"] = "keyword",
["normalize"] = "keyword",
["pow"] = "keyword",
["printf"] = "keyword",
["radians"] = "keyword",
["rcp"] = "keyword",
["reflect"] = "keyword",
["refract"] = "keyword",
["reversebits"] = "keyword",
["round"] = "keyword",
["rsqrt"] = "keyword",
["saturate"] = "keyword",
["sign"] = "keyword",
["sin"] = "keyword",
["sincos"] = "keyword",
["sinh"] = "keyword",
["smoothstep"] = "keyword",
["sqrt"] = "keyword",
["step"] = "keyword",
["tan"] = "keyword",
["tanh"] = "keyword",
["transpose"] = "keyword",
["trunc"] = "keyword",
},
}
+48
View File
@@ -0,0 +1,48 @@
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "Haskell",
files = { "%.hs$" },
comment = "--",
block_comment = {"{-", "-}"},
patterns = {
{ pattern = "%-%-.*", type = "comment" },
{ pattern = { "{%-", "%-}" }, type = "comment" },
{ pattern = { '"', '"', '\\' }, type = "string" },
{ pattern = { "'", "'", '\\' }, type = "string" },
{ pattern = "-?0x%x+", type = "number" },
{ pattern = "-?%d+[%d%.eE]*f?", type = "number" },
{ pattern = "-?%.?%d+f?", type = "number" },
{ pattern = "[!%#%$%%&*+./%<=>%?@\\%^|%-~:]", type = "operator" },
{ pattern = "[%a_'][%w_']*", type = "symbol" },
},
symbols = {
["as"] = "keyword",
["case"] = "keyword",
["of"] = "keyword",
["class"] = "keyword",
["data"] = "keyword",
["default"] = "keyword",
["deriving"] = "keyword",
["do"] = "keyword",
["forall"] = "keyword",
["foreign"] = "keyword",
["hiding"] = "keyword",
["if"] = "keyword",
["then"] = "keyword",
["else"] = "keyword",
["import"] = "keyword",
["infix"] = "keyword",
["infixl"] = "keyword",
["infixr"] = "keyword",
["let"] = "keyword",
["in"] = "keyword",
["mdo"] = "keyword",
["module"] = "keyword",
["newtype"] = "keyword",
["qualified"] = "keyword",
["type"] = "keyword",
["where"] = "keyword",
},
}
+212
View File
@@ -0,0 +1,212 @@
-- mod-version:3
local syntax = require "core.syntax"
local keywords = {
"AcceptFilter", "AcceptMutex", "AcceptPathInfo", "AccessFileName", "Action", "AddAlt",
"AddAltByEncoding", "AddAltByType", "AddCharset", "AddDefaultCharset", "AddDescription",
"AddEncoding", "AddHandler", "AddIcon", "AddIconByType", "AddIconByEncoding", "AddIconByEncoding",
"AddIconByType", "AddInputFilter", "AddLanguage", "AddModuleInfo", "AddOutputFilterByType",
"AddOutputFilter", "AddOutputFilterByType", "AddType", "Alias", "ScriptAlias", "ServerAlias",
"AliasMatch", "Allow", "AllowOverride", "AllowEncodedSlashes", "_ROUTING__allow_GET",
"_ROUTING__allow_HEAD", "_ROUTING__allow_POST", "Allow", "AllowOverride", "AllowEncodedSlashes",
"AllowCONNECT", "AllowEncodedSlashes", "AllowMethods", "AllowOverride", "AllowOverrideList",
"Anonymous", "Anonymous_LogEmail", "Anonymous_NoUserID", "Anonymous_Authoritative",
"Anonymous_LogEmail", "Anonymous_MustGiveEmail", "Anonymous_NoUserId", "Anonymous_VerifyEmail",
"AssignUserID", "AsyncRequestWorkerFactor", "AuthAuthoritative", "AuthBasicAuthoritative",
"AuthBasicFake", "AuthBasicProvider", "AuthBasicUseDigestAlgorithm", "AuthDBDUserPWQuery",
"AuthDBDUserRealmQuery", "AuthDBMAuthoritative", "AuthDBMGroupFile", "AuthDBMType",
"AuthDBMUserFile", "AuthDefaultAuthoritative", "AuthDigestAlgorithm", "AuthDigestDomain",
"AuthDigestFile", "AuthDigestGroupFile", "AuthDigestNcCheck", "AuthDigestNonceFormat",
"AuthDigestNonceLifetime", "AuthDigestProvider", "AuthDigestQop", "AuthDigestShmemSize",
"AuthFormAuthoritative", "AuthFormBody", "AuthFormDisableNoStore", "AuthFormFakeBasicAuth",
"AuthFormLocation", "AuthFormLoginRequiredLocation", "AuthFormLoginSuccessLocation",
"AuthFormLogoutLocation", "AuthFormMethod", "AuthFormMimetype", "AuthFormPassword",
"AuthFormProvider", "AuthFormSitePassphrase", "AuthFormSize", "AuthFormUsername", "AuthGroupFile",
"AuthLDAPAuthoritative", "AuthLDAPAuthorizePrefix", "AuthLDAPAuthzEnabled",
"AuthLDAPBindAuthoritative", "AuthLDAPBindDN", "AuthLDAPBindPassword", "AuthLDAPCharsetConfig",
"AuthLDAPCompareAsUser", "AuthLDAPCompareDNOnServer", "AuthLDAPDereferenceAliases",
"AuthLDAPEnabled", "AuthLDAPFrontPageHack", "AuthLDAPGroupAttribute", "AuthLDAPGroupAttributeIsDN",
"AuthLDAPGroupAttributeIsDN", "AuthLDAPInitialBindAsUser", "AuthLDAPInitialBindPattern",
"AuthLDAPMaxSubGroupDepth", "AuthLDAPRemoteUserAttribute", "AuthLDAPRemoteUserIsDN",
"AuthLDAPSearchAsUser", "AuthLDAPSubGroupAttribute", "AuthLDAPSubGroupClass", "AuthLDAPURL",
"AuthMerging", "AuthName", "AuthnCacheContext", "AuthnCacheEnable", "AuthnCacheProvideFor",
"AuthnCacheProvider", "AuthnCacheSOCache", "AuthnCacheTimeout", "AuthnzFcgiCheckAuthnProvider",
"AuthnzFcgiDefineProvider", "AuthType", "AuthUserFile", "AuthzDBDLoginToReferer", "AuthzDBDQuery",
"AuthzDBDRedirectQuery", "AuthzDBMAuthoritative", "AuthzDBMType", "AuthzDefaultAuthoritative",
"AuthzGroupFileAuthoritative", "AuthzLDAPAuthoritative", "AuthzOwnerAuthoritative",
"AuthzSendForbiddenOnFailure", "AuthzUserAuthoritative", "BalancerGrowth", "BalancerInherit",
"BalancerMember", "BalancerNonce", "BalancerPersist", "BrowserMatch", "BrowserMatchNoCase",
"BrowserMatchNoCase", "BS2000Account", "BufferedLogs", "DeflateBufferSize", "BufferSize",
"CacheDefaultExpire", "CacheDetailHeader", "CacheDirLength", "CacheDirLevels", "CacheDisable",
"CacheEnable", "CacheExpiryCheck", "cachefile", "CacheForceCompletion", "CacheGcClean",
"CacheGcDaily", "CacheGcInterval", "CacheGcMemUsage", "CacheGcUnused", "CacheHeader",
"CacheIgnoreCacheControl", "CacheIgnoreHeaders", "CacheIgnoreNoLastMod", "CacheIgnoreQueryString",
"CacheIgnoreURLSessionIdentifiers", "CacheKeyBaseURL", "CacheLastModifiedFactor", "CacheLock",
"CacheLockMaxAge", "CacheLockPath", "CacheMaxExpire", "CacheMaxFileSize", "CacheMinExpire",
"CacheMinFileSize", "CacheNegotiatedDocs", "CacheQuickHandler", "CacheReadSize", "CacheReadTime",
"CacheRoot", "MCacheSize", "CacheSocache", "CacheSocacheMaxSize", "CacheSocacheMaxTime",
"CacheSocacheMinTime", "CacheSocacheReadSize", "CacheSocacheReadTime", "CacheStaleOnError",
"CacheStoreExpired", "CacheStoreNoStore", "CacheStorePrivate", "CacheTimeMargin", "CaseFilter",
"CaseFilterIn", "CGIDScriptTimeout", "CGIMapExtension", "CGIPassAuth", "CGIVar", "CharsetDefault",
"CharsetOptions", "CharsetSourceEnc", "CheckCaseOnly", "CheckSpelling", "ChildperUserID", "ChrootDir",
"ClientRecheckTime", "ContentDigest", "CookieDomain", "CookieExpires", "CookieLog", "CookieName",
"CookieStyle", "CookieTracking", "CoreDumpDirectory", "CustomLog", "DAV", "DAVDepthInfinity",
"DAVGenericLockDB", "DAVLockDB", "DAVMinTimeout", "DBDExptime", "DBDInitSQL", "DBDKeep", "DBDMax",
"DBDMin", "DBDParams", "DBDPersist", "DBDPrepareSQL", "DBDriver", "DefaultIcon", "DefaultLanguage",
"DefaultRuntimeDir", "DefaultType", "Define", "DeflateBufferSize", "DeflateCompressionLevel",
"DeflateFilterNote", "DeflateInflateLimitRequestBody", "DeflateInflateRatioBurst",
"DeflateInflateRatioLimit", "DeflateMemLevel", "DeflateWindowSize", "Deny", "Deny", "DirectoryIndex",
"DirectorySlash", "DirectoryCheckHandler", "DirectoryIndex", "DirectoryIndexRedirect", "DirectoryMatch",
"DirectorySlash", "VirtualDocumentRoot", "DocumentRoot", "DTracePrivileges", "DumpIOInput",
"DumpIOLogLevel", "DumpIOOutput", "EnableExceptionHook", "EnableMMAP", "EnableSendfile", "ErrorDocument",
"ErrorLog", "ErrorLogFormat", "ExpiresActive", "ExpiresByType", "ExpiresDefault", "ExtendedStatus",
"ExtFilterDefine", "ExtFilterOptions", "FallbackResource", "FancyIndexing", "FileETag", "Files",
"FilesMatch", "FilterChain", "FilterDeclare", "FilterProtocol", "FilterProvider", "FilterTrace",
"ForceLanguagePriority", "ForceType", "ForensicLog", "GlobalLog", "GprofDir", "AuthGroupFile", "Group",
"AuthDBMGroupFile", "AuthLDAPGroupAttribute", "AuthLDAPGroupAttributeIsDN", "AuthzGroupFileAuthoritative",
"H2AltSvc", "H2AltSvcMaxAge", "H2Direct", "H2MaxSessionStreams", "H2MaxWorkerIdleSeconds", "H2MaxWorkers",
"H2MinWorkers", "H2ModernTLSOnly", "H2Push", "H2PushDiarySize", "H2PushPriority", "H2SerializeHeaders",
"H2SessionExtraFiles", "H2StreamMaxMemSize", "H2TLSCoolDownSecs", "H2TLSWarmUpSize", "H2Upgrade",
"H2WindowSize", "Header", "RequestHeader", "HeaderName", "HeaderName", "HeartbeatAddress",
"HeartbeatListen", "HeartbeatMaxServers", "HeartbeatStorage", "HostnameLookups", "IdentityCheck",
"IdentityCheckTimeout", "IfDefine", "IfModule", "IfVersion", "ImapBase", "ImapDefault", "ImapMenu",
"Include", "IncludeOptional", "IndexHeadInsert", "IndexIgnore", "IndexIgnoreReset", "IndexOptions",
"IndexOrderDefault", "IndexStyleSheet", "InputSed", "ISAPIAppendLogToErrors", "ISAPIAppendLogToQuery",
"ISAPICacheFile", "ISAPIFakeAsync", "ISAPILogNotSupported", "ISAPIReadAheadBuffer", "KeepAlive",
"KeepAliveTimeout", "MaxKeepAliveRequests", "KeepAliveTimeout", "KeptBodySize", "LanguagePriority",
"ForceLanguagePriority", "LDAPCacheEntries", "LDAPCacheTTL", "LDAPConnectionPoolTTL",
"LDAPConnectionTimeout", "LDAPLibraryDebug", "LDAPOpCacheEntries", "LDAPOpCacheTTL", "LDAPReferralHopLimit",
"LDAPReferrals", "LDAPRetries", "LDAPRetryDelay", "LDAPSharedCacheFile", "LDAPSharedCacheSize",
"LDAPTimeout", "LDAPTrustedCA", "LDAPTrustedCAType", "LDAPTrustedClientCert", "LDAPTrustedGlobalCert",
"LDAPTrustedMode", "LDAPVerifyServerCert", "LimitRequestBody", "RLimitMEM", "LimitRequestFields",
"LimitRequestFieldSize", "LimitRequestLine", "LimitExcept", "LimitInternalRecursion", "LimitRequestBody",
"LimitRequestFields", "LimitRequestFieldsize", "LimitRequestLine", "LimitXMLRequestBody", "LoadFile",
"LoadModule", "Location", "LocationMatch", "LockFile", "LogFormat", "LogIOTrackTTFB", "RewriteLogLevel",
"LogLevel", "LogMessage", "LuaAuthzProvider", "Lua_____ByteCodeHack", "LuaCodeCache", "LuaHookAccessChecker",
"LuaHookAuthChecker", "LuaHookCheckUserID", "LuaHookFixups", "LuaHookInsertFilter", "LuaHookLog",
"LuaHookMapToStorage", "LuaHookTranslateName", "LuaHookTypeChecker", "LuaInherit", "LuaInputFilter",
"LuaMapHandler", "LuaOutputFilter", "LuaPackageCPath", "LuaPackagePath", "LuaQuickHandler", "LuaRoot",
"LuaScope", "MaxClientConnections", "MaxClients", "MaxConnectionsPerChild", "MaxKeepAliveRequests",
"MaxMemFree", "MaxRangeOverlaps", "MaxRangeReversals", "MaxRanges", "MaxRequestsPerChild",
"MaxRequestsPerThread", "MaxRequestWorkers", "MaxSpareServers", "MaxSpareThreads", "MaxThreads",
"MaxThreadsPerChild", "MCacheMaxObjectCount", "MCacheMaxObjectSize", "MCacheMaxStreamingBuffer",
"MCacheMinObjectSize", "MCacheRemovalAlgorithm", "MCacheSize", "MemcacheConnTTL", "MergeTrailers",
"MetaDir", "MetaFiles", "MetaSuffix", "MimeMagicFile", "MinSpareServers", "MinSpareThreads", "mmapfile",
"ModemStandard", "ModMimeUsePathInfo", "MultiviewsMatch", "Mutex", "NameVirtualHost", "NoProxy",
"NumServers", "NWSSLTrustedCerts", "NWSSLUpgradeable", "Options", "RewriteOptions", "IndexOptions",
"Order", "IndexOrderDefault", "Order", "IndexOrderDefault", "OutputSed", "PassEnv", "php_admin_flag",
"php_admin_value", "php_flag", "php_value", "PidFile", "Port", "PrivilegesMode", "FilterProtocol",
"Protocol", "ProtocolEcho", "Protocols", "ProtocolsHonorOrder", "ProxyPass", "ProxyPassMatch",
"ProxyPassReverse", "ProxyRequests", "ProxyAddHeaders", "ProxyBadHeader", "ProxyBlock", "ProxyDomain",
"ProxyErrorOverride", "ProxyExpressDBMFile", "ProxyExpressDBMType", "ProxyExpressEnable",
"ProxyFtpDirCharset", "ProxyFtpEscapeWildcards", "ProxyFtpListOnWildcard", "ProxyHCExpr", "ProxyHCTemplate",
"ProxyHCTPsize", "ProxyHTMLBufSize", "ProxyHTMLCharsetOut", "ProxyHTMLDoctype", "ProxyHTMLEnable",
"ProxyHTMLEvents", "ProxyHTMLExtended", "ProxyHTMLFixups", "ProxyHTMLInterp", "ProxyHTMLLinks",
"ProxyHTMLMeta", "ProxyHTMLStripComments", "ProxyHTMLURLMap", "ProxyIOBufferSize", "ProxyMatch",
"ProxyMaxForwards", "ProxyPass", "ProxyPassMatch", "ProxyPassReverse", "ProxyPassInherit",
"ProxyPassInterpolateEnv", "ProxyPassMatch", "ProxyPassReverse", "ProxyPassReverseCookieDomain",
"ProxyPassReverseCookiePath", "ProxyPreserveHost", "ProxyReceiveBufferSize", "ProxyRemote",
"ProxyRemoteMatch", "ProxyRequests", "ProxySCGIInternalRedirect", "ProxySCGISendfile", "ProxySet",
"ProxySourceAddress", "ProxyStatus", "ProxyTimeout", "ProxyVia", "QualifyRedirectURL", "ReadmeName",
"Redirect", "RedirectMatch", "RedirectTemp", "RedirectPermanent", "RedirectMatch", "RedirectPermanent",
"RedirectTemp", "ReflectorHeader", "RemoteIPHeader", "RemoteIPInternalProxy", "RemoteIPInternalProxyList",
"RemoteIPProxiesHeader", "RemoteIPTrustedProxy", "RemoteIPTrustedProxyList", "RemoveCharset",
"RemoveEncoding", "RemoveHandler", "RemoveInputFilter", "RemoveLanguage", "RemoveOutputFilter", "RemoveType",
"RequestHeader", "RequestReadTimeout", "RequestTimeout", "Require", "RewriteBase", "RewriteCond",
"RewriteEngine", "RewriteLock", "RewriteLog", "RewriteLogLevel", "RewriteLogLevel", "RewriteMap",
"RewriteOptions", "RewriteRule", "RLimitCPU", "RLimitMEM", "RLimitNPROC", "Satisfy", "ScoreboardFile",
"ScoreBoardFile", "Script", "ScriptAlias", "ScriptAlias", "ScriptAliasMatch", "ScriptInterpreterSource",
"ScriptLog", "ScriptLogBuffer", "ScriptLogLength", "Scriptsock", "ScriptSock", "SecureListen",
"SeeRequestTail", "SerfCluster", "SerfPass", "ServerAdmin", "ServerAlias", "ServerLimit", "ServerName",
"ServerPath", "ServerRoot", "ServerSignature", "ServerTokens", "Session", "SessionCookieName",
"SessionCookieName2", "SessionCookieRemove", "SessionCryptoCipher", "SessionCryptoDriver",
"SessionCryptoPassphrase", "SessionCryptoPassphraseFile", "SessionDBDCookieName", "SessionDBDCookieName2",
"SessionDBDCookieRemove", "SessionDBDDeleteLabel", "SessionDBDInsertLabel", "SessionDBDPerUser",
"SessionDBDSelectLabel", "SessionDBDUpdateLabel", "SessionEnv", "SessionExclude", "SessionHeader",
"SessionInclude", "SessionMaxAge", "SetEnvIfNoCase", "SetEnv", "SetEnvIf", "SetEnvIfNoCase", "SetEnvIf",
"SetEnvIfExpr", "SetEnvIfNoCase", "SetHandler", "SetInputFilter", "SetOutputFilter", "SimpleProcCount",
"SimpleThreadCount", "SSIAccessEnable", "SSIEndTag", "SSIErrorMsg", "SSIEtag", "SSILastModified",
"SSILegacyExprParser", "SSIStartTag", "SSITimeFormat", "SSIUndefinedEcho", "SSLLog", "SSLLogLevel",
"StartServers", "StartThreads", "Substitute", "SubstituteInheritBefore", "SubstituteMaxLineLength",
"Suexec", "SuexecUserGroup", "ThreadLimit", "ThreadsPerChild", "ThreadStackSize", "KeepAliveTimeout",
"AuthnCacheTimeout", "TraceEnable", "TransferLog", "TrustedProxy", "TypesConfig", "UnDefine", "UnsetEnv",
"UseCanonicalName", "UseCanonicalPhysicalPort", "User", "AuthUserFile", "UserDir", "AuthDBMUserFile",
"Anonymous_NoUserID", "UserDir", "VHostCGIMode", "VHostCGIPrivs", "VHostGroup", "VHostPrivs", "VHostSecure",
"VHostUser", "VirtualDocumentRoot", "VirtualDocumentRootIP", "VirtualHost", "VirtualScriptAlias",
"VirtualScriptAliasIP", "Win32DisableAcceptEx", "XBitHack", "xml2EncAlias", "xml2EncDefault",
"xml2StartParse", "SecFilterEngine", "from", "SSLOptions", "SSLRequireSSL", "SSLRequire"
}
local literals = {
"on", "off", "deny", "denied", "all", "allow", "basic", "valid-user", "append", "unset", "set", "eq",
"any", "email"
}
local symbols = {}
for _,lt in ipairs(literals) do
symbols[lt] = "literal"
symbols[lt:gsub("%f[%w]%l", string.upper)] = "literal"
end
for _,kw in ipairs(keywords) do
symbols[kw] = "keyword"
end
local url_syntax = {
patterns = {
{ pattern = "[%%$]%d+", type = "keyword2" },
{ pattern = "[%%$]%{[%w_:%-]+%}", type = "keyword2" },
{ pattern = "[^%%$%s]", type = "string" }
},
symbols = {}
}
local xml_syntax = {
patterns = {{ pattern = { '"', '"', '\\' }, type = "string" }},
symbols = {}
}
syntax.add {
name = ".htaccess File",
files = { PATHSEP .. "^%.htaccess$" },
comment = "#",
patterns = {
-- Comments
{ pattern = "#.*\n", type = "comment" },
-- Strings
{ pattern = { '"', '"', '\\' }, type = "string" },
{ pattern = { "'", "'", '\\' }, type = "string" },
{ pattern = { '`', '`', '\\' }, type = "string" },
-- URLs
{ pattern = { "%w-://", "%f[%s]" }, type = "string", syntax = url_syntax },
{ pattern = { "%f[%S]/", "%f[%s]" }, type = "string", syntax = url_syntax },
-- Mime types
{ pattern = "%f[%w]application/[%w%._+-]+", type = "keyword2" },
{ pattern = "%f[%w]font/[%w%._+-]+", type = "keyword2" },
{ pattern = "%f[%w]image/[%w%._+-]+", type = "keyword2" },
{ pattern = "%f[%w]text/[%w%._+-]+", type = "keyword2" },
{ pattern = "%f[%w]audio/[%w%._+-]+", type = "keyword2" },
{ pattern = "%f[%w]video/[%w%._+-]+", type = "keyword2" },
-- IPs
{ pattern = "%d+%.%d+%.%d+%.%d+", type = "keyword2" },
{ pattern = "%d+%.%d+%.%d+%.%d+/%d+", type = "keyword2" },
{ regex = "([a-f0-9:]+:+)+[a-f0-9]+", type = "keyword2" },
-- Emails
{ pattern = "%w+@%w+%.%w+", type = "keyword2" },
-- Rewrite option sections
{ pattern = "%f[%S]%b[]", type = "number" },
-- XML tags
{ pattern = { "</?%w+", ">" }, type = "literal", syntax = xml_syntax },
-- Variables
{ pattern = "[%%$]%d+", type = "keyword2" },
{ pattern = "[%%$]%{[%w_:%-]+%}", type = "keyword2" },
-- Numbers
{ pattern = "A?%d+", type = "number" },
-- Operators
{ pattern = "%f[%S][!=+%-]+", type = "operator" },
-- Regex (TODO: improve this, it's pretty naive and only works on some regex)
{ pattern = "%f[^%s!]%^%S*", type = "literal" },
{ pattern = "%f[^%s!]%S*%$", type = "literal" },
{ pattern = "%f[^%s!]%b()", type = "literal" },
-- Everything else
{ pattern = "[%a_][%w_-]*", type = "symbol" },
},
symbols = symbols
}
+20
View File
@@ -0,0 +1,20 @@
-- mod-version:3
local syntax = require "core.syntax"
local style = require "core.style"
local common = require "core.common"
style.syntax["ignore"] = { common.color "#72B886" }
style.syntax["exclude"] = { common.color "#F36161" }
syntax.add {
name = ".ignore file",
files = { PATHSEP .. "%..*ignore$" },
comment = "#",
patterns = {
{ regex = "^ *#.*$", type = "comment" },
{ regex = { "(?=^ *!.)", "$" }, type = "ignore" },
{ regex = { "(?=.)", "$" }, type = "exclude" },
},
symbols = {}
}
+27
View File
@@ -0,0 +1,27 @@
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "INI",
files = { "%.ini$", "%.inf$", "%.cfg$", PATHSEP .. "%.editorconfig$", "%.theme$", "%.dockitem$", "%.desktop$" },
comment = ';',
patterns = {
{ pattern = ";.*", type = "comment" },
{ pattern = "#.*", type = "comment" },
{ pattern = { "%[", "%]" }, type = "keyword" },
{ pattern = { '"""', '"""', '\\' }, type = "string" },
{ pattern = { '"', '"', '\\' }, type = "string" },
{ pattern = { "'''", "'''" }, type = "string" },
{ pattern = { "'", "'" }, type = "string" },
{ pattern = "[A-Za-z0-9_%.%-]+%s*%f[=]", type = "function" },
{ pattern = "[%-+]?[0-9_]+%.[0-9_]+", type = "number" },
{ pattern = "[%-+]?[0-9_]+", type = "number" },
{ pattern = "[a-z]+", type = "symbol" },
},
symbols = {
["true"] = "literal",
["false"] = "literal",
},
}
+87
View File
@@ -0,0 +1,87 @@
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "Java",
files = { "%.java$" },
comment = "//",
patterns = {
{ pattern = "//.*", type = "comment" },
{ pattern = { "/%*", "%*/" }, type = "comment" },
{ pattern = { '"', '"', '\\' }, type = "string" },
{ pattern = { "'", "'", '\\' }, type = "string" },
{ pattern = "'\\x%x?%x?%x?%x'", type = "string" }, -- character hexadecimal escape sequence
{ pattern = "'\\u%x%x%x%x'", type = "string" }, -- character unicode escape sequence
{ pattern = "'\\?.'", type = "string" }, -- character literal
{ pattern = "-?0x%x+", type = "number" },
{ pattern = "-?%d+[%d%.eE]*f?", type = "number" },
{ pattern = "-?%.?%d+f?", type = "number" },
{ pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" },
{ pattern = "[%a_][%w_]*%f[(]", type = "function" },
{ regex = "(?>\\w+\\.?)+(?=\\s+\\w++\\s*\\=\\s*)", type = "function" }, -- Class name when creating an object
{ regex = "[A-Z][A-Z_]+", type = "keyword2" }, -- Constants
{ pattern = "[%a_][%w_]*", type = "symbol" },
},
symbols = {
["abstract"] = "keyword",
["assert"] = "keyword",
["break"] = "keyword",
["case"] = "keyword",
["catch"] = "keyword",
["class"] = "keyword",
["const"] = "keyword",
["continue"] = "keyword",
["default"] = "keyword",
["do"] = "keyword",
["else"] = "keyword",
["enum"] = "keyword",
["extends"] = "keyword",
["final"] = "keyword",
["finally"] = "keyword",
["for"] = "keyword",
["if"] = "keyword",
["goto"] = "keyword",
["implements"] = "keyword",
["import"] = "keyword",
["instanceof"] = "keyword",
["interface"] = "keyword",
["native"] = "keyword",
["new"] = "keyword",
["package"] = "keyword",
["permits"] = "keyword",
["private"] = "keyword",
["protected"] = "keyword",
["public"] = "keyword",
["record"] = "keyword",
["return"] = "keyword",
["sealed"] = "keyword",
["static"] = "keyword",
["strictfp"] = "keyword",
["super"] = "keyword",
["switch"] = "keyword",
["synchronized"] = "keyword",
["this"] = "keyword",
["throw"] = "keyword",
["throws"] = "keyword",
["transient"] = "keyword",
["try"] = "keyword",
["var"] = "keyword",
["void"] = "keyword",
["volatile"] = "keyword",
["while"] = "keyword",
["yield"] = "keyword",
["boolean"] = "keyword2",
["byte"] = "keyword2",
["char"] = "keyword2",
["double"] = "keyword2",
["float"] = "keyword2",
["int"] = "keyword2",
["long"] = "keyword2",
["short"] = "keyword2",
["true"] = "literal",
["false"] = "literal",
["null"] = "literal"
}
}
+93
View File
@@ -0,0 +1,93 @@
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "Jiyu",
files = { "%.jiyu$", "%.jyu$" },
comment = "//",
patterns = {
{ pattern = "//.-\n", type = "comment" },
{ pattern = { "/%*", "%*/" }, type = "comment" },
{ pattern = { "\"\"\"", "\"\"\"" }, type = "string" },
{ pattern = { '"', '"', '\\' }, type = "string" },
{ pattern = { "'", "'", '\\' }, type = "string" },
{ pattern = "0b[0-1]+", type = "number" },
{ pattern = "0x[%da-fA-F]+", type = "number" },
{ pattern = "-?%d+[%d%.]*", type = "number" },
{ pattern = "-?%.?%d+?", type = "number" },
{ pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" },
{ pattern = "[<>~=+-*/]=", type = "operator" },
{ pattern = "[..]", type = "operator" },
{ pattern = "[%a_][%w_]*%f[(]", type = "function" },
{ pattern = "[#@]?[%a_][%w_]*", type = "symbol" },
},
symbols = {
-- Keywords
["func"] = "keyword",
["if"] = "keyword",
["else"] = "keyword",
["for"] = "keyword",
["while"] = "keyword",
["defer"] = "keyword",
["return"] = "keyword",
["switch"] = "keyword",
["case"] = "keyword",
["break"] = "keyword",
["continue"] = "keyword",
["fallthrough"] = "keyword",
["struct"] = "keyword",
["union"] = "keyword",
["enum"] = "keyword",
["using"] = "keyword",
["var"] = "keyword",
["let"] = "keyword",
["typealias"] = "keyword",
["library"] = "keyword",
["framework"] = "keyword",
["temporary_c_vararg"] = "keyword2";
-- Builtin procedures and directives
["cast"] = "keyword2",
["sizeof"] = "keyword2",
["alignof"] = "keyword2",
["strideof"] = "keyword2",
["offsetof"] = "keyword2",
["type_of"] = "keyword2",
["type_info"] = "keyword2",
["#if"] = "keyword2",
["#load"] = "keyword2",
["#import"] = "keyword2",
["#clang_import"] = "keyword2",
["#file"] = "keyword2",
["#filepath"] = "keyword2",
["#line"] = "keyword2",
["@c_function"] = "keyword2",
["@export"] = "keyword2",
["@flags"] = "keyword2",
["@metaprogram"] = "keyword2",
-- Types
["string"] = "keyword2",
["int"] = "keyword2",
["uint"] = "keyword2",
["uint8"] = "keyword2",
["uint16"] = "keyword2",
["uint32"] = "keyword2",
["uint64"] = "keyword2",
["uint128"] = "keyword2",
["int8"] = "keyword2",
["int16"] = "keyword2",
["int32"] = "keyword2",
["int64"] = "keyword2",
["int128"] = "keyword2",
["float"] = "keyword2",
["double"] = "keyword2",
["void"] = "keyword2",
["bool"] = "keyword2",
["Type"] = "keyword2",
-- Literals
["true"] = "literal",
["false"] = "literal",
["null"] = "literal",
}
}
+34
View File
@@ -0,0 +1,34 @@
-- mod-version:3 priority:110
local syntax = require "core.syntax"
syntax.add {
name = "JSON",
files = {
"%.json$",
"%.cjson$",
"%.jsonc$",
"%.ipynb$",
},
comment = "//",
block_comment = {"/*", "*/"},
patterns = {
-- cjson support
{ pattern = "//.*", type = "comment" },
{ pattern = { "/%*", "%*/" }, type = "comment" },
{ regex = [["(?:[^"\\]|\\.)*"()\s*:]], type = { "keyword", "normal" } }, -- key
{ regex = [["(?:[^"\\]|\\.)*"]], type = "string" }, -- value
{ pattern = "0x[%da-fA-F]+", type = "number" },
{ pattern = "-?%d+[%d%.eE]*", type = "number" },
{ pattern = "-?%.?%d+", type = "number" },
{ pattern = "null", type = "literal" },
{ pattern = "true", type = "literal" },
{ pattern = "false", type = "literal" }
},
symbols = { }
}
+73
View File
@@ -0,0 +1,73 @@
-- mod-version:3
-- Almost identical to JS, with the exception that / shouldn't denote a regex. Current JS syntax highlighter will highlight half the document due to closing tags.
local syntax = require "core.syntax"
syntax.add {
name = "JSX",
files = { "%.jsx$", "%.astro$" },
comment = "//",
block_comment = { "/*", "*/" },
patterns = {
{ pattern = "//.*", type = "comment" },
{ pattern = { "/%*", "%*/" }, type = "comment" },
{ pattern = { '"', '"', '\\' }, type = "string" },
{ pattern = { "'", "'", '\\' }, type = "string" },
{ pattern = { "`", "`", '\\' }, type = "string" },
{ pattern = "0x[%da-fA-F]+", type = "number" },
{ pattern = "-?%d+[%d%.eE]*", type = "number" },
{ pattern = "-?%.?%d+", type = "number" },
{ pattern = "%f[^<]/?[%a_][%w_]*", type = "function" },
{ pattern = "[%a_][%w_]*%f[(]", type = "function" },
{ pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" },
{ pattern = "[%a_][%w_]*", type = "symbol" },
},
symbols = {
["async"] = "keyword",
["await"] = "keyword",
["break"] = "keyword",
["case"] = "keyword",
["catch"] = "keyword",
["class"] = "keyword",
["const"] = "keyword",
["continue"] = "keyword",
["debugger"] = "keyword",
["default"] = "keyword",
["delete"] = "keyword",
["do"] = "keyword",
["else"] = "keyword",
["export"] = "keyword",
["extends"] = "keyword",
["finally"] = "keyword",
["for"] = "keyword",
["from"] = "keyword",
["function"] = "keyword",
["get"] = "keyword",
["if"] = "keyword",
["import"] = "keyword",
["in"] = "keyword",
["instanceof"] = "keyword",
["let"] = "keyword",
["new"] = "keyword",
["return"] = "keyword",
["set"] = "keyword",
["static"] = "keyword",
["super"] = "keyword",
["switch"] = "keyword",
["throw"] = "keyword",
["try"] = "keyword",
["typeof"] = "keyword",
["var"] = "keyword",
["void"] = "keyword",
["while"] = "keyword",
["with"] = "keyword",
["yield"] = "keyword",
["true"] = "literal",
["false"] = "literal",
["null"] = "literal",
["undefined"] = "literal",
["arguments"] = "keyword2",
["Infinity"] = "keyword2",
["NaN"] = "keyword2",
["this"] = "keyword2",
},
}
+112
View File
@@ -0,0 +1,112 @@
-- mod-version:3
-- Support for the Julia programming language:
-- Covers the most used keywords up to Julia version 1.6.4
local syntax = require "core.syntax"
syntax.add {
name = "Julia",
files = { "%.jl$" },
comment = "#",
patterns = {
{pattern = {"#=", "=#"}, type="comment" },
{pattern = "#.*$", type="comment" },
{ pattern = { 'icxx"""', '"""' }, type = "string", syntax = ".cpp" },
{ pattern = { 'cxx"""', '"""' }, type = "string", syntax = ".cpp" },
{ pattern = { 'py"""', '"""' }, type = "string", syntax = ".py" },
{ pattern = { 'js"""', '"""' }, type = "string", syntax = ".js" },
{ pattern = { 'md"""', '"""' }, type = "string", syntax = ".md" },
{ pattern = "%d%w*[%.-+*//]", type = "number" },
{ pattern = "0[oO_][0-7]+", type = "number" },
{ pattern = "-?0x[%x_]+", type = "number" },
{ pattern = "-?0b[%x_]+", type = "number" },
{ pattern = "-?%d+_%d", type = "number" },
{ pattern = "-?%d+[%d%.eE]*f?", type = "number" },
{ pattern = "-?%.?%d+f?", type = "number" },
{ pattern = "[^%d%g]%:%a*", type = "function" },
{ pattern = "[%+%-=/%*%^%%<>!~|&%:]",type = "operator"},
{ pattern = '""".*"""', type = "string" },
{ pattern = '".*"', type = "string" },
{ pattern = '[bv]".*"', type = "string" },
{ pattern = 'r".*$', type = "string" },
{ pattern = "'\\.*'", type = "string" },
{ pattern = "'.'", type = "string" },
{ pattern = "[%a_][%w_]*%f[(]", type = "function" },
{ pattern = "%g*!", type="function"},
{ pattern = "[%a_][%w_]*", type = "symbol" },
},
symbols = {
-- keywords
["baremodule"] = "keyword",
["begin"] = "keyword",
["break"] = "keyword",
["catch"] = "keyword",
["const"] = "keyword",
["continue"] = "keyword",
["do"] = "keyword",
["Dict"] = "keyword",
["Set"] = "keyword",
["Union"] = "keyword",
["else"] = "keyword",
["elseif"] = "keyword",
["end"] = "keyword",
["export"] = "keyword",
["finally"] = "keyword",
["for"] = "keyword",
["function"] = "keyword",
["global"] = "keyword",
["if"] = "keyword",
["in"] = "keyword",
["import"] = "keyword",
["let"] = "keyword",
["local"] = "keyword",
["macro"] = "keyword",
["type"] = "keyword",
["module"] = "keyword",
["mutable"] = "keyword",
["quote"] = "keyword",
["return"] = "keyword",
["try"] = "keyword",
["typeof"] = "keyword",
["using"] = "keyword",
["while"] = "keyword",
["where"] = "keyword",
-- types
["struct"] = "keyword2",
["abstract"] = "keyword2",
["primitive"] = "keyword2",
["mutable"] = "keyword2",
["Char"] = "keyword2",
["Bool"] = "keyword2",
["Int"] = "keyword2",
["Integer"] = "keyword2",
["Int8"] = "keyword2",
["UInt8"] = "keyword2",
["Int16"] = "keyword2",
["UInt16"] = "keyword2",
["Int32"] = "keyword2",
["UInt32"] = "keyword2",
["Int64"] = "keyword2",
["UInt64"] = "keyword2",
["Int128"] = "keyword2",
["UInt128"] = "keyword2",
["Float16"] = "keyword2",
["Float32"] = "keyword2",
["Float64"] = "keyword2",
["Vector"] = "keyword2",
["Matrix"] = "keyword2",
["Ref"] = "keyword2",
["String"] = "keyword2",
["Function"] = "keyword2",
["Number"] = "keyword2",
-- literals
["missing"] = "literal",
["true"] = "literal",
["false"] = "literal",
["nothing"] = "literal",
["Inf"] = "literal",
["NaN"] = "literal",
}
}
+84
View File
@@ -0,0 +1,84 @@
-- mod-version:3
local syntax = require "core.syntax"
local identifier = "\"?[^%d%s\\/%(%){}<>;%[%]=,\"][^%s\\/%(%){}<>;%[%]=,\"]*\"?"
syntax.add {
name = "KDL",
files = { "%.kdl" },
space_handling = false,
comment = "//",
block_comment = {"/*", "*/"},
patterns = {
{
pattern = "^%s*".. identifier .."%s*",
type = "keyword"
},--
{ pattern = "%s+", type = "normal" },
{
pattern = "[{;]%s*()" .. identifier .. "%s*",
type = {"normal", "keyword"}
},--
{ pattern = { "r#+\"", "\"#+" }, type = "string" },
{ pattern = { '"', '"', '\\' }, type = "string" },
{ pattern = "[%-+]?0x[%x_]+", type = "number" },
{ pattern = "[%-+]?0b[01_]+", type = "number" },
{ pattern = "[%-+]?0o[0-7_]+", type = "number" },
{
pattern = "[%-+]?[%d_]+%.[%d_]+e[%-+]?[%d_]+",
type = "number"
},
{ pattern = "[%-+]?[%d_]+%.[%d_]+", type = "number" },
{ pattern = "[%-+]?[%d_]+e[%-+]?[%d_]+", type = "number" },
{ pattern = "[%-+]?[%d_]+", type = "number" },
{ pattern = "/[%-/].-\n", type = "comment" },
{ pattern = {"/%*", "%*/"}, type = "comment" },
{ pattern = identifier, type = "keyword2" },
{
pattern = "%(()" .. identifier .. "()%)",
type = {"normal", "function", "normal"}
},
},
symbols = {
["null"] = "literal",
["true"] = "literal",
["false"] = "literal",
["i8"] = "function",
["i32"] = "function",
["i16"] = "function",
["i64"] = "function",
["u8"] = "function",
["u32"] = "function",
["u16"] = "function",
["u64"] = "function",
["isize"] = "function",
["usize"] = "function",
["f32"] = "function",
["f64"] = "function",
["decimal64"] = "function",
["decimal128"] = "function",
["date-time"] = "function",
["time"] = "function",
["date"] = "function",
["duration"] = "function",
["decimal"] = "function",
["currency"] = "function",
["country-2"] = "function",
["country-3"] = "function",
["country-subdivision"] = "function",
["email"] = "function",
["idn-email"] = "function",
["hostname"] = "function",
["idn-hostname"] = "function",
["ipv4"] = "function",
["ipv6"] = "function",
["url"] = "function",
["url-reference"] = "function",
["irl"] = "function",
["irl-reference"] = "function",
["url-template"] = "function",
["uuid"] = "function",
["regex"] = "function",
["base64"] = "function",
},
}
+124
View File
@@ -0,0 +1,124 @@
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "Kotlin",
files = { "%.kt$" },
comment = "//",
block_comment = { "/*", "*/" },
patterns = {
{ pattern = "//.*", type = "comment" }, -- Comment, single-line
{ pattern = { "/%*", "%*/" }, type = "comment" }, -- Comment, multi-line
{ pattern = { '"', '"', '\\' }, type = "string" }, -- String, quotation marks
{ pattern = { "'", "'", '\\' }, type = "string" }, -- String, apices
{ pattern = "'\\x%x?%x?%x?%x'", type = "string" }, -- Character hexadecimal escape sequence
{ pattern = "'\\u%x%x%x%x'", type = "string" }, -- Character unicode escape sequence
{ pattern = "'\\?.'", type = "string" }, -- Character literal
{ pattern = "-?0x%x+", type = "number" }, -- ?
{ pattern = "-?%d+[%deE]*f?", type = "number" }, -- ?
{ pattern = "-?%.?%d+f?", type = "number" }, -- ?
{ regex = [[\-\>(?=\s)]], type = "operator" }, -- Lambda
{ regex = [[\.{2}\<?\s?(?=[\\-]?[a-z0-9])]], type = "operator" }, -- Range operators
{ pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" }, -- Operators
{ regex = [[\?(?=\.)]], type = "operator" }, -- ?. operator
{ pattern = "[%a_][%w_]*%f[(]", type = "function" }, -- Function/Method/Class
{ regex = "`[\\w_\\s]+`(?=\\s*\\()", type = "function" }, -- Test Method
{ regex = [[let(?=\s\{)]], type = "function" }, -- ? operator
{ regex = [[\?\:(?=\s?)]], type = "operator" }, -- elvis operator
{ regex = [[this(?=\.?\@?)]], type = "keyword" }, -- this keyword
{ regex = "\\@\\w+", type = "keyword2" }, -- Annotations
{ regex = [[[a-zA-Z]+\@(?=\s?[a-zA-Z])]], type = "keyword2" }, -- Annotations (this pattern is lower priority than the `this keyword` pattern)
{ regex = "[A-Z][A-Z_]+", type = "keyword2" }, -- Constants, FULL UPPERCASE
{ pattern = "import()%s+()[%w_.]+", type = { "keyword", "normal", "normal" } },
{ pattern = "[%a_][%w_]*", type = "symbol" }, -- ?
},
symbols = {
-- Hard keywords
["as"] = "keyword",
["break"] = "keyword",
["class"] = "keyword",
["continue"] = "keyword",
["do"] = "keyword",
["else"] = "keyword",
["for"] = "keyword",
["fun"] = "keyword",
["if"] = "keyword",
["in"] = "keyword",
["!in"] = "keyword",
["interface"] = "keyword",
["is"] = "keyword",
["!is"] = "keyword",
["object"] = "keyword",
["package"] = "keyword",
["return"] = "keyword",
["super"] = "keyword",
["this"] = "keyword",
["throw"] = "keyword",
["try"] = "keyword",
["typealias"] = "keyword",
["typeof"] = "keyword",
["val"] = "keyword",
["var"] = "keyword",
["when"] = "keyword",
["while"] = "keyword",
-- Soft keywords
["by"] = "keyword",
["catch"] = "keyword",
["constructor"] = "keyword",
["delegate"] = "keyword",
["dynamic"] = "keyword",
["field"] = "keyword",
["file"] = "keyword",
["finally"] = "keyword",
["get"] = "keyword",
["import"] = "keyword",
["init"] = "keyword",
["param"] = "keyword",
["property"] = "keyword",
["receiver"] = "keyword",
["set"] = "keyword",
["setparam"] = "keyword",
["value"] = "keyword",
["where"] = "keyword",
-- Modifier keywords
["abstract"] = "keyword",
["actual"] = "keyword",
["annotation"] = "keyword",
["companion"] = "keyword",
["const"] = "keyword",
["crossinline"] = "keyword",
["data"] = "keyword",
["enum"] = "keyword",
["expect"] = "keyword",
["external"] = "keyword",
["final"] = "keyword",
["inline"] = "keyword",
["inner"] = "keyword",
["infix"] = "keyword",
["internal"] = "keyword",
["lateinit"] = "keyword",
["noinline"] = "keyword",
["open"] = "keyword",
["operator"] = "keyword",
["out"] = "keyword",
["override"] = "keyword",
["private"] = "keyword",
["protected"] = "keyword",
["public"] = "keyword",
["reified"] = "keyword",
["sealed"] = "keyword",
["suspend"] = "keyword",
["tailrec"] = "keyword",
["vararg"] = "keyword",
-- Special identifiers
["it"] = "keyword",
-- Boolean
["true"] = "literal",
["false"] = "literal",
["null"] = "literal",
},
}
+22
View File
@@ -0,0 +1,22 @@
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "LilyPond",
files = { "%.i?ly$" },
comment = "%%",
block_comment = { "%%{", "%%}" },
patterns = {
{ pattern = "#%(()[%a_]%S*", type = { "operator", "function" } },
{ pattern = {"%%{", "%%}"}, type = "comment" },
{ pattern = "%%.*", type = "comment" },
{ pattern = "#[%w_-]*", type = "keyword2" },
{ pattern = "\\%a%w+", type = "keyword" },
{ pattern = "\\\\", type = "operator" },
{ pattern = "[%(%){}%[%]<>=/~%-%_']", type = "operator" },
{ pattern = {'"', '"', "\\"}, type = "string" },
{ pattern = "-?%.?%d+", type = "number" },
},
symbols = {}
}
+145
View File
@@ -0,0 +1,145 @@
-- mod-version:3
local syntax = require "core.syntax"
local liquid_syntax = {
patterns = {
{ pattern = { '"', '"', '\\' }, type = "string" },
{ pattern = { "'", "'", '\\' }, type = "string" },
{ pattern = "-?%d+[%d%.]*f?", type = "number" },
{ pattern = "-?%.?%d+f?", type = "number" },
{ pattern = "%w+", type = "symbol" },
},
symbols = {
["abs"] = "keyword2",
["and"] = "operator",
["append"] = "keyword2",
["assign"] = "keyword",
["at_least"] = "keyword2",
["at_most"] = "keyword2",
["break"] = "keyword",
["camelcase"] = "keyword2",
["capitalize"] = "keyword2",
["capture"] = "keyword",
["endcapture"] = "keyword",
["case"] = "keyword",
["ceil"] = "keyword2",
["comment"] = "keyword",
["endcomment"] = "keyword",
["concat"] = "keyword2",
["contains"] = "operator",
["cycle"] = "keyword",
["date"] = "keyword2",
["decrement"] = "keyword",
["default"] = "keyword2",
["divided_by"] = "keyword2",
["downcase"] = "keyword2",
["else"] = "keyword",
["elsif"] = "keyword",
["false"] = "literal",
["first"] = "keyword2",
["floor"] = "keyword2",
["for"] = "keyword",
["endfor"] = "keyword",
["forloop"] = "literal",
["handleize"] = "keyword2",
["handle"] = "keyword2",
["if"] = "keyword",
["endif"] = "keyword",
["increment"] = "keyword",
["index0"] = "literal",
["index"] = "literal",
["in"] = "operator",
["join"] = "keyword2",
["last"] = "keyword2",
["length"] = "literal",
["limit"] = "keyword",
["lstrip"] = "keyword",
["map"] = "keyword2",
["minus"] = "keyword2",
["modulo"] = "keyword2",
["nil"] = "literal",
["null"] = "literal",
["offset"] = "keyword2",
["or"] = "operator",
["pluralize"] = "keyword2",
["plus"] = "keyword2",
["prepend"] = "keyword2",
["raw"] = "keyword",
["endraw"] = "keyword",
["removefirst"] = "keyword2",
["remove"] = "keyword2",
["replacefirst"] = "keyword2",
["replace"] = "keyword2",
["reversed"] = "operator",
["reverse"] = "keyword2",
["rindex0"] = "literal",
["rindex"] = "literal",
["round"] = "keyword2",
["rstrip"] = "keyword2",
["size"] = "keyword2",
["slice"] = "keyword2",
["sort"] = "keyword2",
["split"] = "keyword2",
["strip"] = "keyword2",
["strip_newlines"] = "keyword2",
["times"] = "keyword2",
["true"] = "literal",
["truncate"] = "keyword2",
["truncatewords"] = "keyword2",
["uniq"] = "keyword2",
["unless"] = "keyword",
["endunless"] = "keyword",
["upcase"] = "keyword2",
["when"] = "keyword",
["where"] = "keyword2"
},
}
syntax.add {
name = "Liquid",
files = { "%.liquid?$" },
patterns = {
{ pattern = { "{%%", "%%}" }, syntax = liquid_syntax, type = "function" },
{ pattern = { "{{", "}}" }, syntax = liquid_syntax, type = "function" },
{
pattern = {
"<%s*[sS][cC][rR][iI][pP][tT]%s+[tT][yY][pP][eE]%s*=%s*" ..
"['\"]%a+/[jJ][aA][vV][aA][sS][cC][rR][iI][pP][tT]['\"]%s*>",
"<%s*/[sS][cC][rR][iI][pP][tT]>"
},
syntax = ".js",
type = "function"
},
{
pattern = {
"<%s*[sS][cC][rR][iI][pP][tT]%s*>",
"<%s*/%s*[sS][cC][rR][iI][pP][tT]>"
},
syntax = ".js",
type = "function"
},
{
pattern = {
"<%s*[sS][tT][yY][lL][eE][^>]*>",
"<%s*/%s*[sS][tT][yY][lL][eE]%s*>"
},
syntax = ".css",
type = "function"
},
{ pattern = { "<!%-%-", "%-%->" }, type = "comment" },
{ pattern = { '%f[^>][^<]', '%f[<{]' }, type = "normal" },
{ pattern = { '"', '"', '\\' }, type = "string" },
{ pattern = { "'", "'", '\\' }, type = "string" },
{ pattern = "0x[%da-fA-F]+", type = "number" },
{ pattern = "-?%d+[%d%.]*f?", type = "number" },
{ pattern = "-?%.?%d+f?", type = "number" },
{ pattern = "%f[^<]![%a_][%w_]*", type = "keyword2" },
{ pattern = "%f[^<][%a_][%w_]*", type = "function" },
{ pattern = "%f[^<]/[%a_][%w_]*", type = "function" },
{ pattern = "[%a_][%w_]*", type = "keyword" },
{ pattern = "[/<>=]", type = "operator" }
},
symbols = {},
}
+79
View File
@@ -0,0 +1,79 @@
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "Lobster",
files = "%.lobster$",
comment = "//",
patterns = {
{ pattern = "//.-\n", type = "comment" },
{ pattern = { "/%*", "%*/" }, type = "comment" },
{ pattern = "struct%s()[%a_][%w_]*", type = { "keyword", "keyword2" } },
{ pattern = "class%s()[%a_][%w_]*", type = { "keyword", "keyword2" } },
{ pattern = "[%w_]+%s*%f[{]", type = "keyword2" },
{ pattern = { '"', '"', '\\' }, type = "string" },
{ pattern = { "'", "'", '\\' }, type = "string" },
{ pattern = { '"""', '"""' }, type = "string" },
{ pattern = "0x%x+", type = "number" },
{ pattern = "%d+[%d%.eE]*f?", type = "number" },
{ pattern = "%.?%d+f?", type = "number" },
{ pattern = "[%+%-=/%*%^%%<>!~|&%?]", type = "operator" },
{ pattern = "[%a_][%w_]*%f[(]", type = "function" },
{ pattern = "[%a_][%w_]*", type = "symbol" },
},
symbols = {
["import"] = "keyword",
["from"] = "keyword",
["def"] = "keyword",
["fn"] = "keyword",
["return"] = "keyword",
["program"] = "keyword",
["private"] = "keyword",
["resource"] = "keyword",
-- not really keywords but provides control-flow constructs
["if"] = "keyword",
["guard"] = "keyword",
["for"] = "keyword",
["while"] = "keyword",
["else"] = "keyword",
["enum"] = "keyword",
["enum_flags"] = "keyword",
["int"] = "keyword2",
["float"] = "keyword2",
["string"] = "keyword2",
["any"] = "keyword2",
["void"] = "keyword2",
["is"] = "keyword",
["typeof"] = "keyword",
["var"] = "keyword",
["let"] = "keyword",
["pakfile"] = "keyword",
["switch"] = "keyword",
["case"] = "keyword",
["default"] = "keyword",
["namespace"] = "keyword",
["constructor"] = "keyword",
["operator"] = "keyword",
["super"] = "keyword",
["abstract"] = "keyword",
["attribute"] = "keyword",
["member"] = "keyword",
["member_frame"] = "keyword",
["static"] = "keyword",
["static_frame"] = "keyword",
["not"] = "keyword",
["and"] = "keyword",
["or"] = "keyword",
["struct"] = "keyword",
["class"] = "keyword",
["nil"] = "literal",
},
}
+34
View File
@@ -0,0 +1,34 @@
-- mod-version:3
local syntax = require 'core.syntax'
syntax.add {
name = "Lox",
files = { "%.lox$" },
comment = "//",
patterns = {
{ pattern = "//.-\n", type = "comment" },
{ pattern = { '"', '"' }, type = "string" },
{ pattern = "%a[%w_]*()%s*%f[(]", type = {"function", "normal"} },
{ pattern = "[%a_][%w_]*%s*%f[(]", type = "function" },
{ pattern = "%d+%.?%d*", type = "number" },
{ pattern = "%a%w*", type = "symbol" },
},
symbols = {
["and"] = "keyword",
["class"] = "keyword",
["else"] = "keyword",
["false"] = "literal",
["for"] = "keyword",
["fun"] = "keyword",
["if"] = "keyword",
["nil"] = "literal",
["or"] = "keyword",
["print"] = "keyword",
["return"] = "keyword",
["super"] = "keyword2",
["this"] = "keyword2",
["true"] = "keyword",
["var"] = "keyword",
["while"] = "keyword",
},
}
+19
View File
@@ -0,0 +1,19 @@
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "Makefile",
files = { PATHSEP .. "[Mm]akefile$", "%.mk$" },
comment = "#",
patterns = {
{ pattern = "#.*", type = "comment" },
{ pattern = [[\.]], type = "normal" },
{ pattern = "$[@^<%%?+|*]", type = "keyword2" },
{ pattern = "$%(.-%)", type = "symbol" },
{ pattern = "%f[%w_][%d%.]+%f[^%w_]", type = "number" },
{ pattern = "%..*:", type = "keyword2" },
{ pattern = ".*:", type = "function" },
},
symbols = {
},
}
+42
View File
@@ -0,0 +1,42 @@
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "MARTe",
files = { "%.mrt$", "%.marte$" },
comment = "//",
block_comment = { "/*", "*/" },
patterns = {
{ pattern = "//.*", type = "comment" },
{ pattern = { "/%*", "%*/" }, type = "comment" },
{ pattern = { '"', '"', '\\' }, type = "string" },
{ pattern = { "'", "'", '\\' }, type = "string" },
{ pattern = "%-?%.inf", type = "number" },
{ pattern = "%.NaN", type = "number" },
{
pattern = "Class%s+()=()%s+[%a_][%w_:]*",
type = { "keyword", "operator", "keyword2"}
},
{
pattern = "Type%s+()=()%s+[%a_][%w_]*",
type = { "keyword", "operator", "keyword2"}
},
{
pattern = "[%+%$][%a_][%w_]+%s()=",
type = {"function", "operator"}
},
{ pattern = "=%s+()[%a_][%w_]+", type = "string" },
{
pattern = "[%a_][%w_]+%s()=",
type = {"keyword", "operator"}
},
{ pattern = "0x%x+", type = "number" },
{ pattern = "%d+[%d%.'eE]*f?", type = "number" },
{ pattern = "%.?%d+f?", type = "number" },
{ pattern = "%a[%w_]+", type = "literal" },
},
symbols = {
["true"] = "number",
["false"] = "number",
},
}
+36
View File
@@ -0,0 +1,36 @@
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "Meson",
files = { PATHSEP .. "meson%.build$", PATHSEP .. "meson_options%.txt$" },
comment = "#",
patterns = {
{ pattern = "#.*", type = "comment" },
{ pattern = { "'", "'", '\\' }, type = "string" },
{ pattern = { "'''", "'''" }, type = "string" },
{ pattern = "0x[%da-fA-F]+", type = "number" },
{ pattern = "-?%d+%d*", type = "number" },
{ pattern = "[%+%-=/%%%*!]", type = "operator" },
{ pattern = "[%a_][%w_]*%f[(]", type = "function" },
{ pattern = "[%a_][%w_]*", type = "symbol" },
},
symbols = {
["if"] = "keyword",
["then"] = "keyword",
["else"] = "keyword",
["elif"] = "keyword",
["endif"] = "keyword",
["foreach"] = "keyword",
["endforeach"] = "keyword",
["break"] = "keyword",
["continue"] = "keyword",
["and"] = "keyword",
["not"] = "keyword",
["or"] = "keyword",
["in"] = "keyword",
["true"] = "literal",
["false"] = "literal",
},
}
+102
View File
@@ -0,0 +1,102 @@
-- mod-version:3
local syntax = require 'core.syntax'
syntax.add {
name = "MiniScript",
files = { "%.ms$" },
comment = "//",
patterns = {
{ pattern = "//.*", type = "comment" },
{ pattern = { '"', '"' }, type = "string" },
{ pattern = "[<>!=]=", type = "operator" },
{ pattern = "[%+%-%*%/%^@<>:]", type = "operator" },
{ pattern = "%d%.%d*[eE][-+]?%d+", type = "number" },
{ pattern = "%d%.%d*", type = "number" },
{ pattern = "%.?%d*[eE][-+]?%d+", type = "number" },
{ pattern = "%.?%d+", type = "number" },
{ pattern = "[%a_][%w_]*", type = "symbol" },
},
symbols = {
["if"] = "keyword",
["not"] = "keyword",
["and"] = "keyword",
["or"] = "keyword",
["else"] = "keyword",
["then"] = "keyword",
["for"] = "keyword",
["in"] = "keyword",
["while"] = "keyword",
["break"] = "keyword",
["continue"] = "keyword",
["function"] = "keyword",
["end"] = "keyword",
["return"] = "keyword",
["new"] = "keyword",
["isa"] = "keyword",
["self"] = "keyword2",
["true"] = "literal",
["false"] = "literal",
["null"] = "literal",
["globals"] = "literal",
["locals"] = "literal",
["outer"] = "literal",
-- Built-in types's classes
["number"] = "literal",
["string"] = "literal",
["list"] = "literal",
["map"] = "literal",
["funcRef"] = "literal",
-- Intrinsic functions
["abs"] = "function",
["acos"] = "function",
["asin"] = "function",
["atan"] = "function",
["bitAnd"] = "function",
["bitOr"] = "function",
["bitXor"] = "function",
["ceil"] = "function",
["char"] = "function",
["code"] = "function",
["cos"] = "function",
["floor"] = "function",
["hash"] = "function",
["hasIndex"] = "function",
["indexes"] = "function",
["indexOf"] = "function",
["insert"] = "function",
["join"] = "function",
["len"] = "function",
["log"] = "function",
["lower"] = "function",
["pi"] = "function",
["pop"] = "function",
["print"] = "function",
["pull"] = "function",
["push"] = "function",
["range"] = "function",
["remove"] = "function",
["replace"] = "function",
["rnd"] = "function",
["round"] = "function",
["shuffle"] = "function",
["sign"] = "function",
["sin"] = "function",
["slice"] = "function",
["sort"] = "function",
["split"] = "function",
["sqrt"] = "function",
["str"] = "function",
["sum"] = "function",
["tan"] = "function",
["time"] = "function",
["upper"] = "function",
["val"] = "function",
["values"] = "function",
["version"] = "function",
["wait"] = "function",
["yield"] = "function",
},
}
+64
View File
@@ -0,0 +1,64 @@
-- mod-version:3
local syntax = require "core.syntax"
syntax.add {
name = "MoonScript",
files = "%.moon$",
headers = "^#!.*[ /]moon",
comment = "--",
patterns = {
{ pattern = { '"', '"', '\\' }, type = "string" },
{ pattern = { "'", "'", '\\' }, type = "string" },
{ pattern = { "%[%[", "%]%]" }, type = "string" },
{ pattern = "%-%-.-\n", type = "comment" },
{ pattern = "-?0x%x+", type = "number" },
{ pattern = "-?%d+[%d%.eE]*", type = "number" },
{ pattern = "-?%.?%d+", type = "number" },
{ pattern = "%.%.%.?", type = "keyword2" },
{ pattern = "[<>~=]=", type = "keyword2" },
{ pattern = "[%+%-=/%*%^%%#<>]", type = "keyword2" },
{ pattern = "[%a_][%w_]*%s*%f[(\"{]", type = "function" },
{ pattern = "[%a_][%w_]*", type = "symbol" },
{ pattern = {"\\", "[%a_][%w_]*"}, type = "function" },
{ pattern = {"%.", "[%a_][%w_]*"}, type = "function" },
{ pattern = "@[%a_][%w_]*", type = "keyword2" },
{ pattern = "@", type = "keyword2" },
{ pattern = "!", type = "keyword2" },
{ pattern = "[%p]", type = "keyword" },
},
symbols = {
["if"] = "keyword",
["then"] = "keyword",
["else"] = "keyword",
["when"] = "keyword",
["elseif"] = "keyword",
["do"] = "keyword",
["->"] = "keyword",
["while"] = "keyword",
["for"] = "keyword",
["break"] = "keyword",
["continue"] = "keyword",
["export"] = "keyword",
["unless"] = "keyword",
["return"] = "keyword",
["in"] = "keyword",
["not"] = "keyword",
["and"] = "keyword",
["or"] = "keyword",
["import"] = "keyword",
["as"] = "keyword",
["from"] = "keyword",
["class"] = "keyword",
["extends"] = "keyword",
["switch"] = "keyword",
["with"] = "keyword",
["using"] = "keyword",
["super"] = "keyword2",
["self"] = "keyword2",
["#"] = "keyword2",
["true"] = "literal",
["false"] = "literal",
["nil"] = "literal",
},
}
+119
View File
@@ -0,0 +1,119 @@
-- mod-version:3
-- to better understand these comments, see this section from rxi's article
-- https://rxi.github.io/lite_an_implementation_overview.html#syntax_highlighting
-- first, we need to require the syntax module
local syntax = require "core.syntax"
--[[
then, we'll add a new syntax to the syntax module, lite-xl matches Lua patterns
against the source code in order to highlight the code.
]]
syntax.add {
-- the extension of source code
files = "%.nelua$",
-- this add support for shebang, is not rare to add #!/usr/local/bin/lua to make
-- lua scripts executable, here we add support for it for nelua
headers = "^#!.*[ /]nelua",
-- tells to lite how to toggle comments
comment = "--",
-- finally the patterns, is a table of tables,
-- each entry is a table with some fields, especially with "pattern" and "type" fields.
patterns = {
--[[
["pattern"] field:
Describes a syntax pattern, this is done with Lua Patterns
you can learn it works here: https://www.lua.org/manual/5.4/manual.html#6.4.1
The pattern can be a string or a table, when is a string, then is just a
pattern that match everything, when is a table, then it follows this
logic:
{ range_start_pattern, range_end_pattern [, escape_character] }
The matched range_start_pattern and range_end_pattern text will be highlighted, but the
text between them will not.
["syntax"] field:
Optional field, when set, the text between matched ranges will use syntax from another language,
a good common known example of this is using javascript syntax inside a `script` element:
https://github.com/lite-xl/lite-xl/blob/df667ad28e9995f8cb79dab64e6039f095c202f4/data/plugins/language_html.lua#L17-L23
["type"] field:
Set the style that should be used, this is defined on the "style" file from
the lite-xl's source, at "data/core/style.lua".
]]
{
pattern = {"##%[=*%[", "%]=*%]"},
syntax = ".lua",
type = "function",
},
{
pattern = {"#|", "|#"},
syntax = ".lua",
type = "function",
},
{
pattern = {"##", "\n"},
syntax = ".lua",
type = "function",
},
{ pattern = { '"', '"', '\\' }, type = "string" },
{ pattern = { "'", "'", '\\' }, type = "string" },
{ pattern = { "%[%[", "%]%]" }, type = "string" },
{ pattern = { "%-%-%[=*%[", "%]=*%]"}, type = "comment" },
{ pattern = "%-%-.-\n", type = "comment" },
{ pattern = "0x%x+%.%x*[pP][-+]?%d+", type = "number" },
{ pattern = "0x%x+%.%x*", type = "number" },
{ pattern = "0x%.%x+[pP][-+]?%d+", type = "number" },
{ pattern = "0x%.%x+", type = "number" },
{ pattern = "0x%x+[pP][-+]?%d+", type = "number" },
{ pattern = "0x%x+", type = "number" },
{ pattern = "%d%.%d*[eE][-+]?%d+", type = "number" },
{ pattern = "%d%.%d*", type = "number" },
{ pattern = "%.?%d*[eE][-+]?%d+", type = "number" },
{ pattern = "<%S[%w+%._,%s*'\"()<>]-%S>", type = "keyword2" },
{ pattern = "%.?%d+", type = "number" },
{ pattern = "%.%.%.?", type = "operator" },
{ pattern = "[<>~=]=", type = "operator" },
{ pattern = "[%+%-=/%*%^%%#<>]", type = "operator" },
{ pattern = "[%a_][%w_]*()%s*%f[(\"'{]", type = {"function", "normal"} },
{ pattern = "[%a_][%w_]*", type = "symbol" },
{ pattern = "::[%a_][%w_]*::", type = "function" },
},
-- special symbols, like keywords
symbols = {
-- lua symbols
["if"] = "keyword",
["then"] = "keyword",
["else"] = "keyword",
["elseif"] = "keyword",
["end"] = "keyword",
["do"] = "keyword",
["function"] = "keyword",
["repeat"] = "keyword",
["until"] = "keyword",
["while"] = "keyword",
["for"] = "keyword",
["break"] = "keyword",
["return"] = "keyword",
["local"] = "keyword",
["in"] = "keyword",
["not"] = "keyword",
["and"] = "keyword",
["or"] = "keyword",
["goto"] = "keyword",
["self"] = "keyword2",
["true"] = "literal",
["false"] = "literal",
["nil"] = "literal",
-- nelua symbols
["global"] = "keyword",
["switch"] = "keyword",
["case"] = "keyword",
["defer"] = "keyword",
["continue"] = "keyword",
["nilptr"] = "keyword",
},
}

Some files were not shown because too many files have changed in this diff Show More