Comment.nvim icon indicating copy to clipboard operation
Comment.nvim copied to clipboard

Support advanced multiline strings in lua e.g. --[=[ something ]=]

Open Corey-Keller opened this issue 3 years ago • 3 comments

Just from reading the readme it sounds like this might be possible using the pre_hook, but I'm not sure exactly how I'd go about it.

I have copied the text below from my kommentary request for the same functionality (b3nj5m1n/kommentary#67)


Lua supports semi-arbitrary multiline comment strings in the form of matching numbers of equals signs. Meaning --[==[, --[===[, and --[=[ will only end the comment when it encounters ]==], ]===], and ]=] respectively.

It would be a great idea to match an opening regex like --\[\(=*\)\[ (or --\[(=*)\[ in PCRE style just to make sure it's clear) to the closing ]\1] (using the capture group from the opening regex to guarantee the same number of =)

This may not be as important when creating the comments, but is important to effectively uncomment them.

Corey-Keller avatar Oct 07 '21 15:10 Corey-Keller

Honestly, when I was searching through kommentary issues, I saw your request there 😄 .

Currently, I also don't know how to solve this but this is certainly going to be fun to implement. Would you mind sharing any kind of guide where I can read more about those comments?

numToStr avatar Oct 07 '21 15:10 numToStr

Honestly, when I was searching through kommentary issues, I saw your request there smile .

Currently, I also don't know how to solve this but this is certainly going to be fun to implement. Would you mind sharing any kind of guide where I can read more about those comments?

It's actually a string feature that applies to any string in double brackets [[ like this one ]], which lua just extends to block comments.

[===[ This lets me put '[[', ']=]', or ']======]' (or any double bracket with 0+ '=' in the middle, so long as it's not the same as the surrounding one) inside this string without issue. ]===]

http://lua-users.org/wiki/StringsTutorial

Corey-Keller avatar Oct 07 '21 16:10 Corey-Keller

Interesting I'll try to implement this. Once I handled some edge cases in the current logic. I'll update here once I start working on it :)

numToStr avatar Oct 07 '21 17:10 numToStr

Hi there, I'm a big fan of this plugin and would very much like to have this as a feature; far too many times I've decided to comment out a few lines just to find that some nested comment breaks compatibility. I don't really know much about the internal code structure, but I'm willing to try my hand at making this a reality. AFAIK Lua patterns aren't PCRE, but I was playing around with the Tree-sitter playground and think that if you converted a comment to a single string, you could pattern-match it like the following:

-- Extract the comment text from a Tree-sitter node
local comment = "--[[ some comment\nmore text\n ]=]"
-- Match it and capture the amount of equal signs
local ok, _, open, close = comment:find("^--%[(=*)%[.-%](=*)%]$")
-- Check if a match is found, and if the equals signs are "balanced"
if ok and (#open == #close) then
    local count = #open + 1
    local comment = {
        "--[" .. ("="):rep(count) .. "[",
        "]" .. ("="):rep(count) .. "]",
    }
end

Obviously it would be a lot more involved, but hopefully somebody could give me a few pointers around the codebase?

kylechui avatar Aug 06 '22 03:08 kylechui

The main reason that I didn't make the commenstring, inside the plugin, regex based because I need compatibility and ability to fallback to vim.bo.commenstring. And sometimes I also need the actual length of the left and right side the commenstring for string.sub. Which results to, obviously, no regex and pattern matching.

I think, the only way to pull this off is using pre_hook and vim.v.count (to control the no. of =)

numToStr avatar Aug 06 '22 09:08 numToStr

I don't think I'm quite following why having vim.bo.commenstring as a fallback implies that pattern matching is infeasible. As for your other point, would finding the length of the match groups in str.find not find the lengths of the left/right comment pair for you? I hope I'm not coming across as rude, I'm just trying to better understand the situation

kylechui avatar Aug 06 '22 21:08 kylechui

I don't think I'm quite following why having vim.bo.commenstring as a fallback implies that pattern matching is infeasible. As for your other point, would finding the length of the match groups in str.find not find the lengths of the left/right comment pair for you?

I was wrong about the length and string.sub part. After taking a another look in the code; the reason the left/right part should be kept static is to be able to comment the line initially. https://github.com/numToStr/Comment.nvim/blob/master/lua/Comment/utils.lua#L195

And I believe your, earlier, snippet doesn't consider the initial commenting.

I hope I'm not coming across as rude, I'm just trying to better understand the situation

Nope, not at all. On the contrary, i quite enjoy a healthy discussion.

numToStr avatar Aug 07 '22 05:08 numToStr

After taking a another look in the code; the reason the left/right part should be kept static is to be able to comment the line initially.

Oh wow this is a bit similar to the internals for my plugin haha. I'm afraid I still don't quite get why the left/right part has to be static in order to comment the line; the code snippet you sent seems like it would work just fine if the left/right were different, since you're just appending strings to the beginning/end of a table.

kylechui avatar Aug 07 '22 06:08 kylechui

the code snippet you sent seems like it would work just fine if the left/right were different, since you're just appending strings to the beginning/end of a table.

I don't think so, let me ask you how would you append a pattern i.e "^--%[(=*)%.-%%]$" to a string/line? Just curious.

numToStr avatar Aug 07 '22 06:08 numToStr

Ah, let me try and rephrase what my initial idea was:

  • The user passes in some selection and calls one of the commenting functions
  • The plugin traverses the selection for all nodes of type comment that are contained in the selection, and uses Lua pattern-matching to discern how many equals signs there are in the open/closing comment block (0 or more)
  • The plugin computes what's the first unused number, then creates a new static string pair based on it
  • The plugin surrounds the text selection with the comment pair

Sorry if I'm still misunderstanding the underlying code structure (and so over-simplifying the problem), but this is just one of the ideas that I thought of

kylechui avatar Aug 07 '22 06:08 kylechui

The plugin traverses the selection for all nodes of type comment that are contained in the selection, and uses Lua pattern-matching to discern how many equals signs there are in the open/closing comment block (0 or more)

I am assuming you are talking about treesitter for nodes calculation; Inside the plugin treesitter is only used for calculating embedded language and this sounds way more work. And about the pattern, I have to store the pattern and I have to remind myself of the use-case.

So TBH, everything sounds complicated and requires more maintenance on my end (for something that I probably never use).

Anyway, here is a brief architecture of the plugin

- start

- Pick commentstring either linewise/blockwise from one of the following places 
    1. pre_hook (if string is returned)
    2. stored inside the plugin using treesitter
    3. vim.bo.commentstring

> Every is_comment check below is made using the commentstring calculated in the above step

- Checking the range
    - when linewise
        1. if every line is commented
            1.1 uncomment

        2. else
            2.1 find the column no. to start the comment from (need to respect the indentation)
            2.2 comment

    - when blockwise
        1. if the first line or start of the block is commented with LHS
           and the last line or end of the block is commented with RHS
           1.1 uncomment

        2. else
            2.1 Prepend the LHS into the first line
            2.2 Append the RHS into the last line

    > When doing visual block I can't preprend or append,
    > so in this case we need to slice and concat the line,
    > putting RHS and LHS into right place when doing comment
    > and removing LHS and RHS when uncomment

- end

Edit: I hope this will give you an idea of how things are implemented inside the plugin :)

numToStr avatar Aug 07 '22 14:08 numToStr

Thanks for the high-level description! Yeah it does seem like quite a bit of extra work, especially because it seems like this would need to be "hard-coded" to a certain extent for Lua in particular. I can't really think of any other programming languages at the moment that have this sort of behavior. Your point about code maintenance makes sense; thanks for taking the time to explain your thought processes and for such a great plugin!

kylechui avatar Aug 07 '22 20:08 kylechui

I am moving this from issues to discussion for other people to come up with solution for this. As I think it might be not feasible to support this natively.

numToStr avatar Aug 13 '22 10:08 numToStr