I have noticed a problem when copy pasting JSON sections. An example, if you would have something like this:
},
{
"test" : "json"
},
{
And you want to copy the object with "test" in it and paste it right after. Copied text:
And paste it right after the closing curly bracket, I get this:,
},
{
"test" : "json"
} ,
{
"test" : "json"
},
{
I think there are two problems here that are kinda intertwined.
First Problem: Replace indentation is not working properly
newIndent is being calculated as 8 spaces, which is correct. Then in the TextUtils.replaceIndent(), we are calcualting the existing indent in order to replace it with the newIndent. It goes like this:
- Initial values:
int existingIndent = Integer.MAX_VALUE;
int indentOfLine = 0;
boolean isEmptyLine = true;
boolean skipToLineEnd = false;
int lineCount = 1;
- First char is
,. Values after:
int existingIndent = Integer.MAX_VALUE;
int indentOfLine = 0;
boolean isEmptyLine = false;
boolean skipToLineEnd = true;
int lineCount = 1;
- Second char is
\n. Values after:
int existingIndent = 0;
int indentOfLine = 0;
boolean isEmptyLine = true;
boolean skipToLineEnd = false;
int lineCount = 2;
test() is returning false since existingIndent > 0 is false. We stop processing here, not checking any other lines.
- Now we add
newIndent to each line. Which means that even the lines with 8 spaces already gets an extra 8 spaces (Because it thinks they dont have any indentation).
Second Problem: newIndent is added to the first line
There looks to be an attempt at not doing this in LanguageConfigurationAutoEditStrategy line 170 with:
final var offsetInLine = command.offset - lineStartOffset;
if (offsetInLine > 0 && doc.get(lineStartOffset, offsetInLine).isBlank()) {
command.offset = lineStartOffset;
command.length += offsetInLine;
}
So the offsetInLine will be more than 0, but the line we paste it into is not empty, since it contains a curly bracket. So we dont move the offset or add to length. I am a bit unsure how moving and adding to command works in the end, but it looks to be working (However the first problem is still present). I guess it replaces from the command.offset() so it deletes the already existing indentation.
I think both of these problems can kinda be resolved by properly handling the first line, or actually just disregarding the first line when replacing the indentation. So doing this instead:
if (newIndent != null) {
final int firstNewline = command.text.indexOf('\n');
if (firstNewline >= 0) {
final String firstLine = command.text.substring(0, firstNewline + 1);
final String rest = command.text.substring(firstNewline + 1);
final var offsetInLine = command.offset - lineStartOffset;
if (offsetInLine > 0 && !doc.get(lineStartOffset, offsetInLine).isBlank()) {
command.text = firstLine + TextUtils.replaceIndent(rest, cursorCfg.indentSize, cursorCfg.normalizeIndentation(newIndent), false).toString();
} else {
if (offsetInLine > 0) {
command.offset = lineStartOffset;
command.length += offsetInLine;
}
command.text = newIndent + firstLine.stripLeading() + TextUtils.replaceIndent(rest, cursorCfg.indentSize, cursorCfg.normalizeIndentation(newIndent), false).toString();
}
} else {
command.text = TextUtils.replaceIndent(command.text, cursorCfg.indentSize, cursorCfg.normalizeIndentation(newIndent), false).toString();
}
command.shiftsCaret = true;
}
This would handle four cases:
- Pasting from offset 0 - we add
newIndent + firstLine and replace indentation on the other ones
- Pasting from offset > 0 and first line is blank - we add
newIndent + firstLine and replace indentation on the other ones, as well as move the offset of the command to account for the already existing indentation of the first line
- Pasting from offset > 0 and first line is not blank - we add
firstLine as it is and replace indentation on the other ones.
- Pasting a single line (And the target is a blank line) - we just replace the indentation of this line
I am unsure how to test this however. But let me know what you think.
Thank you!
I have noticed a problem when copy pasting JSON sections. An example, if you would have something like this:
And you want to copy the object with "test" in it and paste it right after. Copied text:
And paste it right after the closing curly bracket, I get this:,
I think there are two problems here that are kinda intertwined.
First Problem: Replace indentation is not working properly
newIndentis being calculated as 8 spaces, which is correct. Then in theTextUtils.replaceIndent(), we are calcualting the existing indent in order to replace it with thenewIndent. It goes like this:,. Values after:\n. Values after:test()is returning false sinceexistingIndent > 0is false. We stop processing here, not checking any other lines.newIndentto each line. Which means that even the lines with 8 spaces already gets an extra 8 spaces (Because it thinks they dont have any indentation).Second Problem:
newIndentis added to the first lineThere looks to be an attempt at not doing this in
LanguageConfigurationAutoEditStrategyline 170 with:So the
offsetInLinewill be more than 0, but the line we paste it into is not empty, since it contains a curly bracket. So we dont move theoffsetor add tolength. I am a bit unsure how moving and adding tocommandworks in the end, but it looks to be working (However the first problem is still present). I guess it replaces from thecommand.offset()so it deletes the already existing indentation.I think both of these problems can kinda be resolved by properly handling the first line, or actually just disregarding the first line when replacing the indentation. So doing this instead:
This would handle four cases:
newIndent + firstLineand replace indentation on the other onesnewIndent + firstLineand replace indentation on the other ones, as well as move the offset of the command to account for the already existing indentation of the first linefirstLineas it is and replace indentation on the other ones.I am unsure how to test this however. But let me know what you think.
Thank you!