Skip to content

Commit

Permalink
fix: Formatting fails when position end is out of range of the document
Browse files Browse the repository at this point in the history
Fixes redhat-developer#183

Signed-off-by: azerr <[email protected]>
  • Loading branch information
angelozerr committed Mar 26, 2024
1 parent 67324b3 commit 5d5b05b
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 3 deletions.
18 changes: 15 additions & 3 deletions src/main/java/com/redhat/devtools/lsp4ij/LSPIJUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -262,9 +262,21 @@ public static Module getModule(@Nullable VirtualFile file, @NotNull Project proj
return ReadAction.compute(() -> ProjectFileIndex.getInstance(project).getModuleForFile(file, false));
}

public static int toOffset(Position start, Document document) throws IndexOutOfBoundsException {
int lineStartOffset = document.getLineStartOffset(start.getLine());
return lineStartOffset + start.getCharacter();
public static int toOffset(@NotNull Position position, @NotNull Document document) throws IndexOutOfBoundsException {
// Adjust position line/character according to this comment https://github.com/microsoft/vscode-languageserver-node/blob/ed3cd0f78c1495913bda7318ace2be7f968008af/textDocument/src/main.ts#L26
int line = position.getLine();
if (line < 0) {
// If a line number is negative, it defaults to 0.
line = 0;
} else {
// If a line number is greater than the number of lines in a document, it defaults back to the number of lines in the document.
line = Math.min(line, document.getLineCount() - 1);
}
int lineStartOffset = document.getLineStartOffset(line);
int lineEndOffset = document.getLineEndOffset(line);
int offset = lineStartOffset + position.getCharacter();
// If the character value is greater than the line length it defaults back to the line length
return Math.min(offset, lineEndOffset - 1);
}

public static Position toPosition(int offset, Document document) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*******************************************************************************
* Copyright (c) 2024 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is made available under the terms of the
* Eclipse Public License v2.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package com.redhat.devtools.lsp4ij;

import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.impl.DocumentImpl;
import com.intellij.testFramework.fixtures.BasePlatformTestCase;
import org.eclipse.lsp4j.Position;

/**
* Tests for {@link LSPIJUtils#toOffset(Position, Document)}.
*/
public class LSPIJUtils_toOffsetTest extends BasePlatformTestCase {

public void testValidPositionWithOneLine() {
assertOffset("foo", 0, 0, 0, 'f');
assertOffset("foo", 0, 1, 1, 'o');
assertOffset("foo", 0, 2, 2, 'o');
}

public void testValidPositionWithTwoLines() {
assertOffset("foo\nbar", 0, 0, 0, 'f');
assertOffset("foo\nbar", 0, 1, 1, 'o');
assertOffset("foo\nbar", 0, 2, 2, 'o');

assertOffset("foo\nbar", 1, 0, 4, 'b');
assertOffset("foo\nbar", 1, 1, 5, 'a');
assertOffset("foo\nbar", 1, 2, 6, 'r');
}

public void testInvalidLineWithOneLine() {
assertOffset("foo", 999999, 0, 0, 'f');
assertOffset("foo", 999999, 1, 1, 'o');
assertOffset("foo", 999999, 2, 2, 'o');
}

public void testInvalidLineWithTwoLines() {
assertOffset("foo\nbar", 999999, 0, 4, 'b');
assertOffset("foo\nbar", 999999, 1, 5, 'a');
assertOffset("foo\nbar", 999999, 2, 6, 'r');
}

public void testInvalidCharacterWithOneLine() {
assertOffset("foo", 0, 999999, 2, 'o');
}

public void testInvalidCharacterWithTwoLines() {
assertOffset("foo\nbar", 0, 999999, 2, 'o');
assertOffset("foo\nbar", 1, 999999, 6, 'r');
}

public void assertOffset(String content, int line, int character, int expectedOffset, char expectedChar) {
assertOffset(content, new Position(line, character),expectedOffset, expectedChar);
}

public void assertOffset(String content, Position position, int expectedOffset, char expectedChar) {
Document document = new DocumentImpl(content);
int actualOffset = LSPIJUtils.toOffset(position, document);
assertEquals(expectedOffset, actualOffset);
// get the character from the given offset
char actualChar = document.getCharsSequence().charAt(expectedOffset);
assertEquals(expectedChar, actualChar);
}


}

0 comments on commit 5d5b05b

Please sign in to comment.