diff --git a/lua/markview/highlights.lua b/lua/markview/highlights.lua index f3d6f58..eb3a755 100644 --- a/lua/markview/highlights.lua +++ b/lua/markview/highlights.lua @@ -703,6 +703,28 @@ highlights.dynamic = { }; ---@diagnostic enable end, + ["CodeFg"] = function () + local vim_bg = highlights.hsl(highlights.color( + "bg", + { "Normal" }, + "#FFFFFF", + "#000000" + )); + + if vim_bg[3] > 0.5 then + vim_bg[3] = clamp(vim_bg[3] - 0.05, 0.1, 0.9); + else + vim_bg[3] = clamp(vim_bg[3] + 0.05, 0.1, 0.9); + end + + ---@diagnostic disable + vim_bg = highlights.rgb(vim_bg); + + return { + fg = highlights.hex(vim_bg) + }; + ---@diagnostic enable + end, ["InlineCode"] = function () local vim_bg = highlights.hsl(highlights.color( "bg", diff --git a/lua/markview/parser.lua b/lua/markview/parser.lua index b3efac4..76c7e73 100644 --- a/lua/markview/parser.lua +++ b/lua/markview/parser.lua @@ -6,6 +6,7 @@ parser.markdown_inline = require("markview.parsers.markdown_inline"); parser.html = require("markview.parsers.html"); parser.latex = require("markview.parsers.latex"); parser.typst = require("markview.parsers.typst"); +parser.yaml = require("markview.parsers.yaml"); parser.ignore_ranges = {}; diff --git a/lua/markview/parsers/yaml.lua b/lua/markview/parsers/yaml.lua new file mode 100644 index 0000000..9db64bd --- /dev/null +++ b/lua/markview/parsers/yaml.lua @@ -0,0 +1,110 @@ +local yaml = {}; + +--- Queried contents +---@type table[] +yaml.content = {}; + +--- Queried contents, but sorted +yaml.sorted = {} + +yaml.insert = function (data) + table.insert(yaml.content, data); + + if not yaml.sorted[data.class] then + yaml.sorted[data.class] = {}; + end + + table.insert(yaml.sorted[data.class], data); +end + +yaml.property = function (buffer, TSNode, text, range) + local key, value = TSNode:field("key")[1], TSNode:field("value")[1]; + + local key_text = key and vim.treesitter.get_node_text(key, buffer) or nil; + local value_text = value and vim.treesitter.get_node_text(value, buffer) or nil; + + local value_type = "unknown"; + + if key_text == "date" then + value_type = "date"; + elseif key_text == "time" then + value_type = "time"; + elseif key_text == "tags" then + value_type = "tags"; + elseif key_text == "aliases" then + value_type = "aliases"; + elseif key_text == "cssclasses" then + value_type = "cssclasses"; + elseif tonumber(value_text) then + value_type = "number"; + elseif value_text == "true" or value_text == "false" then + value_type = "checkbox"; + elseif + value and value:child(0) and value:child(0):child(0) and + value:child(0):child(0):type() == "block_sequence_item" + then + value_type = "list"; + elseif type(value_text) == "string" then + value_type = "string"; + elseif not value_text then + value_type = "nil"; + end + + if not #text == (range.row_end - range.row_start) then + range.row_end = range.row_start + #text; + end + + yaml.insert({ + class = "yaml_property", + type = value_type, + + text = text, + + range = range + }); +end + +yaml.parse = function (buffer, TSTree, from, to) + -- Clear the previous contents + yaml.sorted = {}; + yaml.content = {}; + + local scanned_queries = vim.treesitter.query.parse("yaml", [[ + ((block_mapping_pair) @yaml.property) + ]]); + + for capture_id, capture_node, _, _ in scanned_queries:iter_captures(TSTree:root(), buffer, from, to) do + local capture_name = scanned_queries.captures[capture_id]; + local r_start, c_start, r_end, c_end = capture_node:range(); + + if not capture_name:match("^yaml%.") then + goto continue + end + + local capture_text = vim.treesitter.get_node_text(capture_node, buffer); + + if not capture_text:match("\n$") then + capture_text = capture_text .. "\n"; + end + + local lines = {}; + + for line in capture_text:gmatch("(.-)\n") do + table.insert(lines, line); + end + + yaml[capture_name:gsub("^yaml%.", "")](buffer, capture_node, lines, { + row_start = r_start, + col_start = c_start, + + row_end = r_end, + col_end = c_end + }); + + ::continue:: + end + + return yaml.content, yaml.sorted; +end + +return yaml; diff --git a/lua/markview/renderer.lua b/lua/markview/renderer.lua index b599a13..7dd0507 100644 --- a/lua/markview/renderer.lua +++ b/lua/markview/renderer.lua @@ -1,15 +1,18 @@ local renderer = {}; -local mkd = require("markview.renderers.markdown") -local inl = require("markview.renderers.markdown_inline") -local ltx = require("markview.renderers.latex") +renderer.markdown = require("markview.renderers.markdown") +renderer.markdown_inline = require("markview.renderers.markdown_inline") +renderer.latex = require("markview.renderers.latex") +renderer.yaml = require("markview.renderers.yaml") --- Renders things ---@param buffer integer renderer.render = function (buffer, parsed_content) - inl.render(buffer, parsed_content.markdown_inline) - mkd.render(buffer, parsed_content.markdown) - ltx.render(buffer, parsed_content.latex) + for lang, content in pairs(parsed_content) do + if renderer[lang] then + renderer[lang].render(buffer, content); + end + end end renderer.clear = function (buffer, ignore, from, to) @@ -18,12 +21,15 @@ renderer.clear = function (buffer, ignore, from, to) markdown_inline = {}, html = {}, latex = {}, - typst = {} + typst = {}, + yaml = {} }, ignore or {}); - mkd.clear(buffer, ignore.markdown, from, to); - inl.clear(buffer, ignore.markdown_inline, from, to); - ltx.clear(buffer, ignore.latex, from, to); + for lang, content in pairs(ignore) do + if renderer[lang] then + renderer[lang].clear(buffer, content, from, to); + end + end end renderer.range = function (content) diff --git a/lua/markview/renderers/markdown.lua b/lua/markview/renderers/markdown.lua index dbc46a1..9602bfc 100644 --- a/lua/markview/renderers/markdown.lua +++ b/lua/markview/renderers/markdown.lua @@ -1116,11 +1116,49 @@ markdown.metadata_minus = function (buffer, item) return; end - vim.api.nvim_buf_set_extmark(buffer, markdown.ns("metadatas"), range.row_start, range.col_start, { + vim.api.nvim_buf_set_extmark(buffer, markdown.ns("metadatas"), range.row_start, 0, { + undo_restore = false, invalidate = true, + end_col = #item.text[1], + conceal = "", + + virt_text_pos = "overlay", + virt_text = config.border_top and { + { + string.rep( + config.border_top, + vim.api.nvim_win_get_width( + utils.buf_getwin(buffer) + ) + ), + utils.set_hl(config.border_top_hl or config.border_hl or config.hl) + } + } or nil + }); + + vim.api.nvim_buf_set_extmark(buffer, markdown.ns("metadatas"), range.row_end - 1, 0, { undo_restore = false, invalidate = true, - end_row = range.row_end - 1, end_col = #item.text[#item.text], - conceal = "|", + conceal = "", + + virt_text_pos = "overlay", + virt_text = config.border_bottom and { + { + string.rep( + config.border_bottom, + vim.api.nvim_win_get_width( + utils.buf_getwin(buffer) + ) + ), + utils.set_hl(config.border_bottom_hl or config.border_hl or config.hl) + } + } or nil + }); + + if not config.hl then return; end + + vim.api.nvim_buf_set_extmark(buffer, markdown.ns("metadatas"), range.row_start + 1, 0, { + undo_restore = false, invalidate = true, + end_row = range.row_end - 1, line_hl_group = utils.set_hl(config.hl) }); @@ -1129,18 +1167,56 @@ end markdown.metadata_plus = function (buffer, item) ---+${func, Renders TOML metadata blocks} - local config = get_config("metadata_minus"); + local config = get_config("metadata_plus"); local range = item.range; if not config then return; end - vim.api.nvim_buf_set_extmark(buffer, markdown.ns("metadatas"), range.row_start, range.col_start, { + vim.api.nvim_buf_set_extmark(buffer, markdown.ns("metadatas"), range.row_start, 0, { + undo_restore = false, invalidate = true, + end_col = #item.text[1], + conceal = "", + + virt_text_pos = "overlay", + virt_text = config.border_top and { + { + string.rep( + config.border_top, + vim.api.nvim_win_get_width( + utils.buf_getwin(buffer) + ) + ), + utils.set_hl(config.border_top_hl or config.border_hl or config.hl) + } + } or nil + }); + + vim.api.nvim_buf_set_extmark(buffer, markdown.ns("metadatas"), range.row_end - 1, 0, { undo_restore = false, invalidate = true, - end_row = range.row_end - 1, end_col = #item.text[#item.text], - conceal = "|", + conceal = "", + + virt_text_pos = "overlay", + virt_text = config.border_bottom and { + { + string.rep( + config.border_bottom, + vim.api.nvim_win_get_width( + utils.buf_getwin(buffer) + ) + ), + utils.set_hl(config.border_bottom_hl or config.border_hl or config.hl) + } + } or nil + }); + + if not config.hl then return; end + + vim.api.nvim_buf_set_extmark(buffer, markdown.ns("metadatas"), range.row_start + 1, 0, { + undo_restore = false, invalidate = true, + end_row = range.row_end - 1, line_hl_group = utils.set_hl(config.hl) }); diff --git a/lua/markview/renderers/yaml.lua b/lua/markview/renderers/yaml.lua new file mode 100644 index 0000000..58774bd --- /dev/null +++ b/lua/markview/renderers/yaml.lua @@ -0,0 +1,94 @@ +local yaml = {}; + +local spec = require("markview.spec"); +local utils = require("markview.utils"); + +yaml.cache = {}; + +local get_config = function (...) + local _c = spec.get("yaml", ...); + + if not _c or _c.enable == false then + return; + end + + return _c; +end + +yaml.__ns = { + __call = function (self, key) + return self[key] or self.default; + end +} + +yaml.ns = { + default = vim.api.nvim_create_namespace("markview/yaml"), +}; +setmetatable(yaml.ns, yaml.__ns) + +yaml.set_ns = function () + local ns_pref = get_config("use_seperate_ns"); + if not ns_pref then ns_pref = true; end + + local available = vim.api.nvim_get_namespaces(); + local ns_list = { + ["properties"] = "markview/yaml/properties", + }; + + if ns_pref == true then + for ns, name in pairs(ns_list) do + if vim.list_contains(available, ns) == false then + yaml.ns[ns] = vim.api.nvim_create_namespace(name); + end + end + end +end + +yaml.property = function (buffer, item) + local config = get_config("properties"); + local range = item.range; + + if not config then + return; + elseif not config.text or not config.text[item.type] then + return; + end + + vim.api.nvim_buf_set_extmark(buffer, yaml.ns("properties"), range.row_start, range.col_start, { + virt_text_pos = "inline", + virt_text = { + { + config.text[item.type], + utils.set_hl(config.hl and config.hl[item.type] or nil) + } + } + }); + + for l = range.row_start + 1, range.row_end do + vim.api.nvim_buf_set_extmark(buffer, yaml.ns("properties"), l, math.min(range.col_start, #item.text[(l - range.row_start) + 1]), { + virt_text_pos = "inline", + virt_text = { + { string.rep(" ", vim.fn.strdisplaywidth(config.text[item.type])) } + } + }); + end +end + +yaml.render = function (buffer, content) + yaml.cache = {}; + + for _, item in ipairs(content or {}) do + pcall(yaml[item.class:gsub("^yaml_", "")], buffer, item); + -- yaml[item.class:gsub("^yaml_", "")](buffer, item); + end +end + +yaml.clear = function (buffer, ignore_ns, from, to) + for name, ns in pairs(yaml.ns) do + if ignore_ns and vim.list_contains(ignore_ns, name) == false then + vim.api.nvim_buf_clear_namespace(buffer, ns, from or 0, to or -1); + end + end +end + +return yaml; diff --git a/lua/markview/spec.lua b/lua/markview/spec.lua index a37ec35..531cbab 100644 --- a/lua/markview/spec.lua +++ b/lua/markview/spec.lua @@ -551,7 +551,19 @@ spec.default = { }, metadata_minus = { - hl = "Code" + hl = "Code", + border_hl = "CodeFg", + + border_top = "▄", + border_bottom = "▀" + }, + + metadata_plus = { + hl = "Code", + border_hl = "CodeFg", + + border_top = "▄", + border_bottom = "▀" }, tables = { @@ -841,7 +853,38 @@ spec.default = { pad_char = " " }, }, - typst = {} + typst = {}, + yaml = { + properties = { + enable = true, + hl = { + ["aliases"] = "MarkviewIcon3", + ["cssclasses"] = "MarkviewIcon5", + ["checkbox"] = "MarkviewIcon6", + ["date"] = "MarkviewIcon2", + ["list"] = "MarkviewIcon5", + ["number"] = "MarkviewIcon6", + ["nil"] = "MarkviewIcon1", + ["string"] = "MarkviewIcon4", + ["tags"] = "MarkviewIcon6", + ["time"] = "MarkviewIcon3", + ["unknown"] = "MarkviewIcon2" + }, + text = { + ["aliases"] = " 󱞫 ", + ["cssclasses"] = "  ", + ["checkbox"] = " 󰄵 ", + ["date"] = " 󰃭 ", + ["list"] = " 󱉯 ", + ["number"] = "  ", + ["nil"] = "  ", + ["string"] = "  ", + ["tags"] = " 󰓻 ", + ["time"] = " 󱑂 ", + ["unknown"] = "  " + } + } + } }; spec.config = spec.default; diff --git a/lua/markview/utils.lua b/lua/markview/utils.lua index 44377ee..0cca312 100644 --- a/lua/markview/utils.lua +++ b/lua/markview/utils.lua @@ -113,6 +113,16 @@ utils.find_attached_wins = function (buf) return attached_wins; end +utils.buf_getwin = function (buffer) + local wins = vim.fn.win_findbuf(buffer); + + if vim.list_contains(wins, vim.api.nvim_get_current_win()) then + return vim.api.nvim_get_current_win(); + end + + return wins[1]; +end + --- Gets the start & stop line for a range from the cursor ---@param buffer integer ---@param window integer