Skip to content

Commit

Permalink
feat: new markdown renderer without empty lines around code blocks. F…
Browse files Browse the repository at this point in the history
…ixes #158
  • Loading branch information
folke committed Nov 12, 2022
1 parent 1558c48 commit 111fe5e
Show file tree
Hide file tree
Showing 11 changed files with 434 additions and 70 deletions.
1 change: 0 additions & 1 deletion lua/noice/config/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,6 @@ function M.defaults()
view = "hover",
---@type NoiceViewOptions
opts = {
lang = "markdown",
replace = true,
render = "plain",
format = { "{message}" },
Expand Down
1 change: 1 addition & 0 deletions lua/noice/lsp/message.lua
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ end

---@param result ShowMessageParams
function M.on_message(_, result, ctx)
---@type number
local client_id = ctx.client_id
local client = vim.lsp.get_client_by_id(client_id)
local client_name = client and client.name or string.format("lsp id=%d", client_id)
Expand Down
5 changes: 0 additions & 5 deletions lua/noice/lsp/override.lua
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,6 @@ function M.setup()
Markdown.format(message, text)
message:render(buf, Config.ns)
Markdown.keys(buf)
if not vim.b[buf].ts_highlight then
if not pcall(vim.treesitter.start, buf, "markdown") then
vim.bo[buf].syntax = "markdown"
end
end
return vim.api.nvim_buf_get_lines(buf, 0, -1, false)
end
end
Expand Down
20 changes: 12 additions & 8 deletions lua/noice/lsp/signature.lua
Original file line number Diff line number Diff line change
Expand Up @@ -172,26 +172,30 @@ function M:format_active_parameter(sig, param)
end
end

--- dddd
-- function M:format_signature(boo) end

---@param sig SignatureInformation
---@overload fun() # goooo
function M:format_signature(sig_index, sig)
if sig_index ~= 1 then
self.message:append("\n\n")
self.message:append(sig)
end
self.message:append("```" .. (self.ft or ""))
if sig_index ~= 1 then
self.message:newline()
self.message:newline()
Markdown.horizontal_line(self.message)
self.message:newline()
end
self.message:newline()

local count = self.message:height()
self.message:append(sig.label)
self.message:append(NoiceText.syntax(self.ft, self.message:height() - count))
local param = self:active_parameter(sig_index)
if param then
self:format_active_parameter(sig, param)
end
self.message:append("\n```")
self.message:newline()

if sig.documentation then
Markdown.horizontal_line(self.message)
self.message:newline()
Format.format(self.message, sig.documentation)
end
end
Expand Down
26 changes: 26 additions & 0 deletions lua/noice/text/init.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
local require = require("noice.util.lazy")

local NuiText = require("nui.text")
local Treesitter = require("noice.text.treesitter")
local Syntax = require("noice.text.syntax")
local Markdown = require("noice.text.markdown")

---@class NoiceExtmark
---@field col? number
Expand All @@ -9,6 +12,8 @@ local NuiText = require("nui.text")
---@field hl_group? string
---@field virt_self_win_col? number
---@field relative? boolean
---@field lang? string
---@field lines? number

---@class NoiceText: NuiText
---@field super NuiText
Expand All @@ -34,6 +39,13 @@ function NoiceText.cursor(col)
})
end

function NoiceText.syntax(lang, lines)
return NoiceText("", {
lang = lang,
lines = lines,
})
end

---@param bufnr number buffer number
---@param ns_id number namespace id
---@param linenr number line number (1-indexed)
Expand All @@ -43,6 +55,20 @@ function NoiceText:highlight(bufnr, ns_id, linenr, byte_start)
if not self.extmark then
return
end

if self.extmark.lang then
if self.extmark.lang == "markdown" then
Markdown.keys(bufnr)
end
local range = { linenr - self.extmark.lines, 0, linenr, byte_start - 1 }
if Treesitter.has_lang(self.extmark.lang) then
Treesitter.highlight(bufnr, ns_id, range, self.extmark.lang)
else
Syntax.highlight(bufnr, ns_id, range, self.extmark.lang)
end
return
end

local byte_start_orig = byte_start

---@type NoiceExtmark
Expand Down
171 changes: 120 additions & 51 deletions lua/noice/text/markdown.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@ local require = require("noice.util.lazy")
local NoiceText = require("noice.text")
local Config = require("noice.config")

---@alias MarkdownBlock {line:string}
---@alias MarkdownCodeBlock {code:string[], lang:string}
---@alias Markdown (MarkdownBlock|MarkdownCodeBlock)[]

local M = {}

function M.is_rule(line)
return line and line:find("^[%*%-_][%*%-_][%*%-_]+$")
return line and line:find("^%s*[%*%-_][%*%-_][%*%-_]+%s*$")
end

function M.is_code_block(line)
Expand All @@ -26,82 +30,147 @@ function M.html_entities(text)
return text
end

function M.trim(lines)
---@param text string
function M.parse(text)
text = M.html_entities(text)

---@type Markdown
local ret = {}

local lines = vim.split(text, "\n")

local l = 1

local function eat_nl()
while M.is_empty(lines[l + 1]) do
l = l + 1
end
end

while l <= #lines do
local line = lines[l]
if M.is_empty(line) then
while M.is_empty(lines[l + 1]) do
l = l + 1
end
if not (M.is_code_block(lines[l + 1]) or M.is_rule(lines[l + 1])) then
table.insert(ret, line)
local is_start = l == 1
eat_nl()
local is_end = l == #lines
if not (M.is_code_block(lines[l + 1]) or M.is_rule(lines[l + 1]) or is_start or is_end) then
table.insert(ret, { line = "" })
end
elseif M.is_code_block(line) or M.is_rule(line) then
table.insert(ret, line)
while M.is_empty(lines[l + 1]) do
elseif M.is_code_block(line) then
---@type string
local lang = line:match("```(%S+)") or "text"
local block = { lang = lang, code = {} }
while lines[l + 1] and not M.is_code_block(lines[l + 1]) do
table.insert(block.code, lines[l + 1])
l = l + 1
end

local prev = ret[#ret]
if prev and not M.is_rule(prev.line) then
table.insert(ret, { line = "" })
end

table.insert(ret, block)
l = l + 1
eat_nl()
elseif M.is_rule(line) then
table.insert(ret, { line = "---" })
eat_nl()
else
table.insert(ret, line)
local prev = ret[#ret]
if prev and prev.code then
table.insert(ret, { line = "" })
end
table.insert(ret, { line = line })
end
l = l + 1
end

return ret
end

function M.get_highlights(line)
---@type NoiceText[]
local ret = {}
for pattern, hl_group in pairs(Config.options.markdown.highlights) do
local from = 1
while from do
---@type number, string?
local to, match
---@type number, number, string?
from, to, match = line:find(pattern, from)
if match then
---@type number, number
from, to = line:find(match, from)
end
if from then
table.insert(
ret,
NoiceText("", {
hl_group = hl_group,
col = from - 1,
length = to - from + 1,
-- priority = 120,
})
)
end
from = to and to + 1 or nil
end
end
return ret
end

---@param message NoiceMessage
---@param text string
--```lua
--local a = 1
--local b = true
--```
--foo tex
function M.format(message, text)
text = M.html_entities(text)
local lines = vim.split(vim.trim(text), "\n")
lines = M.trim(lines)

for l, line in ipairs(lines) do
local prev = lines[l - 1]
local next = lines[l + 1]

if M.is_rule(line) and M.is_code_block(prev) then
-- add the rule on top of the end of the code block
M.horizontal_line(message)
elseif
M.is_rule(line) and M.is_code_block(next)
-- will be taken care of at the next iteration
then
else
if l ~= 1 then
message:newline()
local blocks = M.parse(text)

local md_lines = 0

for l = 1, #blocks do
local block = blocks[l]
if block.code then
if md_lines > 0 then
message:append(NoiceText.syntax("markdown", md_lines))
md_lines = 0
end
if M.is_code_block(line) and M.is_rule(prev) and not M.is_code_block(lines[l - 2]) then
M.horizontal_line(message)
message:newline()
---@cast block MarkdownCodeBlock
for c, line in ipairs(block.code) do
message:append(line)
if c == #block.code then
message:append(NoiceText.syntax(block.lang, #block.code))
else
message:newline()
end
end
-- Make the horizontal ruler extend the whole window width
if M.is_rule(line) then
else
---@cast block MarkdownBlock
message:newline()
if M.is_rule(block.line) then
M.horizontal_line(message)
if md_lines > 0 then
message:append(NoiceText.syntax("markdown", md_lines))
md_lines = 0
end
else
message:append(line)
for pattern, hl_group in pairs(Config.options.markdown.highlights) do
local from = 1
while from do
local to, match
from, to, match = line:find(pattern, from)
if match then
from, to = line:find(match, from)
end
if from then
message:append(NoiceText("", {
hl_group = hl_group,
col = from - 1,
length = to - from + 1,
}))
end
from = to and to + 1 or nil
end
message:append(block.line)
for _, t in ipairs(M.get_highlights(block.line)) do
message:append(t)
end
md_lines = md_lines + 1
end
end
end
if md_lines > 0 then
message:append(NoiceText.syntax("markdown", md_lines))
md_lines = 0
end
end

function M.keys(buf)
Expand Down
29 changes: 29 additions & 0 deletions lua/noice/text/syntax.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
local M = {}

--- Highlights a region of the buffer with a given language
---@param buf buffer buffer to highlight. Defaults to the current buffer if 0
---@param ns number namespace for the highlights
---@param range {[1]:number, [2]:number, [3]: number, [4]: number} (table) Region to highlight {start_row, start_col, end_row, end_col}
---@param lang string treesitter language
function M.highlight(buf, ns, range, lang)
vim.api.nvim_buf_call(buf, function()
local group = "@" .. lang:upper()

-- HACK: reset current_syntax, since some syntax files like markdown won't load if it is already set
pcall(vim.api.nvim_buf_del_var, buf, "current_syntax")
if not pcall(vim.cmd, string.format("syntax include %s syntax/%s.vim", group, lang)) then
return
end
vim.cmd(
string.format(
"syntax region %s start=+\\%%%dl+ end=+\\%%%dl+ contains=%s keepend",
lang .. range[1],
range[1] + 1,
range[3] + 1,
group
)
)
end)
end

return M
Loading

0 comments on commit 111fe5e

Please sign in to comment.