A Neovim plugin for viewing FIX protocol messages
- Syntax highlighting for FIX messages (via tree-sitter-fix)
- Tag and value annotation with virtual text
- Easy navigation between fields and messages
- Support for multiple FIX versions
- SOH (
\x01) character concealing for readability - Field picker (optional, with snacks.nvim)
{
"sergluka/fix.nvim",
dependencies = {
"manoelcampos/xml2lua",
"ColinKennedy/mega.cmdparse",
"ColinKennedy/mega.logging",
"folke/snacks.nvim", -- optional, for the fields picker
},
opts = {
-- Configuration options here
},
build = ":TSUpdate fix",
}| Command | Lua API | Description |
|---|---|---|
:FIX --help |
Show help | |
:FIX annotations [all, tag, value, message] |
require("fix").annotate(scope) |
Toggle annotations |
:FIX picker |
require("fix.snacks").open() |
Show fields picker |
:FIX browse |
require("fix").browse_tag_online() |
Open Onixs tag info page in browser |
:FIX yank field [--reg=<REGISTER>] |
require("fix").yank_field(reg) |
Yank annotated field under cursor |
:FIX yank message [--reg=<REGISTER>] |
require("fix").yank_message(reg) |
Yank annotated message under cursor |
{
-- Filetype detection rules (see `vim.filetype.add.filetypes`)
ft = {
extensions = { "fix", "fixlog" },
pattern = { ".*%.fix.txt" },
},
annotate = {
-- Tag annotation
tag = {
enabled = true,
formatter = require("fix.formatters.tag").default,
},
-- Value annotation
value = {
enabled = true,
formatter = require("fix.formatters.value").default,
},
-- Message (title) annotation
message = {
enabled = true,
position = "above", -- "above" | "below"
formatter = require("fix.formatters.message").default,
},
},
}No keybindings are set by default. Example mappings (add to ftplugin/fix.lua or your config):
local fix = require("fix")
vim.keymap.set("n", "<localleader>t", function() fix.annotate_toggle("message") end, { desc = "fix: toggle message annotation", buffer = true })
vim.keymap.set("n", "<localleader>T", function() fix.annotate_toggle("all") end, { desc = "fix: toggle all annotation", buffer = true })
vim.keymap.set("n", "<localleader>x", function() fix.browse_tag_online() end, { desc = "fix: open online doc", buffer = true })
vim.keymap.set("n", "<localleader>yf", function() fix.yank_field("+") end, { desc = "fix: yank field", buffer = true })
vim.keymap.set("n", "<localleader>yy", function() fix.yank_message("+") end, { desc = "fix: yank message", buffer = true })
vim.keymap.set("n", "<localleader><localleader>", function() require("fix.snacks").open() end, { desc = "fix: browse tags", buffer = true })
local ts_move = require("nvim-treesitter.textobjects.move")
vim.keymap.set({ "n", "v" }, "]]", function() ts_move.goto_next_start("@field") end, { desc = "fix: next field start", buffer = true })
vim.keymap.set({ "n", "v" }, "[[", function() ts_move.goto_previous_start("@field") end, { desc = "fix: previous field start", buffer = true })
vim.keymap.set({ "n", "v" }, "]}", function() ts_move.goto_next_end("@field") end, { desc = "fix: next field end", buffer = true })
vim.keymap.set({ "n", "v" }, "[{", function() ts_move.goto_previous_end("@field") end, { desc = "fix: previous field end", buffer = true })
vim.keymap.set({ "n", "v" }, "]m", function() ts_move.goto_next_start("@message") end, { desc = "fix: next message start", buffer = true })
vim.keymap.set({ "n", "v" }, "[m", function() ts_move.goto_previous_start("@message") end, { desc = "fix: previous message start", buffer = true })
vim.keymap.set({ "n", "v" }, "]M", function() ts_move.goto_next_end("@message") end, { desc = "fix: next message end", buffer = true })
vim.keymap.set({ "n", "v" }, "[M", function() ts_move.goto_previous_end("@message") end, { desc = "fix: previous message end", buffer = true })
vim.keymap.set({ "n", "v" }, "]g", function() ts_move.goto_next_start("@comment") end, { desc = "fix: next comment start", buffer = true })
vim.keymap.set({ "n", "v" }, "[g", function() ts_move.goto_previous_start("@comment") end, { desc = "fix: previous comment start", buffer = true })
vim.keymap.set({ "n", "v" }, "]G", function() ts_move.goto_next_end("@comment") end, { desc = "fix: next comment end", buffer = true })
vim.keymap.set({ "n", "v" }, "[G", function() ts_move.goto_previous_end("@comment") end, { desc = "fix: previous comment end", buffer = true })-
For now plugin supports tree-sitter master branch only
-
Due to a Neovim limitation, virtual text above the first line is not displayed, so the first message title may not be visible. Workarounds:
- Add an empty line at the beginning of the file
- Press
C-bto scroll to the top after opening - Use
annotate.message.position = "below"to display the message title below the message


