-
-
Notifications
You must be signed in to change notification settings - Fork 193
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix #707 #1058
Fix #707 #1058
Conversation
Thank you so much for this work. I was a bit out of the loop for the last couple months as the world gone crazy again... I'm going to merge this as you included tests and all and presumably have been using this since december. In case there will be troubles we can always revert and this seems to be already useful and with a lot of demand. Sorry for the delay! If you plan to do some further improvements on elixir let me know and I'll add you as a contributor so you can merge further changes on your own. |
Thanks! I'm not writing in Elixir, was just trying the language back then, and was a bit upset with the support, so I just got my time trying to solve the issue 🙂 . So I don't think I will come back to Elixir in near future, as I prefer Erlang over it, but I may be working on Lua module, as it has very similar problem. Although I don't write Lua directly, rather using a transpiler, I still read and navigate Lua code, so good support for it much more needed for me. However, I would like to come up with a more general solution, maybe a more robust searcher, or a rather simple code walker with stack like approach, so if you have any thoughts on how Smartparens could handle such languages, which have all these context dependent |
We basically already use a stack-based search and this is not powerful enough. Ours is probably a little bit more powerful than the canonical CFG but not by much. However, with the callbacks (unless, when, skip) the system is complete in a sense it can parse anything parsable. Although the API is quite bad to work with as you are writing a lot of extra code which is executed "somehow" and it lacks structure. So it ends up being ad-hoc for each langauge. Ultimately an LSP-based search would be best, but I'm not sure LSP supports such API (i.e. give me corresponding delimiter to this one at point). And I'm not sure what the performance would be... maybe it would be faster to get all pairs in a region/document. I'm sure it can serve AST already. |
I still think that TreeSitter approach is better, because, it is a tool built for working with AST, and is fast enough to parse huge files on every keypress, which makes it mostly ideal for languages with a lot of ambiguity, as you maintain the correct tree and can recover from errors in a meaningful way. LSP has the communication lag, which may be not great for structural editing, where you shuffle branches around. Second, writing a grammar for tree sitter is kinda easier than implementing this in LSP, which opens support for more languages (in theory), e.g. TreeSitter supports languages which do not have LSP implementation at all. The downside is that we're tying ourselves to specific technology, which is not great, but can also be said about LSP, though the support behind LSP is much greater. My thought was that we can build a successive lookahead/behind first-error stack based search engine, which I was trying to do here. So for example, in Lua case, where for i = 0, 10 do
print i
do
█
local j = i + 10
print j
end
end so we want to do I hope this makes sense :) |
It makes complete sense and it's very clever! Is this how TreeSitter works in general or is this only the approach you took here? I heard about TreeSitter before but honestly that's about it, I knew it existed. I am generally not biased towards LSP as the input lag is exactly what I was afraid of. If something else is much faster and "practically synchronous", that would be my first choice. I guess once a generic support for it is written, extra languages can be added by anyone implementing the grammar, so that seems like a worthy pursuit. |
It makes complete sense and it's very clever! Is this how TreeSitter works
in general or is this only the approach you took here?
That's what I've implemented in this PR, although it's not generic, and not
as precise, as I don't maintain stack, so it is limited to search of depth
1. But the idea is roughly the same.
Tree sitter is completely different, as it is a generalized LR parser, with
some extensions.
I will look into implementing this search algorithm in near future
|
This is second attempt to fix #707 which lifts off limitation that matching keyword must be at the same line as
do
, e.g. it works for this particular example:This PR adds two search functions, that walk file line by line and check if line has given set of keywords at the start of the line. I'm not sure if this is optimal way to handle this, but it already works better than current implementation as it allows multiline definitions. I've benchmarked search functions on a medium sized file and the performance seems OK.
Check-list for what's needed to be done:
Caveats:
Since the search is line-based and there are no special heuristics to check if both
do:
anddo
are part of definition, this will not work:This can be fixed by implementing word-based search, which is possible to do, however proven to be extremely slow.
Also, some keys might not be handled rightnow, as I've found recently,
defimpl
usesfor:
keyword, which this algorithm supports, however if any other keywords support something similar, they'll need to be added manually in future PRs.Overall parsing algorithm implemented here is not great, but works okayish