Skip to content

Commit

Permalink
feat: add vimtex integration (#9)
Browse files Browse the repository at this point in the history
Co-authored-by: Vinzent03 <[email protected]>
Co-authored-by: Melker Ulander <[email protected]>
  • Loading branch information
3 people authored Jan 31, 2025
1 parent a5bd58e commit ef477e1
Show file tree
Hide file tree
Showing 6 changed files with 228 additions and 3 deletions.
64 changes: 64 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ With [lazy.nvim](https://github.com/folke/lazy.nvim):
{
'mawkler/demicolon.nvim',
-- keys = { ';', ',', 't', 'f', 'T', 'F', ']', '[', ']d', '[d' }, -- Uncomment this to lazy load
-- ft = 'tex', -- ...and this if you use LaTeX
dependencies = {
'nvim-treesitter/nvim-treesitter',
'nvim-treesitter/nvim-treesitter-textobjects',
Expand Down Expand Up @@ -79,6 +80,23 @@ demicolon.nvim lets you repeat any [nvim-treesitter-textobjects](https://github.
| `]t`/`[t` | Test | `:help neotest.jump` |
| `]T`/`[T` | Failed test | `:help neotest.jump` |

### [VimTeX](https://github.com/lervag/vimtex) motions

Note that these mappings are only created in normal mode and visual mode. For some reason they don't work when created for operator-pending mode.

| Motion | Jumps to next/pevious... | Help page with more information |
| --------- | ------------------------ | ------------------------------- |
| `][`/`[[` | Section start | `:help vimtex-motions` |
| `]]`/`[]` | Section end | `:help vimtex-motions` |
| `]r`/`[r` | Frame start | `:help vimtex-motions` |
| `]R`/`[R` | Frame end | `:help vimtex-motions` |
| `]n`/`[n` | Math start | `:help vimtex-motions` |
| `]N`/`[N` | Math end | `:help vimtex-motions` |
| `]/`/`[/` | Comment start | `:help vimtex-motions` |
| `]*`/`[*` | Comment end | `:help vimtex-motions` |
| `]m`/`[m` | Environment start | `:help vimtex-motions` |
| `]M`/`[M` | Environment end | `:help vimtex-motions` |

## Configuration

Default options:
Expand Down Expand Up @@ -127,6 +145,52 @@ opts = {
},
},
},
-- Integration with https://github.com/lervag/vimtex
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
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
95 changes: 95 additions & 0 deletions lua/demicolon/integrations/vimtex.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
local M = {}

---@param options { forward?: boolean, vimtex_key: string }
function M.jump(options)
return function()
require('demicolon.jump').repeatably_do(function(opts)
local direction = (opts.forward == nil or opts.forward) and ']' or '['
local vimtex_mapping = direction .. opts.vimtex_key

-- 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, 'nx')
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 nx = { 'n', 'x' }

vim.keymap.set(nx, key, M.jump({ forward = forward, vimtex_key = vimtex_key }),
{ desc = desc, buffer = true, noremap = true, silent = 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()
if vim.fn.exists(':VimtexCompile') ~= 2 then
return
end

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

0 comments on commit ef477e1

Please sign in to comment.