Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add sass variable matcher. #22

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 39 additions & 12 deletions lua/colorizer.lua
Original file line number Diff line number Diff line change
Expand Up @@ -85,21 +85,22 @@ local CATEGORY_HEX = lshift(1, 2);
local CATEGORY_ALPHANUM = bor(CATEGORY_ALPHA, CATEGORY_DIGIT)
do
local b = string.byte
local b_0, b_9, b_a, b_z, b_f = b'0', b'9', b'a', b'z', b'f'
for i = 0, 255 do
local v = 0
-- Digit is bit 1
if i >= b'0' and i <= b'9' then
if i >= b_0 and i <= b_9 then
v = bor(v, lshift(1, 0))
v = bor(v, lshift(1, 2))
v = bor(v, lshift(i - b'0', 4))
v = bor(v, lshift(i - b_0, 4))
end
local lowercase = bor(i, 0x20)
-- Alpha is bit 2
if lowercase >= b'a' and lowercase <= b'z' then
if lowercase >= b_a and lowercase <= b_z then
v = bor(v, lshift(1, 1))
if lowercase <= b'f' then
if lowercase <= b_f then
v = bor(v, lshift(1, 2))
v = bor(v, lshift(lowercase - b'a'+10, 4))
v = bor(v, lshift(lowercase - b_a+10, 4))
end
end
BYTE_CATEGORY[i] = v
Expand All @@ -119,8 +120,9 @@ local function parse_hex(b)
return rshift(BYTE_CATEGORY[b], 4)
end

local b_percent = string.byte("%")
local function percent_or_hex(v)
if v:sub(-1,-1) == "%" then
if v:byte(-1) == b_percent then
return tonumber(v:sub(1,-2))/100*255
end
local x = tonumber(v)
Expand Down Expand Up @@ -185,7 +187,7 @@ local function color_name_parser(line, i)
end
end

local b_hash = ("#"):byte()
local b_hash = string.byte("#")
local function rgb_hex_parser(line, i, minlen, maxlen)
if i > 1 and byte_is_alphanumeric(line:byte(i-1)) then
return
Expand Down Expand Up @@ -286,19 +288,19 @@ do
local RGB_FUNCTION_TRIE = Trie {'rgb', 'rgba'}
local HSL_FUNCTION_TRIE = Trie {'hsl', 'hsla'}
css_function_parser = function(line, i)
local prefix = CSS_FUNCTION_TRIE:longest_prefix(line:sub(i))
local prefix = CSS_FUNCTION_TRIE:longest_prefix(line, i)
if prefix then
return css_fn[prefix](line, i)
end
end
rgb_function_parser = function(line, i)
local prefix = RGB_FUNCTION_TRIE:longest_prefix(line:sub(i))
local prefix = RGB_FUNCTION_TRIE:longest_prefix(line, i)
if prefix then
return css_fn[prefix](line, i)
end
end
hsl_function_parser = function(line, i)
local prefix = HSL_FUNCTION_TRIE:longest_prefix(line:sub(i))
local prefix = HSL_FUNCTION_TRIE:longest_prefix(line, i)
if prefix then
return css_fn[prefix](line, i)
end
Expand Down Expand Up @@ -445,6 +447,9 @@ local function highlight_buffer(buf, ns, lines, line_start, options)
initialize_trie()
ns = ns or DEFAULT_NAMESPACE
local loop_parse_fn = make_matcher(options)
if options.custom_matcher then
loop_parse_fn = compile_matcher {loop_parse_fn, options.custom_matcher}
end
for current_linenum, line in ipairs(lines) do
current_linenum = current_linenum - 1 + line_start
-- Upvalues are options and current_linenum
Expand Down Expand Up @@ -505,7 +510,7 @@ local function attach_to_buffer(buf, options)
BUFFER_OPTIONS[buf] = options
rehighlight_buffer(buf, options)
if already_attached then
return
return false
end
-- send_buffer: true doesn't actually do anything in Lua (yet)
nvim.buf_attach(buf, false, {
Expand All @@ -522,6 +527,7 @@ local function attach_to_buffer(buf, options)
BUFFER_OPTIONS[buf] = nil
end;
})
return true
end

--- Stop highlighting the current buffer.
Expand Down Expand Up @@ -620,7 +626,18 @@ local function get_buffer_options(buf)
if buf == 0 or buf == nil then
buf = nvim_get_current_buf()
end
return merge({}, BUFFER_OPTIONS[buf])
if BUFFER_OPTIONS[buf] then
return merge({}, BUFFER_OPTIONS[buf])
end
end

--- Return the currently active buffer options.
-- @tparam[opt=0|nil] integer buf A value of 0 or nil implies the current buffer.
local function is_buffer_attached(buf)
if buf == 0 or buf == nil then
buf = nvim_get_current_buf()
end
return BUFFER_OPTIONS[buf] ~= nil
end

--- @export
Expand All @@ -632,5 +649,15 @@ return {
highlight_buffer = highlight_buffer;
reload_all_buffers = reload_all_buffers;
get_buffer_options = get_buffer_options;
is_buffer_attached = is_buffer_attached;
parsers = {
compile = compile_matcher;
color_name_parser = color_name_parser;
css_fn = css_fn;
css_function_parser = css_function_parser;
hsl_function_parser = hsl_function_parser;
rgb_function_parser = rgb_function_parser;
rgb_hex_parser = rgb_hex_parser;
}
}

123 changes: 123 additions & 0 deletions lua/colorizer/sass.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
local colorizer = require 'colorizer'
local nvim = require 'colorizer/nvim'

local nvim_buf_get_lines = vim.api.nvim_buf_get_lines
local nvim_get_current_buf = vim.api.nvim_get_current_buf


local M = {}

local LINE_DEFINITIONS = {}
local VARIABLE_DEFINITIONS = {}
local RECURSIVE_VARIABLES = {}

local function variable_matcher(line, i)
local variable_name = line:sub(i):match("^%$([%w_]+)")
if variable_name then
local rgb_hex = VARIABLE_DEFINITIONS[variable_name]
if rgb_hex then
return #variable_name + 1, rgb_hex
end
end
end

local VALUE_PARSER = colorizer.parsers.compile {
function(line,i) return colorizer.parsers.rgb_hex_parser(line,i,3,8) end;
colorizer.parsers.color_name_parser;
colorizer.parsers.css_function_parser;
}

local function update_from_lines(buf, buffer_variable_definitions, line_start, line_end)
local variable_definitions_changed = false
local lines = nvim_buf_get_lines(buf, line_start, line_end, false)
for linenum = line_start, line_start + #lines - 1 do
local existing_variable_name = buffer_variable_definitions[linenum]
-- Invalidate any existing definitions for the lines we are processing.
if existing_variable_name then
VARIABLE_DEFINITIONS[existing_variable_name] = nil
RECURSIVE_VARIABLES[existing_variable_name] = nil
variable_definitions_changed = true
buffer_variable_definitions[linenum] = nil
end
end
for i, line in ipairs(lines) do
local linenum = i + line_start - 1
local variable_name, variable_value = line:match("^%s*%$([%w_]+)%s*:%s*(%S+)%s*$")
-- Check if we got a variable definition
if variable_name then
-- Check for a recursive variable definition.
local target_variable_name = variable_value:match("%$([%w_]+)")
if target_variable_name then
-- Update the recursive variable definition
RECURSIVE_VARIABLES[variable_name] = target_variable_name
-- Update the value.
VARIABLE_DEFINITIONS[variable_name] = VARIABLE_DEFINITIONS[target_variable_name]
variable_definitions_changed = true
else
-- If it's not recursive, then just update the value.
local length, rgb_hex = VALUE_PARSER(variable_value, 1)
if length then
variable_definitions_changed = true
buffer_variable_definitions[linenum] = variable_name
VARIABLE_DEFINITIONS[variable_name] = rgb_hex
end
end
-- Propagate changes to recursive dependents.
-- TODO this isn't recursive, obviously. Only works for 1 depth.
for varn, varv in pairs(RECURSIVE_VARIABLES) do
if varv == variable_name then
VARIABLE_DEFINITIONS[varn] = VARIABLE_DEFINITIONS[varv]
end
end
end
end
return variable_definitions_changed
end

local function rehighlight_attached_buffers()
-- Rehighlight all buffers
for bufnr in pairs(LINE_DEFINITIONS) do
colorizer.attach_to_buffer(bufnr)
end
end


--- Attach to a buffer and continuously highlight changes.
-- @tparam[opt=0|nil] integer buf A value of 0 implies the current buffer.
-- @param[opt] options Configuration options as described in `setup`
-- @see setup
function M.attach_to_buffer(buf)
--function M.attach_to_buffer(buf, options)
if buf == 0 or buf == nil then
buf = nvim_get_current_buf()
end

LINE_DEFINITIONS[buf] = {}
local buffer_variable_definitions = LINE_DEFINITIONS[buf]

-- Parse the whole buffer to start.
update_from_lines(buf, buffer_variable_definitions, 0, -1)
rehighlight_attached_buffers()

-- send_buffer: true doesn't actually do anything in Lua (yet)
nvim.buf_attach(buf, false, {
on_lines = function(event_type, buf, changed_tick, firstline, lastline, new_lastline)
-- This is used to signal stopping the handler highlights
if not colorizer.is_buffer_attached(buf) then
return true
end
local variable_definitions_changed = update_from_lines(buf, buffer_variable_definitions, firstline, new_lastline)
-- If the variable_definitions_changed then rehighlight all watched buffers.
if variable_definitions_changed then
rehighlight_attached_buffers()
end
end;
on_detach = function()
LINE_DEFINITIONS[buf] = nil
end;
})
end

M.variable_matcher = variable_matcher

return M