Skip to content
This repository has been archived by the owner on Sep 6, 2021. It is now read-only.

Block Comment Improvements/Fixes #7135

Merged
merged 6 commits into from
May 19, 2014
Merged

Block Comment Improvements/Fixes #7135

merged 6 commits into from
May 19, 2014

Conversation

TomMalbran
Copy link
Contributor

This is a remake of PR #3060 which greatly simplifies the search for Block Comments and fixes the issues of having line comments delimiters be a prefix of block comment delimiters and the issue when the block comment delimiters use the same string.

…ents as prefix of bock comments and equal block comments delimiters
if (!result || ctx.token.type !== "comment" || ctx.token.string.match(suffixExp)) {
// Is a range of text selected? (vs just an insertion pt)
var hasSelection = (sel.start.line !== sel.end.line) || (sel.start.ch !== sel.end.ch);
// Next, move forwards until we find a comment inside the selection
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From here until the part when we actually do the block commenting, the code is completely different, which might make it easier to read the actual code and not this diff. This comment can explain better how it works.

@TomMalbran
Copy link
Contributor Author

@njx Merged this with master, so it now works with CM v4. All tests are passing too.

@njx
Copy link

njx commented Mar 21, 2014

Great! Thanks for integrating it with the new v4 stuff - looks like you didn't really have to touch the multiselect bit much. I'll try to review this next week.

@TomMalbran
Copy link
Contributor Author

The big improvements here is the way it finds the block comment and that part didn't changed with multiselect. Explained in more detail in this comment. This also fixes the issue with line comments delimiters that are a suffix of block comment delimiters and that is what changed in the line comment section.

Let me know if you when you need this to be merged with master.

@njx
Copy link

njx commented Apr 1, 2014

Hey - sorry, I got swamped with stuff and didn't get to review this yet, but I haven't forgotten about it :) It's at the top of my list for this week to at least do an initial review - depending on when we branch for release it might land in the next release after this one though.

@TomMalbran
Copy link
Contributor Author

It is ok, but it got out of sync again, so let me know when you want to merge it with master.

@joaoafrmartins
Copy link

+1!

@joaoafrmartins
Copy link

i would love to get involved in this... there are things that seem to be missing for coffeescript support like auto close block comments... sintax highlightning for function definitions like () -> .... am i missing some extension? how can i help improve this? should i develop an extension? is this getting built in support?

@peterflynn
Copy link
Member

@joaoafrmartins if you're seeing syntax highlighting problems, that won't be addressed by this pull request. Can you check if the problems also occur here, and if so file a bug on CodeMirror? (If not please file a new, separate Brackets bug).

Auto-closing block comments is not implemented in Brackets for any language yet. I've added a user story to our backlog for this: Auto insert close of block comment. Please upvote it to help raise its priority.

Edit: in the meantime you could write a simple extension to add the auto-close functionality just for CoffeeScript. See the reasonable comments extension which does similar things for /*-style comments.

@njx
Copy link

njx commented Apr 11, 2014

@TomMalbran I took the liberty of merging it with master so I could play with it - the changes were pretty small (the main thing was in EditorCommandHandlers where we changed calls to trim() to use regexps instead).


for (i = lineSyntax.length; i < blockSyntax.length; i++) {
character = blockSyntax.charAt(i);
subExps.push(prevChars + "[^" + character + "]");
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to StringUtils.regexEscape() the character?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should, just in case. Fixed it

@njx
Copy link

njx commented Apr 12, 2014

@TomMalbran - started reviewing this but won't get a chance to finish today. Will keep picking away at it when I have time.

@njx
Copy link

njx commented Apr 14, 2014

Found a broken case: in CoffeeScript mode, enter this:

### x ###

# foo

and put the cursor on the blank line, then do Toggle Block Comment. It deletes the ### from the start of the previous line but leaves the ### at the end.

It seems like we should be careful not to move past the current line when doing the initial check for whether the current line has a comment or not. Maybe we could add a couple of different token steppers (e.g. moveNextTokenOnLine, movePrevTokenOnLine) in TokenUtils that just stop at the end/beginning of the line.

if (_matchExpressions(ctx.token.string, lineExp)) {
// If the token starts at ch 0 with no starting white spaces, then this might be a block comment or a line
// comment over the whole line, and if we found this comment at the start of the selection, we need to search
// backwards until we get can tell if we are in a block or a line comment
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand this case. If I'm understanding correctly, the issue here might be that we're immediately before a line comment, but might be inside an outer block comment. I'm not sure why that case can only occur if the line comment starts at the very beginning of a line - wouldn't the same issue occur if the line comment started later on the line after whitespace?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Looks like you didn't respond to this comment - I wonder if it's related to the case I mention below, where the line comments start after some indentation.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I missed this comment. That is because if we are after the first line of a block comment that spans multiple lines, the string returned from the context actually starts from the char 0, so every whitespace before the comment is included in the string and get the correct type of comment. So if there are whitespaces at the start of the string and has a type of comment we know that it is a block comment. The only case where we don't know what happens is when the string starts with a line comment prefix.

If we have:

/* comment
 |  // line comment
*/

The string in the context at the cursor is actually // line comment and the position starts on the column 0. If there wasn't a block comment surrounding the line comment, the string would be // line comment and the position wouldn't start on the column 0.

Now if we have:

/* comment
// |line comment
*/

You can't tell, at the cursor context, if is a line comment or a block comment.

@TomMalbran
Copy link
Contributor Author

Moving the Token on line will not help in this case, since the line is empty or is only whitespaces, and the token is empty. So we need to move to the previous token to see what is happening. We could either be inside a comment or not.

The fix should first be able to find the block comment suffix and after that we should check if the cursor from the initial position is between the prefix and suffix. I think I am doing something similar for another case.


// If we are in a line that only has a prefix or a suffix and the prefix and suffix are the same string,
// lets find first if this is a prefix or suffix and move the token to the inside of the block comment.
// This is required so that later we can find the prefix by moving backwards and the suffix by moving forwards.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is slightly confusing since it implies that the ctx will always end up after the prefix of the block comment, but in at least one case (where the comment is empty and the initial pos was inside the comment) it will actually end up before the prefix. That case seems to be okay since below we start at the current token to see if it matches the prefix, but it's worth clarifying here that that edge case is correct.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I refer to the inside of the block comment, it means that the ctx will be after the prefix and before the suffix, or at least the string of the ctx will be at the prefix or suffix.

invalidComment = result && !!ctx.token.string.match(prefixExp);

// We moved the token at the start when it was in a whitespace, but maybe we shouldn't have done it
if (prefixPos && editor.indexFromPos(sel.end) < editor.indexFromPos(prefixPos)) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More efficient to check CodeMirror.cmpPos(sel.end, prefixPos) < 0)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@njx
Copy link

njx commented Apr 14, 2014

Initial review done. Overall the new algorithm seems pretty straightforward. I never really looked at the old code, though, and don't have all the use cases in my head, so can't really evaluate the code from that perspective, but luckily the existing unit tests seem to quite extensively cover all the desired cases for existing languages, so it seems like we're good there.

A couple of general thoughts:

  • It might be worth summarizing a few more of the use cases in the main comment above the _getBlockCommentPrefixSuffixEdit() function. For example, it seems like if the selection contains multiple block comments, we intentionally do nothing - probably worth mentioning at the top. I know we don't want to describe every edge case (that's what the unit tests are for :)), but seems like it's worth describing the major edge cases.
  • (Along those lines, the comment above that function refers to slashComments, which no longer seems to be a parameter. That paragraph probably needs to be rewritten.)
  • Is there any way in which multiple selections might affect some of the new behaviors? I don't think so, but just wanted to ask the question.

@TomMalbran
Copy link
Contributor Author

Thanks for the review. I probably won't be able to work on the comments this week, but i'll try to do it next week.

You are right. That comment is really outdated. slashComments was replaced with linePrefixes when I added multiple line prefixes, and is now a required parameter and not an optional as before.

I don't think that the new code might affect the multiple selections, since I haven't touched the code that deals with the selections, and I am still not sure how it actually works.

@njx
Copy link

njx commented Apr 14, 2014

Yeah - I guess what I meant with the last one is whether there would be some user-visible case where having multiple selections should do something different than you would expect by just iterating over each selection independently (and that would be specific to the new cases). But I just discovered that there were already cases (in current master) where the multiple-selection stuff isn't doing the right thing anyway - for example, if you have multiple cursors inside a single block comment, hitting toggle block comment does nothing (because it ends up generating overlapping edits, which get rejected by the doMultipleEdits stuff). I don't think there's anything specific to multiple selections with the new CoffeeScript-like cases, and anyway we should probably fix the other issues more generally (though they're also probably not super important). I'll file them separately.

@njx
Copy link

njx commented Apr 14, 2014

Filed the latter as #7510

// Save the initial position to start searching for the suffix from here
initialPos = $.extend({}, ctx.pos);

// Find the position of the start of the prefix
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

grammar nit: should be "find the starting position of the prefix"

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's also grammatically correct as-is though

@TomMalbran
Copy link
Contributor Author

@njx I fixed all the comments and the case you mentioned, and added a few more tests, including one for the case you mentioned.

@njx
Copy link

njx commented May 5, 2014

Thanks, will try to take a look later this week.

@njx
Copy link

njx commented May 16, 2014

Hey - finally got around to looking at this again. It's too bad it took me so long, because I've forgotten the context of most of my original comments :(, but the changes seem to make sense.

I've found a few more issues, though: (but maybe we don't need to fix all of them)

  • If you have a single-line block comment, e.g. /* foo */ in CSS, and put the cursor within the ending string (e.g. between the * and / in this case), then toggle block comment, it adds a new empty block comment instead of removing the existing block comment. This works correctly in master.
  • In master, if I have indented line comments and some blank lines, like:
    // a comment

    // another comment

and select across them, then toggle line comment, it will remove the line comments. With this PR, it adds another level of line comments. This is a bit of an edge case (it seems to work if there are no blank lines), but it is a style some people use. (Though if they are using it, they won't be happy with the way we add line comments, since we always add them at the beginning of the line.)

  • In CoffeeScript, if I have a few lines that have block comments and some that don't, like:
### a comment ###
alert "foo!"
### another comment ###

and then I select all the lines and toggle line comment multiple times, it keeps adding line comments instead of toggling them on and off. I almost think I don't care about this case :), because at that point it seems hard to detect what the heck is going on anyway. But I imagine it could annoy some people. I could live with not fixing this and seeing if anyone complains about it.

@TomMalbran
Copy link
Contributor Author

@njx I fixed the comments and the first 2 cases you mentioned. I don't know how to fix the last one since is an issue with the RegExp created for the line comment delimiters.

If you have a single-line block comment, e.g. /* foo */ in CSS, and put the cursor within the ending string (e.g. between the * and / in this case), then toggle block comment, it adds a new empty block comment instead of removing the existing block comment. This works correctly in master.

Fixed this and added a new test for it.

In master, if I have indented line comments and some blank lines, like: ... and select across them, then toggle line comment, it will remove the line comments. With this PR, it adds another level of line comments. This is a bit of an edge case (it seems to work if there are no blank lines), but it is a style some people use. (Though if they are using it, they won't be happy with the way we add line comments, since we always add them at the beginning of the line.)

I was trying to fix the other issue you mentioned on the first review and had the problem of having _containsNotLineComment returning true on empty lines. So the change I did here fixed that but broke other stuff. Anyway, I noticed that the change done to check if we found a block comment outside of the initial selection fixes this case too, so I removed the new code there.

In CoffeeScript, if I have a few lines that have block comments and some that don't, like: ... and then I select all the lines and toggle line comment multiple times, it keeps adding line comments instead of toggling them on and off. I almost think I don't care about this case :), because at that point it seems hard to detect what the heck is going on anyway. But I imagine it could annoy some people. I could live with not fixing this and seeing if anyone complains about it.

I am not sure how to fix this. We would need to change the RegExps created for the line comment delimiters somehow to include this cases. The code in _createSpecialLineExp create those RegExp following this #3060 (comment) by @peterflynn.

Ready for another review.

@njx
Copy link

njx commented May 19, 2014

Looks good. Merging (finally!)

njx pushed a commit that referenced this pull request May 19, 2014
@njx njx merged commit a0ca546 into master May 19, 2014
@njx
Copy link

njx commented May 19, 2014

Thanks for persevering with this @TomMalbran :)

@njx njx deleted the tom/block-comment-improvements branch May 19, 2014 23:29
@TomMalbran
Copy link
Contributor Author

Woot!!! Thanks

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants