This is a plugin (Neovim only) for writing LilyPond scores, with asynchronous make, midi/MP3 player, "hyphenation" function for lyrics, fast syntax highlighting... This repository also contains ftplugin files for LaTeX and Texinfo files which allows embedded LilyPond syntax highlighting, and makeprg which support lilypond-book or lyluatex package out of the box.
Installation • Configuration • Usage • Tips & tricks
Note
NEW PLAYER (sept. 2026)
- automatic audio update if the player is open
- use
gg,G, and[NUM]Gto navigate to a specific bar - add/jump to/del marks with
m,'anddm - new ui
- Fast syntax file for LilyPond
- Asynchronous :make - compile in background without freezing Neovim
- Audio player in floating window (LilyPond only) - convert (mp3 or wav) and play midi file while writing score (using
mpv,timidityorfluidsynth&ffmpeg) - QuickPlayer (LilyPond only) - convert and play only visual selection
- Hyphenation : automatically place hyphens ' -- ' inside texts to make those texts usable as lyrics (LilyPond only)
- Simple ftplugin for LilyPond with
makeprg - Multiple files support - Compile only main file when working on multiple files project
- ftplugin for LaTex and Texinfo files which detects and allows embedded LilyPond syntax, adaptive compilation function for
lyluatexorlilypond-book - Easy auto-completion and Point & Click configuration
- Error managment with correct quickfix and diagnostics
⚠ This plugin requires Nvim >= 0.7
If you want to use all the functions (player, hyphenation for various languages...), please read the installation section in the wiki to install dependencies
{
'martineausimon/nvim-lilypond-suite',
opts = {
-- edit config here (see "Customize default settings" in wiki)
}
}Non lazy.nvim users : this plugin needs require('nvls').setup()
With config (click to expand)
{
'martineausimon/nvim-lilypond-suite',
opts = {
lilypond = {
mappings = {
player = "<F3>",
compile = "<F5>",
open_pdf = "<F6>",
switch_buffers = "<A-Space>",
insert_version = "<F4>",
hyphenation = "<F12>",
hyphenation_change_lang = "<F11>",
insert_hyphen = "<leader>ih",
add_hyphen = "<leader>ah",
del_next_hyphen = "<leader>dh",
del_prev_hyphen = "<leader>dH",
},
options = {
pitches_language = "default",
hyphenation_language = "en_DEFAULT",
output = "pdf",
backend = nil,
main_file = "main.ly",
main_folder = "%:p:h",
include_dir = nil,
pdf_viewer = nil,
errors = {
diagnostics = true,
quickfix = "external",
filtered_lines = {
"compilation successfully completed",
"search path"
}
},
},
},
latex = {
mappings = {
compile = "<F5>",
open_pdf = "<F6>",
lilypond_syntax = "<F3>"
},
options = {
lilypond_book_flags = nil,
clean_logs = false,
main_file = "main.tex",
main_folder = "%:p:h",
include_dir = nil,
lilypond_syntax_au = "BufEnter",
pdf_viewer = nil,
errors = {
diagnostics = true,
quickfix = "external",
filtered_lines = {
"Missing character",
"See the LaTeX manual or LaTeX Companion for explanation",
"for immediate help.",
"Overfull \\hbox",
"^%s%.%.%.",
"%s+%(.*%)"
}
},
},
},
texinfo = {
mappings = {
compile = "<F5>",
open_pdf = "<F6>",
lilypond_syntax = "<F3>"
},
options = {
lilypond_book_flags = "--pdf",
clean_logs = false,
main_file = "main.texi",
main_folder = "%:p:h",
include_dir = nil,
lilypond_syntax_au = "BufEnter",
pdf_viewer = nil,
errors = {
diagnostics = true,
quickfix = "external",
filtered_lines = {
"Missing character",
"See the LaTeX manual or LaTeX Companion for explanation",
"for immediate help.",
"Overfull \\hbox",
"^%s%.%.%.",
"%s+%(.*%)"
}
},
},
},
player = {
mappings = {
quit = "q",
play_pause = "p",
loop = "<A-l>",
backward = "h",
small_backward = "<S-h>",
forward = "l",
small_forward = "<S-l>",
decrease_speed = "j",
increase_speed = "k",
halve_speed = "<S-j>",
double_speed = "<S-k>"
},
options = {
row = 1,
col = "99%",
width = "50",
height = "1",
border_style = "single",
winhighlight = "Normal:Normal,FloatBorder:Normal,FloatTitle:Normal",
winhighlight_inactive = "Normal:NvlsPlayerInactive,FloatBorder:NvlsPlayerInactive,FloatTitle:NvlsPlayerInactive,PmenuSel:NvlsPlayerInactive,NonText:NvlsPlayerInactive",
midi_synth = "fluidsynth",
fluidsynth_flags = nil,
timidity_flags = nil,
ffmpeg_flags = nil,
audio_format = "mp3",
mpv_flags = {
"--msg-level=cplayer=no,ffmpeg=no,alsa=no",
"--loop",
"--config-dir=/dev/null",
"--no-video"
},
icon_play = "",
icon_pause = "",
bar_char = "━",
seek_step = 5,
seek_step_small = 1,
speed_step = 0.1,
speed_multiply = 2.0,
refresh_interval_ms = 150,
},
}
}Minimal config with Lazy and Blink (click to expand)
-- Install lazy.nvim
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not (vim.uv or vim.loop).fs_stat(lazypath) then
local lazyrepo = "https://github.com/folke/lazy.nvim.git"
local out = vim.fn.system({ "git", "clone", "--filter=blob:none", "--branch=stable", lazyrepo, lazypath })
if vim.v.shell_error ~= 0 then
vim.api.nvim_echo({
{ "Failed to clone lazy.nvim:\n", "ErrorMsg" },
{ out, "WarningMsg" },
{ "\nPress any key to exit..." },
}, true, {})
vim.fn.getchar()
os.exit(1)
end
end
vim.opt.rtp:prepend(lazypath)
-- Plugins config
require("lazy").setup({
{
"martineausimon/nvim-lilypond-suite",
opts = {}
},
{ 'nvim-lua/plenary.nvim', lazy = true }, -- Required for blink.cmp
{
'saghen/blink.cmp',
dependencies = {
'Kaiser-Yang/blink-cmp-dictionary', -- Required for dictionary completion
},
version = '*',
opts = {
sources = {
default = { 'dictionary', 'lsp', 'path', 'snippets', 'buffer' }, -- Add 'dictionary'
providers = {
dictionary = {
module = 'blink-cmp-dictionary',
name = 'Dict',
min_keyword_length = 3,
max_items = 8,
opts = {
dictionary_files = function()
if vim.bo.filetype == 'lilypond' then -- Add lilypond words to sources
return vim.fn.glob(vim.fn.expand('$LILYDICTPATH') .. '/*', true, true)
end
end,
}
},
},
},
},
opts_extend = { "sources.default" }
},
},{})
vim.diagnostic.config({ -- Show diagnostics if errors
virtual_text = true,
signs = true,
update_in_insert = false,
underline = true,
})
vim.api.nvim_create_autocmd('BufEnter', { -- Better highlights
command = "syntax sync fromstart",
pattern = { '*.ly', '*.ily', '*.tex', '*.texi', '*.texinfo' }
})
vim.api.nvim_create_autocmd( 'QuickFixCmdPost', { -- Show quickfix if errors, else close window
command = "cwindow",
pattern = "*"
})