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

feat: add vimtex integration #9

Merged
merged 12 commits into from
Jan 31, 2025
2 changes: 1 addition & 1 deletion doc/demicolon.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
*demicolon.txt* For NVIM v0.8.0 Last change: 2025 January 24
*demicolon.txt* For NVIM v0.8.0 Last change: 2025 January 29

==============================================================================
Table of Contents *demicolon-table-of-contents*
Expand Down
66 changes: 66 additions & 0 deletions lua/demicolon/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,26 @@ local M = {}
---@field enabled? boolean
---@field keymaps? DemicolonNeotestKeymapOptions

---@class DemicolonVimtexKeymapOptions
---@field section_start? DemicolonIntegrationKeymaps
---@field section_end? DemicolonIntegrationKeymaps
---@field frame_start? DemicolonIntegrationKeymaps
---@field frame_end? DemicolonIntegrationKeymaps
---@field math_start? DemicolonIntegrationKeymaps
---@field math_end? DemicolonIntegrationKeymaps
---@field comment_start? DemicolonIntegrationKeymaps
---@field comment_end? DemicolonIntegrationKeymaps
---@field environment_start? DemicolonIntegrationKeymaps
---@field environment_end? DemicolonIntegrationKeymaps

---@class DemicolonVimtexOptions
---@field enabled? boolean
---@field keymaps? DemicolonVimtexKeymapOptions

---@class DemicolonIntegrationOptions
---@field gitsigns? DemicolonGitsignsOptions Integration with https://github.com/lewis6991/gitsigns.nvim
---@field neotest? DemicolonNeotestOptions Integration with https://github.com/nvim-neotest/neotest
---@field vimtex? DemicolonVimtexOptions Integration with https://github.com/lervag/vimtex

---@class DemicolonOptions
---@field diagnostic? DemicolonDiagnosticOptions Diagnostic options
Expand Down Expand Up @@ -70,6 +87,51 @@ local options = {
},
},
},
vimtex = {
enabled = true,
keymaps = {
section_start = {
next = '][',
prev = '[[',
},
section_end = {
next = ']]',
prev = '[]',
},
frame_start = {
next = ']r',
prev = '[r',
},
frame_end = {
next = ']R',
prev = '[R',
},
math_start = {
next = ']n',
prev = '[n',
},
math_end = {
next = ']N',
prev = '[N',
},
comment_start = {
next = ']/',
prev = '[/',
},
comment_end = {
next = ']%',
prev = '[%',
},
environment_start = {
next = ']m',
prev = '[m',
},
environment_end = {
next = ']M',
prev = '[M',
},
}
}
},
}

Expand Down Expand Up @@ -113,6 +175,10 @@ function M.setup(opts)
if options.integrations.neotest.enabled then
require('demicolon.integrations.neotest').create_keymaps()
end

if options.integrations.vimtex.enabled then
require('demicolon.integrations.vimtex').create_keymaps()
end
end

return M
2 changes: 1 addition & 1 deletion lua/demicolon/integrations/gitsigns.lua
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ function M.jump(options)
else
local exists, gitsigns = pcall(require, 'gitsigns')
if not exists then
vim.notify('diagnostic.nvim: gitsigns.nvim is not installed', vim.log.levels.WARN)
vim.notify('demicolon.nvim: gitsigns.nvim is not installed', vim.log.levels.WARN)
return
end

Expand Down
2 changes: 1 addition & 1 deletion lua/demicolon/integrations/neotest.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ function M.jump(options)
require('demicolon.jump').repeatably_do(function(opts)
local exists, neotest = pcall(require, 'neotest')
if not exists then
vim.notify('diagnostic.nvim: neotest is not installed', vim.log.levels.WARN)
vim.notify('demicolon.nvim: neotest is not installed', vim.log.levels.WARN)
return
end

Expand Down
103 changes: 103 additions & 0 deletions lua/demicolon/integrations/vimtex.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
local M = {}

---@param options { forward?: boolean, vimtex_key: string }
function M.jump(options)
return function()
require('demicolon.jump').repeatably_do(function(opts)
if vim.fn.exists(':VimtexCompile') ~= 2 then
Vinzent03 marked this conversation as resolved.
Show resolved Hide resolved
vim.notify('demicolon.nvim: vimtex is not installed', vim.log.levels.WARN)
return
end

local direction = (opts.forward == nil or opts.forward) and 'next' or 'prev'

local vimtex_key = opts.vimtex_key
local vimtex_mapping = ""

if direction == "prev" then
vimtex_mapping = "[" .. vimtex_key
else
vimtex_mapping = "]" .. vimtex_key
end
Vinzent03 marked this conversation as resolved.
Show resolved Hide resolved

-- Vimtex does not use lua to map to their functions, but special <Plug>
-- mappings, which we have to map to.
-- All mappings of the desired type are listed here:
-- https://github.com/lervag/vimtex/blob/83e331dcad5ce28012e656eea3906b5b897db2ba/doc/vimtex.txt#L3899

-- Manually store the count and prepend it to the mapping to preserve it
local count = vim.v.count
local count_str = count > 1 and tostring(count) or ""
local mapping = count_str .. "<Plug>(vimtex-" .. vimtex_mapping .. ")"
local plug_mapping = vim.api.nvim_replace_termcodes(mapping, true, false, true)
vim.api.nvim_feedkeys(plug_mapping, "m", false)
end, options)
end
end

---@param key string the key to map this to
---@param vimtex_mapping string the original vimtex mapping
---@param desc string the description of the mapping
function M.vimtex_map(key, vimtex_mapping, desc)
-- Override only if it's a vimtex mapping or not set.
-- That's roughly the behavior of vimtex as well:
-- https://github.com/lervag/vimtex/blob/83e331dcad5ce28012e656eea3906b5b897db2ba/autoload/vimtex.vim#L415
local existing_lhs = vim.fn.maparg(vimtex_mapping, "nxo")
if (existing_lhs ~= '' and existing_lhs:sub(1, 13) ~= "<Plug>(vimtex") then
return
end

local vimtex_key = vimtex_mapping:sub(2, 2)
local forward = vimtex_mapping:sub(1, 1) == "]"

local nxo = { 'n', 'x', 'o' }

vim.keymap.set(nxo, key, M.jump({ forward = forward, vimtex_key = vimtex_key }), { desc = desc, buffer = true })
end

function M.create_keymaps()
local options = require('demicolon').get_options().integrations.vimtex
local keymaps = options and options.keymaps

if not options or not options.enabled or not keymaps then
return
end

vim.api.nvim_create_autocmd("FileType", {
group = vim.api.nvim_create_augroup('demicolon_vimtex_keymap', {}),
pattern = "tex",
callback = function()
M.vimtex_map(keymaps.section_start.next, "][", "Next section start")
M.vimtex_map(keymaps.section_start.prev, "[[", "Previous section start")

M.vimtex_map(keymaps.section_end.next, "]]", "Next section end")
M.vimtex_map(keymaps.section_end.prev, "[]", "Previous section end")

M.vimtex_map(keymaps.frame_start.next, "]r", "Next frame start")
M.vimtex_map(keymaps.frame_start.prev, "[r", "Previous frame start")

M.vimtex_map(keymaps.frame_end.next, "]R", "Next frame end")
M.vimtex_map(keymaps.frame_end.prev, "[R", "Previous frame end")

M.vimtex_map(keymaps.math_start.next, "]n", "Next math start")
M.vimtex_map(keymaps.math_start.prev, "[n", "Previous math start")

M.vimtex_map(keymaps.math_end.next, "]N", "Next math end")
M.vimtex_map(keymaps.math_end.prev, "[N", "Previous math end")

M.vimtex_map(keymaps.comment_start.next, "]/", "Next comment start")
M.vimtex_map(keymaps.comment_start.prev, "[/", "Previous comment start")

M.vimtex_map(keymaps.comment_end.next, "]%", "Next comment end")
M.vimtex_map(keymaps.comment_end.prev, "[%", "Previous comment end")

M.vimtex_map(keymaps.environment_start.next, "]m", "Next environment start")
M.vimtex_map(keymaps.environment_start.prev, "[m", "Previous environment start")

M.vimtex_map(keymaps.environment_end.next, "]M", "Next environment end")
M.vimtex_map(keymaps.environment_end.prev, "[M", "Previous environment end")
end,
})
end

return M