Skip to content

Commit

Permalink
Merge branch 'parse_from_ast'
Browse files Browse the repository at this point in the history
  • Loading branch information
L3MON4D3 committed Aug 27, 2022
2 parents e0bce25 + eb2e776 commit 97a51a0
Show file tree
Hide file tree
Showing 42 changed files with 4,325 additions and 500 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/deps/
/deps/nvim
/doc/tags
/lua/luasnip-jsregexp.so
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "deps/jsregexp"]
path = deps/jsregexp
url = https://github.com/kmarius/jsregexp/
104 changes: 101 additions & 3 deletions DOC.md
Original file line number Diff line number Diff line change
Expand Up @@ -1305,7 +1305,7 @@ extended(...)
# LSP-SNIPPETS

Luasnip is capable of parsing lsp-style snippets using
`ls.parser.parse_snippet(context, snippet_string)`:
`ls.parser.parse_snippet(context, snippet_string, opts)`:
```lua
ls.parser.parse_snippet({trig = "lsp"}, "$1 is ${2|hard,easy,challenging|}")
```
Expand All @@ -1316,17 +1316,86 @@ ls.parser.parse_snippet({trig = "lsp"}, "$1 is ${2|hard,easy,challenging|}")

<!-- panvimdoc-ignore-end -->

`context` can be:
- `string|table`: treated like the first argument to `ls.s`, `parse_snippet`
returns a snippet.
- `number`: `parse_snippet` returns a snippetNode, with the position
`context`.
- `nil`: `parse_snippet` returns a flat table of nodes. This can be used
like `fmt`.

Nested placeholders(`"${1:this is ${2:nested}}"`) will be turned into
choiceNode's with:
- the given snippet(`"this is ${1:nested}"`) and
- an empty insertNode
- the given snippet(`"this is ${1:nested}"`) and
- an empty insertNode

<!-- panvimdoc-ignore-start -->

![lsp2](https://user-images.githubusercontent.com/25300418/184359306-c669d3fa-7ae5-4c07-b11a-34ae8c4a17ac.gif)

<!-- panvimdoc-ignore-end -->

This behaviour can be modified by changing `parser_nested_assembler` in
`ls.setup()`.


Luasnip will also modify some snippets it's incapable of representing
accurately:
- if the `$0` is a placeholder with something other than just text inside
- if the `$0` is a choice
- if the `$0` is not an immediate child of the snippet (it could be inside a
placeholder: `"${1: $0 }"`)

To remedy those incompatibilities, the invalid `$0` will be replaced with a
tabstop/placeholder/choice which will be visited just before the new `$0`. This
new `$0` will be inserted at the (textually) earliest valid position behind the
invalid `$0`.

`opts` can contain the following keys:
- `trim_empty`: boolean, remove empty lines from the snippet. Default true.
- `dedent`: boolean, remove common indent from the snippet's lines.
Default true.

Both `trim_emtpy` and `dedent` will be disabled for snippets parsed via
`ls.lsp_expand`: it might prevent correct expansion of snippets sent by lsp.

## Snipmate

It is furthermore possible to parse snipmate-snippets (this includes support for
vimscript-evaluation!!)
Snipmate-snippets have to be parsed with a different function,
`ls.parser.parse_snipmate`:
```lua
ls.parser.parse_snipmate("year", "The year is `strftime('%Y')`")
```

`parse_snipmate` accepts the same arguments as `parse_snippet`, only the
snippet-body is parsed differently.

## Transformations

To apply
[Variable/Placeholder-transformations](https://code.visualstudio.com/docs/editor/userdefinedsnippets#_variable-transforms),
luasnip needs to apply ECMAScrip-regexes.
This is implemented by relying on [`jsregexp`](https://github.com/kmarius/jsregexp).
The easiest, but potentially error-prone way to install it is by calling `make
install_jsregexp` in the repo-root.
This process can be automated by `packer.nvim`:
```lua
use("L3MON4D3/luasnip", run = "make install_jsregexp")
```
If this fails, first open an issue :P, and then try installing the
`jsregexp`-luarock. This is also possible via
`packer.nvim`, although actual usage may require a small workaround, see
[here](https://github.com/wbthomason/packer.nvim/issues/593) or
[here](https://github.com/wbthomason/packer.nvim/issues/358).

Alternatively, `jsregexp` can be cloned locally, `make`d, and the resulting
`jsregexp.so` placed in some place where nvim can find it (probably
`~/.config/nvim/lua/`).

If `jsregexp` is not available, transformation are replaced by a simple copy.

# VARIABLES

All `TM_something`-variables are supported with two additions:
Expand Down Expand Up @@ -1417,6 +1486,28 @@ end, {}))

<!-- panvimdoc-ignore-end -->

## LSP-Variables

All variables, even ones added via `env_namespace`, can be accessed in
lsp-snippets as `$VAR_NAME`.

The lsp-spec states:

----

With `$name` or `${name:default}` you can insert the value of a variable.
When a variable isn’t set, its default or the empty string is inserted.
When a variable is unknown (that is, its name isn’t defined) the name of the variable is inserted and it is transformed into a placeholder.

----

The above necessiates a differentiation between `unknown` and `unset` variables:

For Luasnip, a variable `VARNAME` is `unknown` when `env.VARNAME` returns `nil` and `unset`
if it returns an empty string.

Consider this when adding env-variables which might be used in lsp-snippets.

# LOADERS

Luasnip is capable of loading snippets from different formats, including both
Expand Down Expand Up @@ -1737,6 +1828,13 @@ local sp = require("luasnip.nodes.snippetProxy")
sp("trig", "a snippet $1")
```

`sp(context, body, opts) -> snippetProxy`
- `context`: exactly the same as the first argument passed to `ls.s`.
- `body`: the snippet-body.
- `opts`: accepts the same `opts` as `ls.s`, with some additions:
- `parse_fn`: the function for parsing the snippet. Defaults to
`ls.parser.parse_snippet` (the parser for lsp-snippets), an alternative is
the parser for snipmate-snippets (`ls.parser.parse_snipmate`).

# EXT\_OPTS

Expand Down
21 changes: 19 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,25 @@ NVIM_PATH=deps/nvim
nvim:
git clone --depth 1 https://github.com/neovim/neovim ${NVIM_PATH} || (cd ${NVIM_PATH}; git fetch --depth 1; git checkout origin/master)

JSREGEXP_PATH=deps/jsregexp
jsregexp:
git submodule init
git submodule update
# conditional: find lua nvim is linked against, and link against it too.
make INCLUDE_DIR=-I$(shell pwd)/deps/lua51_include/ LDLIBS=$(if nvim -v | grep LuaJIT,"-lluajit-5.1","-llua5.1") -C ${JSREGEXP_PATH}

install_jsregexp: jsregexp
# access via require("luasnip-jsregexp")
# The hyphen must be used here, otherwise the luaopen_*-call will fail.
# See the package.loaders-section [here](https://www.lua.org/manual/5.1/manual.html#pdf-require)
cp $(shell pwd)/${JSREGEXP_PATH}/jsregexp.so $(shell pwd)/lua/luasnip-jsregexp.so

uninstall_jsregexp:
rm $(shell pwd)/lua/luasnip-jsregexp.so

# Expects to be run from repo-location (eg. via `make -C path/to/luasnip`).
test: nvim
test: nvim jsregexp
# unset both to prevent env leaking into the neovim-build.
# add helper-functions to lpath.
unset LUA_PATH LUA_CPATH ; LUASNIP_SOURCE=$(shell pwd) TEST_FILE=$(realpath tests) BUSTED_ARGS=--lpath=$(shell pwd)/tests/?.lua make -C ${NVIM_PATH} functionaltest
# ";;" in CPATH appends default.
unset LUA_PATH LUA_CPATH; LUASNIP_SOURCE=$(shell pwd) JSREGEXP_PATH=$(shell pwd)/${JSREGEXP_PATH} TEST_FILE=$(realpath tests) BUSTED_ARGS=--lpath=$(shell pwd)/tests/?.lua make -C ${NVIM_PATH} functionaltest
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ https://user-images.githubusercontent.com/41961280/122515860-5179fa00-d00e-11eb-

# 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).
- The LSP-parser does not support Regex-Transformations.

# Requirements
Neovim >= 0.5 (extmarks)
`jsregexp` for lsp-snippet-transformations (see [here](https://github.com/L3MON4D3/LuaSnip/blob/master/DOC.md#transformations) for some tips on installing it)

# Setup
## Install
Expand Down
1 change: 1 addition & 0 deletions deps/jsregexp
Submodule jsregexp added at c3e473
172 changes: 172 additions & 0 deletions deps/lua51_include/lauxlib.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
/*
** $Id: lauxlib.h,v 1.88.1.1 2007/12/27 13:02:25 roberto Exp $
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/


#ifndef lauxlib_h
#define lauxlib_h


#include <stddef.h>
#include <stdio.h>

#include "lua.h"


#if defined(LUA_COMPAT_GETN)
LUALIB_API int (luaL_getn) (lua_State *L, int t);
LUALIB_API void (luaL_setn) (lua_State *L, int t, int n);
#else
#define luaL_getn(L,i) ((int)lua_objlen(L, i))
#define luaL_setn(L,i,j) ((void)0) /* no op! */
#endif

#if defined(LUA_COMPAT_OPENLIB)
#define luaI_openlib luaL_openlib
#endif


/* extra error code for `luaL_load' */
#define LUA_ERRFILE (LUA_ERRERR+1)


typedef struct luaL_Reg {
const char *name;
lua_CFunction func;
} luaL_Reg;



LUALIB_API void (luaI_openlib) (lua_State *L, const char *libname,
const luaL_Reg *l, int nup);
LUALIB_API void (luaL_register) (lua_State *L, const char *libname,
const luaL_Reg *l);
LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e);
LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e);
LUALIB_API int (luaL_typerror) (lua_State *L, int narg, const char *tname);
LUALIB_API int (luaL_argerror) (lua_State *L, int numarg, const char *extramsg);
LUALIB_API const char *(luaL_checklstring) (lua_State *L, int numArg,
size_t *l);
LUALIB_API const char *(luaL_optlstring) (lua_State *L, int numArg,
const char *def, size_t *l);
LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int numArg);
LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int nArg, lua_Number def);

LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int numArg);
LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int nArg,
lua_Integer def);

LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg);
LUALIB_API void (luaL_checktype) (lua_State *L, int narg, int t);
LUALIB_API void (luaL_checkany) (lua_State *L, int narg);

LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname);
LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname);

LUALIB_API void (luaL_where) (lua_State *L, int lvl);
LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...);

LUALIB_API int (luaL_checkoption) (lua_State *L, int narg, const char *def,
const char *const lst[]);

LUALIB_API int (luaL_ref) (lua_State *L, int t);
LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref);

LUALIB_API int (luaL_loadfile) (lua_State *L, const char *filename);
LUALIB_API int (luaL_loadbuffer) (lua_State *L, const char *buff, size_t sz,
const char *name);
LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s);

LUALIB_API lua_State *(luaL_newstate) (void);


LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p,
const char *r);

LUALIB_API const char *(luaL_findtable) (lua_State *L, int idx,
const char *fname, int szhint);




/*
** ===============================================================
** some useful macros
** ===============================================================
*/

#define luaL_argcheck(L, cond,numarg,extramsg) \
((void)((cond) || luaL_argerror(L, (numarg), (extramsg))))
#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL))
#define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL))
#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n)))
#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d)))
#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n)))
#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d)))

#define luaL_typename(L,i) lua_typename(L, lua_type(L,(i)))

#define luaL_dofile(L, fn) \
(luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0))

#define luaL_dostring(L, s) \
(luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0))

#define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n)))

#define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n)))

/*
** {======================================================
** Generic Buffer manipulation
** =======================================================
*/



typedef struct luaL_Buffer {
char *p; /* current position in buffer */
int lvl; /* number of strings in the stack (level) */
lua_State *L;
char buffer[LUAL_BUFFERSIZE];
} luaL_Buffer;

#define luaL_addchar(B,c) \
((void)((B)->p < ((B)->buffer+LUAL_BUFFERSIZE) || luaL_prepbuffer(B)), \
(*(B)->p++ = (char)(c)))

/* compatibility only */
#define luaL_putchar(B,c) luaL_addchar(B,c)

#define luaL_addsize(B,n) ((B)->p += (n))

LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B);
LUALIB_API char *(luaL_prepbuffer) (luaL_Buffer *B);
LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l);
LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s);
LUALIB_API void (luaL_addvalue) (luaL_Buffer *B);
LUALIB_API void (luaL_pushresult) (luaL_Buffer *B);


/* }====================================================== */


/* compatibility with ref system */

/* pre-defined references */
#define LUA_NOREF (-2)
#define LUA_REFNIL (-1)

#define lua_ref(L,lock) ((lock) ? luaL_ref(L, LUA_REGISTRYINDEX) : \
(lua_pushstring(L, "unlocked references are obsolete"), lua_error(L), 0))

#define lua_unref(L,ref) luaL_unref(L, LUA_REGISTRYINDEX, (ref))

#define lua_getref(L,ref) lua_rawgeti(L, LUA_REGISTRYINDEX, (ref))


#define luaL_reg luaL_Reg

#endif
Loading

0 comments on commit 97a51a0

Please sign in to comment.