Skip to content

Commit 6eef62c

Browse files
Feature: add language icon above code blocks
# Details Idea from: https://github.com/OXY2DEV/markview.nvim Adds support for overlaying a language icon above code blocks using nvim-web-devicons. Make the nvim-web-devicons dependency optional and gracefully handle the case when it is not installed using a pcall. Add a code_style option to allow users to disable this if they prefer not to have it.
1 parent 78ef395 commit 6eef62c

File tree

10 files changed

+93
-10
lines changed

10 files changed

+93
-10
lines changed

README.md

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ Plugin to improve viewing Markdown files in Neovim
3838
Used to parse `markdown` files
3939
- [latex](https://github.com/latex-lsp/tree-sitter-latex) (Optional):
4040
Used to get `LaTeX` blocks from `markdown` files
41+
- [nvim-web-devicons](https://github.com/nvim-tree/nvim-web-devicons) (Optional):
42+
Used for icon above code blocks
4143
- System dependencies:
4244
- [pylatexenc](https://pypi.org/project/pylatexenc/) (Optional):
4345
Used to transform `LaTeX` strings to appropriate unicode using `latex2text`
@@ -50,7 +52,10 @@ Plugin to improve viewing Markdown files in Neovim
5052
{
5153
'MeanderingProgrammer/markdown.nvim',
5254
name = 'render-markdown', -- Only needed if you have another plugin named markdown.nvim
53-
dependencies = { 'nvim-treesitter/nvim-treesitter' },
55+
dependencies = {
56+
'nvim-treesitter/nvim-treesitter', -- Mandatory
57+
'nvim-tree/nvim-web-devicons', -- Optional but recommended
58+
},
5459
config = function()
5560
require('render-markdown').setup({})
5661
end,
@@ -63,7 +68,8 @@ Plugin to improve viewing Markdown files in Neovim
6368
use({
6469
'MeanderingProgrammer/markdown.nvim',
6570
as = 'render-markdown', -- Only needed if you have another plugin named markdown.nvim
66-
after = { 'nvim-treesitter' },
71+
after = { 'nvim-treesitter' }, -- Mandatory
72+
requires = { 'nvim-tree/nvim-web-devicons', opt = true }, -- Optional but recommended
6773
config = function()
6874
require('render-markdown').setup({})
6975
end,
@@ -173,10 +179,15 @@ require('render-markdown').setup({
173179
rendered = 'nvic',
174180
},
175181
},
182+
-- Determines how code blocks are rendered
183+
-- full: adds language icon above code block if possible + normal behavior
184+
-- normal: renders a background
185+
-- none: disables rendering
186+
code_style = 'full',
176187
-- Determines how tables are rendered
177188
-- full: adds a line above and below tables + normal behavior
178189
-- normal: renders the rows of tables
179-
-- none: disables rendering, use this if you prefer having cell highlights
190+
-- none: disables rendering
180191
table_style = 'full',
181192
-- Determines how table cells are rendered
182193
-- overlay: writes over the top of cells removing conealing and highlighting

demo/heading_code.gif

3.1 KB
Loading

doc/render-markdown.txt

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
*render-markdown.txt* For 0.10.0 Last change: 2024 June 24
1+
*render-markdown.txt* For 0.10.0 Last change: 2024 June 26
22

33
==============================================================================
44
Table of Contents *render-markdown-table-of-contents*
@@ -69,6 +69,8 @@ Plugin to improve viewing Markdown files in Neovim
6969
Used to parse `markdown` files
7070
- latex <https://github.com/latex-lsp/tree-sitter-latex> (Optional):
7171
Used to get `LaTeX` blocks from `markdown` files
72+
- nvim-web-devicons <https://github.com/nvim-tree/nvim-web-devicons> (Optional):
73+
Used for icon above code blocks
7274
- System dependencies:
7375
- pylatexenc <https://pypi.org/project/pylatexenc/> (Optional):
7476
Used to transform `LaTeX` strings to appropriate unicode using `latex2text`
@@ -84,7 +86,10 @@ LAZY.NVIM *render-markdown-install-lazy.nvim*
8486
{
8587
'MeanderingProgrammer/markdown.nvim',
8688
name = 'render-markdown', -- Only needed if you have another plugin named markdown.nvim
87-
dependencies = { 'nvim-treesitter/nvim-treesitter' },
89+
dependencies = {
90+
'nvim-treesitter/nvim-treesitter', -- Mandatory
91+
'nvim-tree/nvim-web-devicons', -- Optional but recommended
92+
},
8893
config = function()
8994
require('render-markdown').setup({})
9095
end,
@@ -98,7 +103,8 @@ PACKER.NVIM *render-markdown-install-packer.nvim*
98103
use({
99104
'MeanderingProgrammer/markdown.nvim',
100105
as = 'render-markdown', -- Only needed if you have another plugin named markdown.nvim
101-
after = { 'nvim-treesitter' },
106+
after = { 'nvim-treesitter' }, -- Mandatory
107+
requires = { 'nvim-tree/nvim-web-devicons', opt = true }, -- Optional but recommended
102108
config = function()
103109
require('render-markdown').setup({})
104110
end,
@@ -210,10 +216,15 @@ modified by the user.
210216
rendered = 'nvic',
211217
},
212218
},
219+
-- Determines how code blocks are rendered
220+
-- full: adds language icon above code block if possible + normal behavior
221+
-- normal: renders a background
222+
-- none: disables rendering
223+
code_style = 'full',
213224
-- Determines how tables are rendered
214225
-- full: adds a line above and below tables + normal behavior
215226
-- normal: renders the rows of tables
216-
-- none: disables rendering, use this if you prefer having cell highlights
227+
-- none: disables rendering
217228
table_style = 'full',
218229
-- Determines how table cells are rendered
219230
-- overlay: writes over the top of cells removing conealing and highlighting

lua/render-markdown/handler/markdown.lua

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
local callout = require('render-markdown.callout')
2+
local icons = require('render-markdown.icons')
23
local list = require('render-markdown.list')
34
local logger = require('render-markdown.logger')
45
local state = require('render-markdown.state')
@@ -55,12 +56,39 @@ M.render_node = function(namespace, buf, capture, node)
5556
virt_text_pos = 'overlay',
5657
})
5758
elseif capture == 'code' then
59+
if state.config.code_style == 'none' then
60+
return
61+
end
62+
5863
vim.api.nvim_buf_set_extmark(buf, namespace, start_row, 0, {
5964
end_row = end_row,
6065
end_col = 0,
6166
hl_group = highlights.code,
6267
hl_eol = true,
6368
})
69+
70+
if state.config.code_style ~= 'full' then
71+
return
72+
end
73+
74+
local info = ts.child(node, 'info_string')
75+
if info == nil then
76+
return
77+
end
78+
local language = vim.treesitter.get_node_text(info, buf)
79+
local icon, icon_highlight = icons.get(language)
80+
if icon == nil or icon_highlight == nil then
81+
return
82+
end
83+
local icon_text = { icon .. ' ', { icon_highlight, highlights.code } }
84+
-- language takes care of info_string so padding needs to take care of code block start, i.e. ```
85+
-- subtract space taken up by icon and pad the remainder
86+
local padding = string.rep(' ', 3 - vim.fn.strdisplaywidth(icon_text[1]))
87+
local language_text = { language .. padding, { 'Normal', highlights.code } }
88+
vim.api.nvim_buf_set_extmark(buf, namespace, start_row, start_col, {
89+
virt_text = { icon_text, language_text },
90+
virt_text_pos = 'overlay',
91+
})
6492
elseif capture == 'list_marker' then
6593
if ts.sibling(node, { 'task_list_marker_unchecked', 'task_list_marker_checked' }) ~= nil then
6694
-- Hide the list marker for checkboxes rather than replacing with a bullet point
@@ -145,7 +173,7 @@ M.render_node = function(namespace, buf, capture, node)
145173
local delim_value = vim.treesitter.get_node_text(delim, buf)
146174
local delim_width = get_table_row_width(delim_row, delim_value)
147175

148-
local lines = vim.api.nvim_buf_get_lines(buf, start_row, end_row, false)
176+
local lines = vim.api.nvim_buf_get_lines(buf, start_row, end_row, true)
149177
local start_width = get_table_row_width(start_row, list.first(lines))
150178
local end_width = get_table_row_width(end_row - 1, list.last(lines))
151179

lua/render-markdown/icons.lua

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
local ok, devicons = pcall(require, 'nvim-web-devicons')
2+
3+
local M = {}
4+
5+
---@param language string
6+
---@return string?
7+
---@return string?
8+
M.get = function(language)
9+
if ok then
10+
return devicons.get_icon_by_filetype(language)
11+
else
12+
return nil, nil
13+
end
14+
end
15+
16+
return M

lua/render-markdown/init.lua

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ local M = {}
6363
---@field public quote? string
6464
---@field public callout? render.md.UserCallout
6565
---@field public win_options? table<string, render.md.WindowOption>
66+
---@field public code_style? 'full'|'normal'|'none'
6667
---@field public table_style? 'full'|'normal'|'none'
6768
---@field public cell_style? 'overlay'|'raw'
6869
---@field public custom_handlers? table<string, render.md.Handler>
@@ -166,10 +167,15 @@ M.default_config = {
166167
rendered = 'nvic',
167168
},
168169
},
170+
-- Determines how code blocks are rendered
171+
-- full: adds language icon above code block if possible + normal behavior
172+
-- normal: renders a background
173+
-- none: disables rendering
174+
code_style = 'full',
169175
-- Determines how tables are rendered
170176
-- full: adds a line above and below tables + normal behavior
171177
-- normal: renders the rows of tables
172-
-- none: disables rendering, use this if you prefer having cell highlights
178+
-- none: disables rendering
173179
table_style = 'full',
174180
-- Determines how table cells are rendered
175181
-- overlay: writes over the top of cells removing conealing and highlighting

lua/render-markdown/types.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
---@field public quote string
5050
---@field public callout render.md.Callout
5151
---@field public win_options table<string, render.md.WindowOption>
52+
---@field public code_style 'full'|'normal'|'none'
5253
---@field public table_style 'full'|'normal'|'none'
5354
---@field public cell_style 'overlay'|'raw'
5455
---@field public custom_handlers table<string, render.md.Handler>

tests/heading_code_spec.lua

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,15 @@ async_tests.describe('heading_code.md', function()
5959
hl_eol = true,
6060
hl_group = 'ColorColumn',
6161
},
62+
{
63+
row = { 10 },
64+
col = { 0 },
65+
virt_text = {
66+
{ '', { 'DevIconPy', 'ColorColumn' } },
67+
{ 'python ', { 'Normal', 'ColorColumn' } },
68+
},
69+
virt_text_pos = 'overlay',
70+
},
6271
})
6372

6473
local actual = util.get_actual_marks()

tests/minimal.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ end
2222
vim.opt.rtp:prepend('.')
2323
source_plugin('plenary.nvim', 'plenary.vim')
2424
source_plugin('nvim-treesitter', 'nvim-treesitter.lua')
25+
source_plugin('nvim-web-devicons', 'nvim-web-devicons.vim')
2526

2627
-- https://github.com/ThePrimeagen/refactoring.nvim/blob/master/scripts/minimal.vim
2728
ensure_installed({ 'markdown', 'markdown_inline', 'latex' })

tests/util.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ M.marks_are_equal = function(expected, actual)
5353
for i = 1, math.min(#expected, #actual) do
5454
eq(expected[i], actual[i], string.format('Marks at index %d mismatch', i))
5555
end
56-
eq(#expected, #actual)
56+
eq(#expected, #actual, 'Different number of marks found')
5757
end
5858

5959
return M

0 commit comments

Comments
 (0)