Coder Social home page Coder Social logo

luasnip's Introduction

LuaSnip

LuaSnip

javadoc.mp4

Features

  • Tabstops
  • Text-Transformations using Lua functions
  • Conditional Expansion
  • Defining nested Snippets
  • Filetype-specific Snippets
  • Choices
  • Dynamic Snippet creation
  • Regex-Trigger
  • Autotriggered Snippets
  • Easy Postfix Snippets
  • Fast
  • Parse LSP-Style Snippets either directly in lua, as a vscode package or a snipmate snippet collection.
  • Expand LSP-Snippets with nvim-compe (or its' successor, nvim-cmp (requires cmp_luasnip))
  • Snippet history (jump back into older snippets)
  • Resolve filetype at the cursor using Treesitter

Drawbacks

  • Snippets that make use of the entire functionality of this plugin have to be defined in Lua (but 95% of snippets can be written in lsp-syntax).

Requirements

Neovim >= 0.7 (extmarks) jsregexp for lsp-snippet-transformations (see here for some tips on installing it).

Setup

Install

  • With your preferred plugin manager i.e. vim-plug, Packer or lazy
    Packer:

    use({
    	"L3MON4D3/LuaSnip",
    	-- follow latest release.
    	tag = "v2.*", -- Replace <CurrentMajor> by the latest released major (first number of latest release)
    	-- install jsregexp (optional!:).
    	run = "make install_jsregexp"
    })

    lazy:

    {
    	"L3MON4D3/LuaSnip",
    	-- follow latest release.
    	version = "v2.*", -- Replace <CurrentMajor> by the latest released major (first number of latest release)
    	-- install jsregexp (optional!).
    	build = "make install_jsregexp"
    }

    vim-plug:

    " follow latest release and install jsregexp.
    Plug 'L3MON4D3/LuaSnip', {'tag': 'v2.*', 'do': 'make install_jsregexp'} " Replace <CurrentMajor> by the latest released major (first number of latest release)

    Check the Releases-section to the right for the latest major version.

  • LuaSnip uses Semantic Versioning (with some leeway, big patches might end up as a Minor version)!
    Releases will be tagged as vMajor.Minor.Patch, we recommend following the latest Major release.
    Consider watching the repos releases so you're notified when a new version becomes available.

Keymaps

In vimscript, with <Tab> for jumping forward/expanding a snippet, <Shift-Tab> for jumping backward, and <Ctrl-E> for changing the current choice when in a choiceNode...

" press <Tab> to expand or jump in a snippet. These can also be mapped separately
" via <Plug>luasnip-expand-snippet and <Plug>luasnip-jump-next.
imap <silent><expr> <Tab> luasnip#expand_or_jumpable() ? '<Plug>luasnip-expand-or-jump' : '<Tab>' 
" -1 for jumping backwards.
inoremap <silent> <S-Tab> <cmd>lua require'luasnip'.jump(-1)<Cr>

snoremap <silent> <Tab> <cmd>lua require('luasnip').jump(1)<Cr>
snoremap <silent> <S-Tab> <cmd>lua require('luasnip').jump(-1)<Cr>

" For changing choices in choiceNodes (not strictly necessary for a basic setup).
imap <silent><expr> <C-E> luasnip#choice_active() ? '<Plug>luasnip-next-choice' : '<C-E>'
smap <silent><expr> <C-E> luasnip#choice_active() ? '<Plug>luasnip-next-choice' : '<C-E>'

... or in lua, with a different set of keys: <Ctrl-K> for expanding, <Ctrl-L> for jumping forward, <Ctrl-J> for jumping backward, and <Ctrl-E> for changing the active choice.

vim.keymap.set({"i"}, "<C-K>", function() ls.expand() end, {silent = true})
vim.keymap.set({"i", "s"}, "<C-L>", function() ls.jump( 1) end, {silent = true})
vim.keymap.set({"i", "s"}, "<C-J>", function() ls.jump(-1) end, {silent = true})

vim.keymap.set({"i", "s"}, "<C-E>", function()
	if ls.choice_active() then
		ls.change_choice(1)
	end
end, {silent = true})

nvim-cmp's wiki also contains an example for setting up a super-tab-like mapping.

Add Snippets

Check out the doc for a general explanation of the loaders and their benefits. The following list serves only as a short overview.

  • VS Code-like: To use existing VS Code style snippets from a plugin (eg. rafamadriz/friendly-snippets) simply install the plugin and then add

    require("luasnip.loaders.from_vscode").lazy_load()

    somewhere in your nvim-config. LuaSnip will then load the snippets contained in the plugin on startup. You can also easily load your own custom vscode style snippets by passing the path to the custom snippet-directory to the load function:

    -- load snippets from path/of/your/nvim/config/my-cool-snippets
    require("luasnip.loaders.from_vscode").lazy_load({ paths = { "./my-cool-snippets" } })

    For more info on the VS Code loader, check the examples or documentation.

  • SnipMate-like: Very similar to VS Code packages; install a plugin that provides snippets and call the load-function:

    require("luasnip.loaders.from_snipmate").lazy_load()

    The SnipMate format is very simple, so adding custom snippets only requires a few steps:

    • add a directory beside your init.vim (or any other place that is in your runtimepath) named snippets.
    • inside that directory, create files named <filetype>.snippets and add snippets for the given filetype in it (for inspiration, check honza/vim-snippets).
      # comment
      snippet <trigger> <description>
      <snippet-body>
      snippet if C-style if
      if ($1)
      	$0

    Again, there are some examples and documentation.

  • Lua: Add the snippets by calling require("luasnip").add_snippets(filetype, snippets). An example for this can be found here.
    This can also be done much cleaner, with all the benefits that come with using a loader, by using the loader for lua

There's also a repository collecting snippets for various languages, molleweide/LuaSnip-snippets.nvim

Documentation

Getting started

You have two main choices: use SnipMate/VS Code snippets (easier) or write snippets in Lua (more complex but also more feature-rich). Here are some suggestions for getting started in either case:

  • SnipMate or VS Code snippets: if you only want to write/load SnipMate or VS Code snippets and ignore Lua snippets (and this is definitely recommended if you don't yet need Lua snippets' more complicated features), check out the sections on loading VS Code or SnipMate packages in DOC.md. Of those two, SnipMate is definitely the more comfortable way of writing snippets.
  • Lua snippets: we suggest first watching or reading one of the introductory guides in the Resources for new users section below. After getting familiar with the basics, you should check out the important LuaSnip features in the following list:
    • config: Notable: region_check_events for jumping to the end of snippets the cursor is no longer inside of, delete_check_events for cleaning up snippets whose text was deleted, and enable_autosnippets to enable automatic snippet expansion.
    • extras: This module contains many functions that make writing snippets significantly easier; fmt and lambda are especially useful.
    • lua-loader: A very useful way to load snippets, more comfortable than calling add_snippets.
      Also supports hot reload (limited to buffers in the same NeoVim instance as the edited file) and jumping to the files that provide snippets to the current buffer.
    • Advanced nodes: functionNode, dynamicNode, choiceNode and restoreNode.
      Instead of reading about them in the doc, the first three are explained very well in this video by TJ DeVries.

Official docs and examples

Note: instead of immediately reading the official documentation, you may want to check out the Resources for new users section below since the docs are written more as a reference manual than as a tutorial for new users.

  • DOC.md is the main documentation—it gives an overview of how to write snippets, explains the role and use case of each LuaSnip node, shows how to load snippets from Lua, VS Code, and SnipMate formats, and covers the available LuaSnip API.
  • :help luasnip.txt is a plain text version of DOC.md available with Neovim's :help feature.
  • The file Examples/snippets.lua contains many example snippets written in Lua—we highly recommend looking through (or better yet, :luafileing) these example snippets before using LuaSnip's advanced features.
  • The Wiki contains some useful LuaSnip extensions and some examples of advanced snippets and configs.
  • Configuration is documented in DOC.md as well.

【中文版】DOC in Chinese is here.

Resources for new users

Here are some LuaSnip videos and tutorials on the Web:

Inspired by vsnip.vim

luasnip's People

Contributors

amenonsen avatar andrew15-5 avatar atticus-sullivan avatar bew avatar cbarrete avatar dvdsk avatar evesdropper avatar gongfarmer avatar henryhchchc avatar jedrzejboczar avatar jonathf avatar jrowlingson avatar kunzaatko avatar l3mon4d3 avatar leiserfg avatar loichyan avatar lyonelz96 avatar masakichi avatar max397574 avatar mike325 avatar muniftanjim avatar ner0-m avatar samasaur1 avatar stasjok avatar tomtomjhj avatar twistoy avatar uga-rosa avatar uyha avatar xu-cheng avatar zjp-cn avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

luasnip's Issues

Using with nvim-compe gives error when loading vscode snippets with multiple options. [ERROR] attempt to concatenate a table value

Error output:

Error executing vim.schedule lua callback: .../pack/packer/start/nvim-compe/lua/compe_luasnip/init.lua:27: attempt to concatenate a table value

Minimal init.lua to reproduce:

-- This file is a minimal `init.lua` example for debuggin plugins.
-- Open with `nvim -u debug.lua`

local fn = vim.fn
local install_path = "/tmp/nvim/site/pack/packer/start/packer.nvim"

vim.cmd([[set packpath=/tmp/nvim/site]])
local function load_plugins()
	local use = require("packer").use
	require("packer").startup({
		function()
			use("wbthomason/packer.nvim")
			-- Put plugins to install here:
			use("hrsh7th/nvim-compe")
			use("L3MON4D3/LuaSnip")
			use("rafamadriz/friendly-snippets")
		end,
		config = { package_root = "/tmp/nvim/site/pack" },
	})
end

_G.load_config = function()
	vim.o.completeopt = "menuone,noselect"
	require("compe").setup({
		enabled = true,
		preselect = 'enable',
		autocomplete = true,
		source = {
			luasnip = true,
		},
	})
	local function prequire(...)
		local status, lib = pcall(require, ...)
		if status then
			return lib
		end
		return nil
	end

	local luasnip = prequire("luasnip")

	local t = function(str)
		return vim.api.nvim_replace_termcodes(str, true, true, true)
	end

	local check_back_space = function()
		local col = vim.fn.col(".") - 1
		if col == 0 or vim.fn.getline("."):sub(col, col):match("%s") then
			return true
		else
			return false
		end
	end

	_G.tab_complete = function()
		if vim.fn.pumvisible() == 1 then
			return t("<C-n>")
		elseif luasnip and luasnip.expand_or_jumpable() then
			return t("<Plug>luasnip-expand-or-jump")
		elseif check_back_space() then
			return t("<Tab>")
		else
			return vim.fn["compe#complete"]()
		end
	end
	_G.s_tab_complete = function()
		if vim.fn.pumvisible() == 1 then
			return t("<C-p>")
		elseif luasnip and luasnip.jumpable(-1) then
			return t("<Plug>luasnip-jump-prev")
		else
			return t("<S-Tab>")
		end
	end

	local map = vim.api.nvim_set_keymap
	vim.cmd("inoremap <silent><expr> <CR>      compe#confirm('<CR>')")
	map("i", "<Tab>", "v:lua._G.tab_complete()", { expr = true })
	map("s", "<Tab>", "v:lua._G.s_tab_complete()", { expr = true })
	map("i", "<S-Tab>", "v:lua.MUtils.s_tab_complete()", { expr = true })
	map("s", "<S-Tab>", "v:lua.MUtils.s_tab_complete()", { expr = true })
	require("luasnip.loaders.from_vscode").load()
end

if fn.isdirectory(install_path) == 0 then
	-- install packer
	fn.system({ "git", "clone", "https://github.com/wbthomason/packer.nvim", install_path })
	load_plugins()
	require("packer").sync()
	vim.cmd("autocmd User PackerComplete ++once lua load_config()")
else
	load_plugins()
	_G.load_config()
end

Steps:

  1. Open minimal init.lua example.
  2. Edit a file and trigger a snippet that has multiple options.

Here a video.

In this case I'm trying to use the shebang snippet which has multiple options, (see here)

2021-07-07_16-54-47.mp4

Optional terser snippet syntax

See #39.

On top of that, I'd like to:

  1. allow strings as the first argument for snippets, which would be converted to { trig = the_string_here }
  2. auto-insert i(0) at the end of snippets that don't have any

With all of those merged, a short snippet could look something like:

s('sh', t'#!/bin/bash')

Arguably, we could also auto-convert strings/tables of strings into text nodes and numbers/{ number, text_node } into insert nodes, or something like that. It would be a bit more questionable and a quite big addition, but the user-experience/snippet readability would be improved IMO.

What's your opinion on all that? :)

Add more verbose node alternatives

In init.lua, you define

	s = snip_mod.S,
	sn = snip_mod.SN,
	t = require("luasnip.nodes.textNode").T,
	f = require("luasnip.nodes.functionNode").F,
	i = require("luasnip.nodes.insertNode").I,
	c = require("luasnip.nodes.choiceNode").C,
	d = require("luasnip.nodes.dynamicNode").D,

which is nice and terse, but not super user-friendly. I know that it put me off when I first checked out this plugin and I keep needing to look up what they mean every once in a while.

Since most users will alias those functions anyways (e.g. local s = ls.s), would you be open to adding more verbose variants as well? local s = ls.snippet would be much more readable for most people and barely more verbose in the context of a full config. Of course the current ones would stay, if only for backwards compatibility.

I'd be happy to submit a PR with this and adjusting the documentation if that sounds good to you.

Thanks for LuaSnip btw, it looks like a really solid plugin from what I've seen so far!

Just want to say thanks :)

This morning, when I decided to see what's new in nvim-compe these days, I did a double-take when I found that it supported a new snippets plugin. "LuaSnip?", I thought, "Huh. Gotta check that one out."

And lo and behold, it was glorious. With select mode and extmarks, the presentation is really simple and non-surprising—exactly as I like it. The snippets syntax is a bit bewildering at first, but pretty ingenious overall.

When I realized that I wasn't shackled to my previous snippets plugins anymore, a single tear rolled down my face.

Thank you, @L3MON4D3. I feel at home.

🍆

Can't complete lsp snippets in rust

When I enable compe lsp snippet support I can't complete lsp entries. Instead the selected text simply gets deleted.

Completion works as expected when I disable lsp snippet support (as in doesn't delete the text) or use vsnip instead of luasnip.

I'm using the configuration below.

local capabilities = vim.lsp.protocol.make_client_capabilities()
capabilities.textDocument.completion.completionItem.snippetSupport = true

require'lspconfig'.rust_analyzer.setup {
	capabilities = capabilities,
}

require'compe'.setup {
	enabled = true;
	autocomplete = true;
	preselect = 'enable';
	documentation = true;

	source = {
		buffer = true;
		nvim_lsp = true;
		nvim_lua = true;
		luasnip = true;
		vsnip = false;
	};
}

local t = function(str)
  return vim.api.nvim_replace_termcodes(str, true, true, true)
end

local check_back_space = function()
    local col = vim.fn.col('.') - 1
    if col == 0 or vim.fn.getline('.'):sub(col, col):match('%s') then
        return true
    else
        return false
    end
end

_G.tab = function()
  if vim.fn.pumvisible() == 1 then
    return t "<C-n>"
  elseif require'luasnip'.expand_or_jumpable() then
    return t "<Plug>(luasnip-expand-or-jump)"
  elseif check_back_space() then
    return t "<Tab>"
  else
    return vim.fn['compe#complete']()
  end
end
_G.s_tab = function()
  if vim.fn.pumvisible() == 1 then
    return t "<C-p>"
  elseif require'luasnip'.jumpable(-1) then
    return t "<Plug>(luasnip-jump-prev)"
  else
    -- If <S-Tab> is not working in your terminal, change it to <C-h>
    return t "<S-Tab>"
  end
end

nvim_set_keymap('i', '<Tab>',       'v:lua.tab()', {expr=true})
nvim_set_keymap('i', '<S-Tab>',     'v:lua.s_tab()', {expr=true})
nvim_set_keymap('i', '<cr>',        'compe#confirm("<cr>")', {expr=true})
nvim_set_keymap('i', '<c-space>',   'compe#complete()', {expr=true})

Snippets with empty lines

I have a problem with empty lines apparently terminating a snippet definition. Consider the following simple snippet:

    s('foo', {t('bar'','','baz')}),

which should expand to

bar

baz|

(with | the cursor). But what happens is

bar|

Question on adding custom json files as snippets.

Hi,
I've being trying to get friendly-snippets to work or figure out how to.
Although my aim is to actually alter them for my own needs.

Seems like there have being few mentions found, but I still couldn't get it to work.

https://old.reddit.com/r/neovim/comments/o66q3d/which_snippet_plugin_do_you_prefer_moving_out/h2x7enh/?context=10000
#35

From Folke's comment.
You need to add the below in your config to load friendly snippets:
lua require("luasnip/loaders/from_vscode").load()

I actually took and use
https://github.com/L3MON4D3/LuaSnip/blob/master/Examples/snippets.lua

So its included.

I also have friendly-snippets installed using packer.
use 'rafamadriz/friendly-snippets'

Regarding the runtimepath

The plugins are and snippets seems to be here.
~/.local/share/nvim/site/pack/packer/start/friendly-snippets/snippets

So I copied them to here
~/.config/nvim/lua/friendly-snippets

Not really sure how to continue.

I guess the missing part is the setting of runtimepath, but I dont fully grasp this.

Add the snippet-directory to your runtimepath (:set runtimepath+=snipdir)
Modify the package.json to match your layout and put it into snipdir's root

Input node using the wrong range

I have this snippet

local function replace_each(replacer)
    return function(args)
        local len = #args[1][1]
        return {replacer:rep(len)}
    end
end

ls.snippets = {
 all = {
s({trig = "bbox", wordTrig=true},
    {
        t{""}, f(replace_each(""), {1}), t{"", ""},
        i(1, {"content"}),  t{"", ""},
        f(replace_each(""), {1}),
        t{""},
        i(0)}
 )

 }
}

When it renders the first time instead of selecting content it selects content.
I tested with different characters for the corners and sides of the box ( *, "|" and "-") and it works fine, so I guess is something related to unicode runes counting.

<S-Tab> inserts "false"

If I use <S-Tab> when no snippets are active, then false is inserted.
Is there a way to check if snippet is available instead of just using jump(-1)?

My configuration (as in README, but in lua):

vim.api.nvim_set_keymap('i', '<S-Tab>', [[luaeval('require("luasnip").jump(-1)')]], { noremap = true, expr = true, silent = true })
vim.api.nvim_set_keymap('s', '<S-Tab>', [[luaeval('require("luasnip").jump(-1)')]], { noremap = true, expr = true, silent = true })

Breaking Changes

Watch this issue to be notified of any breaking changes.

thanks to @clason for recommending this

A way to choice_node and function_node?

I want to choice as follows.

\left(  \right)
↓
\left\{  \right\}
↓
\left[  \right]
↓

So, I defined the following snippet.

    s("brackets", {
      t("\\left"),
      c(1, {t("("), t("\\{"), t("["),}),
      i(0),
      t("\\right"),
      f(close_bracket, 1),
    }),

The function close_bracket to get the corresponding parentheses, but I don't know how to write it...

Bug report: Luasnip_current_nodes (nil value)

Hey, I've been getting some bug reports regarding to errors triggered by LuaSnip when running commands like Telescope or PackerSync. After debugging for a while I've found that LuaSnip was working fine until the commit c1ed401f8281925f5cc842e29767656e5c8e7735 was pushed and the line that is causing this error is L#26.

Hope that information can help to debug and fix this behavior. Thanks in advance!

unexpected behaviour of choice_active()

Sometimes it happens that require('luasnip').choice_active() returns true even if no snippet exists, for example after LuaSnipUnlinkCurrent execution or because history = false.

Moreover if no snippets exists, LuaSnipUnlinkCurrent raises an error: 'LuaSnip/lua/luasnip/init.lua:82: attempt to index a nil value'. I think having a print('Hey! no more snippet here') should be cooler.

Question: can I use my collection of personal json snippets with this plugin

Hi 👋🏾 ,

I'm curious about potentially using this plugin but having done a migration from ultisnips based snippets, to json based snippets. I'd rather not/won't (😆 ) do yet another migration/conversion to lua based snippets and leave everything I've created behind. I see there's some functionality for parsing json based snippets from friendly-snippets but I can't tell how I would do this with a custom set of json snippets I've created and have in my dotfiles.

For vim-vsnip and ultisnips they both accept a directory option which is used to source personal snippets of their particular format, all namespaced by filetype. Now, with that pre-amble over, my question is can I do something like that with this plugin?

Popup Window

I have been using Snippets and i like how there is window so I know where I am at, I was wondering if this could do a same thing,
I don't mean enter text in the pop up window,
I meant something like to show info/hint, for example with choice,
we can see a list of choice and select one without going through all to see what we need? same with input ( so we know we are at $1 or $0 etc)?

We can set this as default disable and allow user to enable it manually

Changing completion item icon

Hi there , is there any way I could change the "[Snippets]" here to only an icon?

image

I do the same for buffer completion and it worked with vsnip too but I dont use vsnip anymore , tried it with luasnip but doesnt work

image

image

Function and dynamic nodes are missplacing the extmarks

local ls = require("luasnip")
local s = ls.s
local t = ls.t
local i = ls.i
local f = ls.f
local function date()
  return {os.date("%Y-%m-%d")}
end
ls.snippets = {
    all = {
        s({trig = "date", wordTrig = true}, {f(date, {}), i(0)}), 
        s({trig = "date2", wordTrig = true}, {f(date, {}), t({" "}), i(0)})
    }
}

date renders to
␣2021-05-24
instead of 2021-05-24␣.
while date2 renders to
2021-05-24 ␣

Question: Would you be willing to use a lua formatter?

Would you be open to using https://github.com/JohnnyMorganz/StyLua on this project? I want to contribute some stuff, but your lua style is like the opposite of what I have set up for all my other lua projects, so it makes it hard to write it the right way for this project 😆

Stylua supports using tabs and all that, so if you want to keep doing that, that's totally fine with me, you (or I in a PR) could just add a stylua.toml file in the base of the repo and then I don't have to worry about messing up your style haha

Ability to list available snippets

Hi,
I've started to use LuaSnip and I am wondering if there is a way to list all available snippets for current file?

Also wondering if there could be example for using bash command output as a snippet?

jump to saved snippet location only if I'm inside the body of that snippet

Currently, the behaviour I have is that if there exists a saved location(do these have a name in snippet lingo? tabstop?) and if I press a key which I have mapped to <plug>luasnip-expand-or-jump then my cursor is moved to the next saved location regardless of how far away from that saved location I may have been. This has happened quite a few times when I have snippets with saved locations that I don't necessarily have to touch. Then instead of jumping through all the locations I may just enter normal mode and exit the snippet that way. But then the snippet jump locations are not removed and I jump to them the next time I want to insert a new line, because I have <cr> bound with a condition to first complete with compe, then LuaSnip and then insert a new line.

I wonder, is it possible to make it so that I only jump to a saved location if I am within the start and end points of the code that was inserted by the snippet?

If this is not possible, is this a feature you think makes sense for the plugin to have? The plugin works with nested snippets and I think it might be important to note that this shouldn't interfere with that, since in a nested snippet you are still within the body of the outer snippet.

<Plug>luasnip-expand-or-jump in select/visual mode does not jump

As title: <Plug>luasnip-expand-or-jump doesn't work in select/visual mode.

To reproduce the issue, map
smap <silent><expr> <Tab> luasnip#expand_or_jumpable() ? '<Plug>luasnip-expand-or-jump' : '<Tab>'
or use my configuration.

local vim = vim
local nvim_set_keymap = vim.api.nvim_set_keymap
local prequire = require('plugins.utils').prequire

local luasnip = prequire('luasnip')
local compe = require('compe')

-- Completation
compe.setup {
    preselect = 'enable',
    documentation = true,

    source = {
        path = {menu = '', priority = 7}, -- this do not work
        nvim_lsp = {menu = '', priority = 9},
        spell = {menu = '', priority = 6},
        nvim_lua = {menu = '', priority = 8},
        luasnip = {menu = '', priority = 10},
        treesitter = false
    }
}

local t = function(str)
    return vim.api.nvim_replace_termcodes(str, true, true, true)
end

local check_back_space = function()
    local col = vim.fn.col('.') - 1
    if col == 0 or vim.fn.getline('.'):sub(col, col):match('%s') then
        return true
    else
        return false
    end
end

-- Use (s-)tab to:
--- move to prev/next item in completion menuone
--- jump to prev/next snippet's placeholder
_G.tab_complete = function()
    if vim.fn.pumvisible() == 1 then
        print('c-n') -- debug
        return t '<C-n>'
    elseif luasnip and luasnip.expand_or_jumpable() then
        print('luasnip') -- debug
        return t '<Plug>luasnip-expand-or-jump'
    elseif check_back_space() then
        print('Tab') -- debug
        return t '<Tab>'
    end
    print('compe#complete') -- debug
    return vim.fn['compe#complete']()
end

_G.s_tab_complete = function()
    if vim.fn.pumvisible() == 1 then
        return t '<C-p>'
    elseif luasnip and luasnip.jumpable(-1) then
        return t '<Plug>luasnip-jump-prev'
    end
    return t '<S-Tab>'
end

_G.enter_complete = function()
    if luasnip and luasnip.choice_active() then
        return t '<Plug>luasnip-next-choice'
    end
    return vim.fn['compe#confirm'](t '<CR>')
end

local opts = {expr = true, noremap = false, silent = true}
nvim_set_keymap('i', '<Tab>', 'v:lua.tab_complete()', opts)
nvim_set_keymap('s', '<Tab>', 'v:lua.tab_complete()', opts) -- s or v
nvim_set_keymap('i', '<S-Tab>', 'v:lua.s_tab_complete()', opts)
nvim_set_keymap('s', '<S-Tab>', 'v:lua.s_tab_complete()', opts) -- s or v

nvim_set_keymap('i', '<CR>', 'v:lua.enter_complete()', opts)
nvim_set_keymap('s', '<CR>', '<cmd>lua print(require("luasnip").expand_or_jumpable())<CR>', {}) -- debug too for s or v

`parse_string` list parsing

I'm trying to integrate the plugin with https://github.com/rafamadriz/friendly-snippets basically by doing the same magic that vsnipet does (iterating over runtimepath looking for packages.json pointing to snippet files). That part is done, but then I discovered that vscode snippets can be ( and most of the time are) defined as a list of strings instead of a single one. If parse_snippet were able to read those it will be easy pie to proceed and I could even contribute the code for the snippets loading upstream.

How to use function nodes propertly? [QUESTION]

I'm trying to migrate my snippets but I don't understand well how I'm supposed to use the f node

all = {
    s({trig = "date", wordTrig = true},
        {f(function() os.date() end, {})}
     ),

    s({trig = "date1", wordTrig = true},
        {f(function() t{os.date()} end, {})}
     ),
 }

None of those work so no idea what should I do.

Match indentation?

Is there any way to match the current indentation for multi-line snippets?

For example, with snippets.nvim, I have a few snippets similar to this:

    def = U.match_indentation [[
def ${1:function}($2) do
  $0
end]];

When inserted, each line is prepended with the current indentation of the trigger.

Is there a way to do this, or even more generally, operate on each line of the snippet's result to be able to do things like add a comment prefix, line numbers, etc. to be able to build the match indent functionality in user space?

Thank you!

[Question] Auto-complete Latex (LuaSnip - Compe - friendly-snippets)

Hi,

I am very new with LuaSnip, been used to UltiSnips but wanted to switch to full Lua.
Is there a way to have auto-complete with LuaSnip on only certain snippets?

Let's say I want to enter math mode with 'mk' (or whatever the snippet), I am not sure how I would define an auto-trigger/auto-complete to enter math-mode in Latex.
Besides that, in-line math mode in Latex is '$YOUR MATH HERE$', how do you define a snippet to include those '$'?

Thanks for your help!

Setup with nvim-compe

So I'm trying to replace vim-snip with this plugin, right now I'm using the exemple setup in nvim-compe README.md

local t = function(str)
  return vim.api.nvim_replace_termcodes(str, true, true, true)
end

local check_back_space = function()
  local col = vim.fn.col('.') - 1
  if col == 0 or vim.fn.getline('.'):sub(col, col):match('%s') then
    return true
  else
    return false
  end
end

-- Use (s-)tab to:
--- move to prev/next item in completion menuone
--- jump to prev/next snippet's placeholder
MUtils.tab_complete = function()
  if vim.fn.pumvisible() == 1 then
    return t "<C-n>"
  elseif vim.fn.call("vsnip#available", {1}) == 1 then
    return t "<Plug>(vsnip-expand-or-jump)"
  elseif check_back_space() then
    return t "<Tab>"
  else
    return vim.fn['compe#complete']()
  end
end

MUtils.s_tab_complete = function()
  if vim.fn.pumvisible() == 1 then
    return t "<C-p>"
  elseif vim.fn.call("vsnip#jumpable", {-1}) == 1 then
    return t "<Plug>(vsnip-jump-prev)"
  else
    return t "<S-Tab>"
  end
end

and

map("i", "<Tab>", "v:lua.MUtils.tab_complete()", {expr = true})
map("s", "<Tab>", "v:lua.MUtils.tab_complete()", {expr = true})
map("i", "<S-Tab>", "v:lua.MUtils.s_tab_complete()", {expr = true})
map("s", "<S-Tab>", "v:lua.MUtils.s_tab_complete()", {expr = true})

What would be the best way to use a similar setup with LuaSnip?

$MYVIMRC nil value

apparently $MYVIMRC is not set which throws at
LuaSnip/lua/luasnip/loaders/from_vscode.lua:168

:h $MYVIMRC

						*VIMINIT* *EXINIT* *$MYVIMRC*
     b. Locations searched for initializations, in order of preference:
	-  $VIMINIT environment variable (Ex command line).
	-  User |config|: $XDG_CONFIG_HOME/nvim/init.vim.
	-  Other config: {dir}/nvim/init.vim where {dir} is any directory
	   in $XDG_CONFIG_DIRS.
	-  $EXINIT environment variable (Ex command line).
	|$MYVIMRC| is set to the first valid location unless it was already
	set or when using $VIMINIT.

also i try to lazy load like this

require("luasnip/loaders/from_vscode").lazy_load(
    {paths = {"~/.local/share/nvim/site/pack/packer/start/friendly-snippets"}}
)

i use init.lua as cfg

nvim version

NVIM v0.5.0-dev+1375-gca802046b
Build type: RelWithDebInfo
LuaJIT 2.0.5
Compilation: /usr/bin/cc -march=x86-64 -mtune=generic -O2 -pipe -fno-plt -fexceptions     -Wp,-D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security     -fstack-clash-protection -fcf-protection -Wp,-U_FORTIFY_SOURCE -Wp,-D_FORTIFY_SOURCE=1 -O2 -g -Og -g -Wall -Wextra -pedantic -Wno-unused-parameter -Wstrict-prototypes -std=gnu99 -Wshadow -Wconversion -Wmissing-prototypes -Wimplicit-fallthrough -Wvla -fstack-protector-strong -fno-common -fdiagnostics-color=auto -DINCLUDE_GENERATED_DECLARATIONS -D_GNU_SOURCE -DNVIM_MSGPACK_HAS_FLOAT32 -DNVIM_UNIBI_HAS_VAR_FROM -DMIN_LOG_LEVEL=3 -I/home/dnehrig/.cache/yay/neovim-git/src/build/config -I/home/dnehrig/.cache/yay/neovim-git/src/neovim-git/src -I/usr/include -I/home/dnehrig/.cache/yay/neovim-git/src/build/src/nvim/auto -I/home/dnehrig/.cache/yay/neovim-git/src/build/include
Compiled by dnehrig

Features: +acl +iconv +tui
See ":help feature-compile"

   system vimrc file: "$VIM/sysinit.vim"
  fall-back for $VIM: "/usr/share/nvim"

Run :checkhealth for more info

Guidance to set triggers

If I have this

  ls.parser.parse_snippet(
    {
      trig = "te",
      name = "ternary",
      dscr = ""
    },
    "${1:cond} ? ${2:true} : ${3:false}"
  ),

  ls.parser.parse_snippet(
    {
      trig = "e",
      name = "module export",
      dscr = ""
    },
    "export ${1:member}"
  ),

and I have editing

te|

must expand to |cond ? true : false but was expanded as texport |member

where | is the cursor

Bad argument #1 to 'ipairs' (table expected, got nil)

I have this error with the following configuration:

vim.api.nvim_set_keymap('i', '<Tab>', 'luasnip#expand_or_jumpable() ? "<Plug>luasnip-expand-or-jump" : "<Tab>"', { expr = true, silent = true })
vim.api.nvim_set_keymap('i', '<S-Tab>', [[luaeval('require("luasnip").jump(-1)')]], { noremap = true, expr = true, silent = true })
vim.api.nvim_set_keymap('i', '<C-e>', 'luasnip#choice_active() ? "<Plug>luasnip-next-choice" : "<C-E>"', { expr = true, silent = true })
vim.api.nvim_set_keymap('s', '<Tab>', [[luaeval('require("luasnip").jump(1)')]], { noremap = true, expr = true, silent = true })
vim.api.nvim_set_keymap('s', '<S-Tab>', [[luaeval('require("luasnip").jump(-1)')]], { noremap = true, expr = true, silent = true })

Even if I just call the following in cmd:

echo luasnip#expand_or_jumpable()

Attempt to perform arithmetic on a nil value

Preface:
This error only occurs when bdelete is used. When bwipeout is used, the error doesn't occur.

First error:
image

Steps to reproduce:

  1. Open two buffers
  2. Insert a snippet in one of the buffers
  3. Save and bdelete the buffer
  4. Reopen the file

Second error:
image

Steps to reproduce:

  1. Reproduce first error
  2. Execute <Plug>luasnip-expand-or-jump bind on the same line as the snippet till error pops up

LuaSnip Configuration:

local function char_count_same(c1, c2)
  local line = vim.api.nvim_get_current_line()
  local _, ct1 = string.gsub(line, c1, '')
  local _, ct2 = string.gsub(line, c2, '')
  return ct1 == ct2
end

local function even_count(c)
  local line = vim.api.nvim_get_current_line()
  local _, ct = string.gsub(line, c, '')
  return ct % 2 == 0
end

local function neg(fn, ...)
  return not fn(...)
end

local ls = require'luasnip'
local s = ls.s
local t = ls.t
local i = ls.i

ls.snippets = {
  all = {
    s({trig="("}, { t({"("}), i(1), t({")"}), i(0) }, neg, char_count_same, '%(', '%)'),
    s({trig="{"}, { t({"{"}), i(1), t({"}"}), i(0) }, neg, char_count_same, '%{', '%}'),
    s({trig="["}, { t({"["}), i(1), t({"]"}), i(0) }, neg, char_count_same, '%[', '%]') ,
    s({trig="<"}, { t({"<"}), i(1), t({">"}), i(0) }, neg, char_count_same, '<', '>'),
    s({trig="'"}, { t({"'"}), i(1), t({"'"}), i(0) }, neg, even_count, '\''),
    s({trig="\""}, { t({"\""}), i(1), t({"\""}), i(0) }, neg, even_count, '"'),
    s({trig="{;"}, { t({"{","\t"}), i(1), t({"", "}"}), i(0) }),
  },
}

P.S. Stole the snippets from your configuration and they work nicely! Thanks.

Add "simple" function node

This one is more borderline in usefulness, but may be nice to have: A "simple" function node that just inserts the output of a Lua statement, e.g.,

a(os.date('%Y-%m-%d'))

as syntactic sugar for

f(function() return os.date '%Y-%m-%d' end, {})

TexLab Language Server: snippet not working properly

I'm not sure if this is an issue with the texlab language server or LuaSnip. Let me know and I'll close this issue and create one on their repo.

Here's the v:completed_item dictionary if that might be helpful

{'word': 'begin{', 'menu': '[LSP]', 'user_data': {'compe': {'completion_item': {'label': 'begin', 'data': 
'commandSnippet', 'preselect': v:false, 'sortText': '00', 'kind': 15, 'detail': 'built-in', 'insertText': 
'begin{$1}^@^I$0^@\end{$1}', 'insertTextFormat': 2}, 'request_position': {'character': 1, 'line': 4}}}, 'info': '', 'kind': '', 'abbr': 'begin~'}   

Add conditional text node

Continuing in my quest for more "convenience nodes" to make writing snippets in LuaSnip's powerful syntax more convenient and concise, I'd like to suggest adding a "conditional text" that add text if and only if a placeholder is non-empty, so you could do something like

t"\usepackage", cond("[",2), i(2), cond("]",2), t"{", i(1), t"}"

which would expand to \usepackage[bar]{foo} in general but \usepackage{bar} if $2 was left empty.

(One could generalize this with an arbitrary regex that is matched against the insert node, but this might be overkill?)

Replace `\t` when makes sence

When rendering the snippet in the buffer, if expandtab is on \t should be replaced by the tabstop amount of spaces.

useless diagnostics errors upon completions

I don't how this relates to this plugin but if I try to fmt.Pr| and select Print from completion menu somehow this plugin causes cursor to be moved to (|) and virtualbox show a useless error like so
image

without this plugin
image

It's weird bc I don't even select a snippet from completion menu

use {
	"L3MON4D3/LuaSnip",
	requires = {
		{
		        "rafamadriz/friendly-snippets",
		}
	},
	config = function()
		require"luasnip/loaders/from_vscode".lazy_load()
	end
}

LSP snippet: end_row out of bounds

<Plug>luasnip-expand-or-jump raises sometimes an error after an expansion of a LSP snippet . It happens "randomly", because actually I haven't found yet a way to reproduce it.
The error:
LuaSnip/lua/luasnip/nodes/snippet.lua:318: end_row out of bounds

I know that require('luasnip').expand_or_jumpable() returns true.

Expand snippet without pressing the expand key

I've used LuaSnip for a few days and I've been super happy with it so far. But just now I realized that I want LuaSnip to also handle automatic expansion of common paired symbols like (), '', [], {}, "". Right now I can make (<cr> expand into (|) where | is the cursor and by pressing <tab> I get ()| so I can jump out. I would like this to work without having to press <cr> for expanding the snippet. I tried to achieve this in the following way(and some other similar ways)
imap <silent><expr> ( ('<plug>luasnip-expand-or-jump'
and later I would have intended to add some treesitter things disable this for example inside comments. But this key bind doesn't work. I suspect that this isn't possible to do currently. If it is possible and I'm just failing at configuting LuaSnip then I would very much appreciate some help. If it isn't possible, then I hope this issue raises awareness of a feature that some would appreciate.

Since I've previously seen some resistance to adding this kind of feature to other snippet plugins before, I'll below give two arguments why I think this automatic pair expansion is better handled by a snippet plugin than by a dedicated automatic pair expansion plugin.

First reason. If I use both a snippet plugin and a auto pair plugin then pairs can come from two different sources: snippets or autopair. If the pair comes from snippets then I jump in and out of the pair as I want but if the pair comes from autopair then I can't jump around. This is an annoying inconsitency. I'd much prefer to always be able to jump around, meaning that I'd prefer to let automatic pair expansion be the job of the snippet plugin as well.

Second reason. So I want to easily jump out of a pair like (). If this is pair is generated by nvim-autopairs(the autopair plugin I currently use) then I can't jump out the snippet way. But people say that if you just want to leave the pair the just press ) and you'll jump out, or at least you would jump out if the cursor was right before the automatically generated closing perenthesis. At least on my nordic keyboard layout, ) is Shift+9. So jumping out of a pair () by writing the closing parenthesis is much more awkward than simply jumping out the snippet way, by pressing <tab>. So having snippets handle auto pair expansion also gives a much more convenient way to jump out of auto expanded pairs.

So my conclusion is that if the snippet plugin handles automatic expansion of pairs instead of having a non-snippet plugin doing this then we get an experience which is 1) more consistent, and 2) more convenient.

Add "repeat" node with optional transform

One very common task in snippets is to insert the typed input in multiple places (possibly with a transformation), for example replacing whitespace with underscores to add a label or header guard. This can be done with a function or dynamic node, of course, but it's so common that I feel having this built-in would reduce boilerplate and make writing snippets much more convenient.

So my proposal would be to add a new node type "repeat node" that would look like

r(1, {match = "[^.]+$", upper = true, gsub = {"%s+", "_"}})

to insert the current value of the input node 1, with everything after the first . stripped, converted to upper case, then with whitespace replaced by underscore. (Maybe that's not the best interface; comments welcome :))

Example for init.lua keybinding?

Hi,
Can you also include a lua based example on how to map this plugin?

For now I've gotten it like this but I think this is not the best way.

cmd([[
imap luasnip#expand_or_jumpable() ? 'luasnip-expand-or-jump' : ''
inoremap lua require'luasnip'.jump(-1)

snoremap lua require('luasnip').jump(1)
snoremap lua require('luasnip').jump(-1)

imap luasnip#choice_active() ? 'luasnip-next-choice' : ''
smap luasnip#choice_active() ? 'luasnip-next-choice' : ''
]])

from_vscode: invalid value (nil) at index 1 in table for 'concat'

Updating to latest version I now have this error:
image

Here is my simple config (based off stripped down version of the example) that used to work a few commits ago:

    local luasnip = require('luasnip')

    luasnip.config.set_config({
        history = true,
        updateevents = 'TextChanged,TextChangedI',
    })

    require('luasnip/loaders/from_vscode').load()

I've tried playing with opts and add an include but I think the issue is with handling the path. Sadly I can't help much more than this bug report as my lua and neovim is still pretty limited.

Some snippets that make the parser fail

When testing the pr for the loader I found some snippets that fail. For the record:

ls.parser.parse_snippet({trig="for_i", wordTrig=true}, "for ((${0:i} = 0; ${0:i} < ${1:10}; ${0:i}++)); do\n\techo \"$${0:i}\"\ndone\n"),                                
ls.parser.parse_snippet({trig="for_in", wordTrig=true}, "for ${0:VAR} in $${1:LIST}\ndo\n\techo \"$${0:VAR}\"\ndone\n"),                                                 
ls.parser.parse_snippet({trig="case", wordTrig=true}, "case \"$${0:VAR}\" in\n\t${1:1}) echo 1\n\t;;\n\t${2:2|3}) echo 2 or 3\n\t;;\n\t*) echo default\n\t;;\nesac\n"),  
ls.parser.parse_snippet({trig="texlr", wordTrig=true}, "\\left\\{ ${1:${TM_SELECTED_TEXT}} \\right\\\\}"),                                                              

Limit when snippets are available (& compe preview)

Amazing plugin, thanks!

Is it possible to make snippet available only if triggered from the beginning of the line? I have tried:

ps({ name = "Conventional: build", trig = "^build", regTrig = true }, "build(${1:scope}): ${2:subject}")

But it does not seem to do what I want.

Also, is compe suppose to expand snippets in preview window? I only get to see this:
Screenshot 2021-07-02 at 23 16 21

Does something like <plug>luasnip-expand exist?

I currently have two types of keybinds for LuaSnip. One keybind expands or jumps, this is <cr> for me, and I have one type of keybind that only jumps, like <tab> and shift + <tab>. What I actually want is for <cr> to only allow expansion of snippets, not jump in snippets.

What sometimes happens is that I'm inside a snippet and want to add a new line. But in order to do that I first have to remove all snippet jump locations. One way to resolve this would be to expand snippets with <tab> instead of <cr> but I really don't want to move snippet expansion to <tab>, because I view snippet expansion as a type of completion and I like having all completions on <cr>. So I don't like that way of resolving this.

Is there currently a way to bind <cr> to only expand and not jump? If yes, is there also some kind of function like luasnip#expandable()? I tried looking through the source code and I don't think I found anything that looks like what I want.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.