Skip to content

Commit

Permalink
OCL commenter #319
Browse files Browse the repository at this point in the history
  • Loading branch information
giraud committed Mar 21, 2023
1 parent c09beb0 commit 9e3ed25
Show file tree
Hide file tree
Showing 5 changed files with 257 additions and 139 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
## Unreleased

- :bug: [#350](https://github.com/giraud/reasonml-idea-plugin/issues/350) Use declaration documentation if no local documentation
- :bug: [#319](https://github.com/giraud/reasonml-idea-plugin/issues/319) "Comment with line comment" action incorrect for lines ending with "("
- :bug: [#174](https://github.com/giraud/reasonml-idea-plugin/issues/174) Compiler output listener needs a change for ocaml >= 4.09

## 0.110 - 2023/03/01
Expand Down
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ intellij {
changeNotes = """
<ul>
<li>#350 - Use declaration documentation if no local documentation</li>
<li>#319 - "Comment with line comment" action incorrect for lines ending with "("</li>
<li>#174 - Compiler output listener needs a change for ocaml >= 4.09</li>
</ul>
<p><a href="https://github.com/giraud/reasonml-idea-plugin/blob/master/CHANGELOG.md">Full change log...</a></p>
Expand Down
323 changes: 198 additions & 125 deletions src/main/java/com/reason/ide/comment/OclCommenter.java
Original file line number Diff line number Diff line change
@@ -1,133 +1,206 @@
package com.reason.ide.comment;

import com.intellij.lang.Commenter;
import com.intellij.lang.CustomUncommenter;
import com.intellij.openapi.util.Couple;
import com.intellij.openapi.util.TextRange;
import com.intellij.util.text.CharArrayUtil;
import java.util.ArrayList;
import java.util.Collection;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public class OclCommenter implements Commenter, CustomUncommenter {
@Nullable
@Override
public String getLineCommentPrefix() {
return null;
}

@Nullable
@Override
public String getBlockCommentPrefix() {
return "(*";
}

@Nullable
@Override
public String getBlockCommentSuffix() {
return "*)";
}

@Nullable
@Override
public String getCommentedBlockCommentPrefix() {
return "(*";
}

@Nullable
@Override
public String getCommentedBlockCommentSuffix() {
return "*)";
}

@Nullable
@Override
public TextRange findMaximumCommentedRange(@NotNull CharSequence text) {
TextRange commentedRange = null;

// trim start & end
int selectionStart = 0;
selectionStart = CharArrayUtil.shiftForward(text, selectionStart, " \t\n");

int selectionEnd = text.length() - 1;
selectionEnd = CharArrayUtil.shiftBackward(text, selectionEnd, " \t\n") + 1;

// Find how many distinct comments in text
boolean commentStart = CharArrayUtil.regionMatches(text, selectionStart, "(*");
if (commentStart) {
int commentCount = 0;
int nestedComment = 0;
for (int i = selectionStart; i < selectionEnd; i++) {
char c = text.charAt(i);
if (c == '(') {
char c2 = text.charAt(i + 1);
if (c2 == '*') {
nestedComment++;
}
} else if (c == '*') {
char c2 = text.charAt(i + 1);
if (c2 == ')') {
nestedComment--;
if (nestedComment == 0) {
commentCount++;
import com.intellij.codeInsight.generation.*;
import com.intellij.lang.*;
import com.intellij.openapi.editor.*;
import com.intellij.openapi.util.*;
import com.intellij.psi.*;
import com.intellij.util.text.*;
import org.jetbrains.annotations.*;

import java.util.*;

public class OclCommenter implements SelfManagingCommenter<CommenterDataHolder>, Commenter, CommenterWithLineSuffix, CustomUncommenter {
@Override
public @NotNull String getLineCommentPrefix() {
return "(*";
}

@Override
public @NotNull String getLineCommentSuffix() {
return "*)";
}

@Override
public @NotNull String getBlockCommentPrefix() {
return "(*";
}

@Override
public @NotNull String getBlockCommentSuffix() {
return "*)";
}

@Override
public @NotNull String getCommentedBlockCommentPrefix() {
return "(*";
}

@Override
public @NotNull String getCommentedBlockCommentSuffix() {
return "*)";
}

@Override
public @NotNull CommenterDataHolder createLineCommentingState(int startLine, int endLine, @NotNull Document document, @NotNull PsiFile file) {
return EMPTY_STATE;
}

@Override
public @NotNull CommenterDataHolder createBlockCommentingState(int selectionStart, int selectionEnd, @NotNull Document document, @NotNull PsiFile file) {
return EMPTY_STATE;
}

@Override
public void commentLine(int line, int offset, @NotNull Document document, @NotNull CommenterDataHolder data) {
int lineEndOffset = document.getLineEndOffset(line);

CharSequence chars = document.getCharsSequence();
boolean startWithSpace = chars.charAt(offset) == ' ';
boolean endsWithSpace = chars.charAt(lineEndOffset - 1) == ' ';

SelfManagingCommenterUtil.insertBlockComment(offset, lineEndOffset, document, startWithSpace ? "(*" : "(* ", endsWithSpace ? "*)" : " *)");
}

@Override
public void uncommentLine(int line, int offset, @NotNull Document document, @NotNull CommenterDataHolder data) {
CharSequence chars = document.getCharsSequence();

int lineEndOffset = document.getLineEndOffset(line);
int textEndOffset = CharArrayUtil.shiftBackward(chars, lineEndOffset - 1, " \t");

SelfManagingCommenterUtil.uncommentBlockComment(offset, textEndOffset + 1, document, "(*", "*)");
}

@Override
public boolean isLineCommented(int line, int offset, @NotNull Document document, @NotNull CommenterDataHolder data) {
CharSequence charSequence = document.getCharsSequence().subSequence(offset, offset + 2);
return charSequence.toString().equals(getBlockCommentPrefix());
}

@Override
public @NotNull String getCommentPrefix(int line, @NotNull Document document, @NotNull CommenterDataHolder data) {
return "(*";
}

@Override
public @Nullable TextRange getBlockCommentRange(int selectionStart, int selectionEnd, @NotNull Document document, @NotNull CommenterDataHolder data) {
return SelfManagingCommenterUtil.getBlockCommentRange(selectionStart, selectionEnd, document, "(*", "*)");
}

@Override
public @NotNull String getBlockCommentPrefix(int selectionStart, @NotNull Document document, @NotNull CommenterDataHolder data) {
return "(*";
}

@Override
public @NotNull String getBlockCommentSuffix(int selectionEnd, @NotNull Document document, @NotNull CommenterDataHolder data) {
return "*)";
}

@Override
public void uncommentBlockComment(int startOffset, int endOffset, Document document, CommenterDataHolder data) {
CharSequence chars = document.getCharsSequence();

boolean startHasLF = chars.charAt(startOffset + 2) == '\n';
boolean endHasLF = chars.charAt(endOffset - 1 - 2) == '\n';

SelfManagingCommenterUtil.uncommentBlockComment(startOffset, endOffset, document, startHasLF ? "(*\n" : "(*", endHasLF ? "\n*)" : "*)");
}

@Override
public @Nullable TextRange insertBlockComment(int startOffset, int endOffset, Document document, CommenterDataHolder data) {
CharSequence chars = document.getCharsSequence();

boolean startHasLF = chars.charAt(startOffset) == '\n';
boolean endHasLF = chars.charAt(endOffset - 1) == '\n';

return SelfManagingCommenterUtil.insertBlockComment(startOffset, endOffset, document, startHasLF ? "(*" : "(*\n", endHasLF ? "*)\n" : "\n*)");
}

@Override
public @Nullable TextRange findMaximumCommentedRange(@NotNull CharSequence text) {
TextRange commentedRange = null;

// trim start & end
int selectionStart = 0;
selectionStart = CharArrayUtil.shiftForward(text, selectionStart, " \t\n");

int selectionEnd = text.length() - 1;
selectionEnd = CharArrayUtil.shiftBackward(text, selectionEnd, " \t\n") + 1;

// Find how many distinct comments in text
boolean commentStart = CharArrayUtil.regionMatches(text, selectionStart, "(*");
if (commentStart) {
int commentCount = 0;
int nestedComment = 0;
for (int i = selectionStart; i < selectionEnd; i++) {
char c = text.charAt(i);
if (c == '(') {
char c2 = text.charAt(i + 1);
if (c2 == '*') {
nestedComment++;
}
} else if (c == '*') {
char c2 = text.charAt(i + 1);
if (c2 == ')') {
nestedComment--;
if (nestedComment == 0) {
commentCount++;
}
}
}
}

if (commentCount == 1
&& selectionEnd - selectionStart >= 2 + 2
&& CharArrayUtil.regionMatches(text, selectionEnd - 2, "*)")) {
commentedRange = new TextRange(selectionStart, selectionEnd);
}
}
}
}

if (commentCount == 1
&& selectionEnd - selectionStart >= 2 + 2
&& CharArrayUtil.regionMatches(text, selectionEnd - 2, "*)")) {
commentedRange = new TextRange(selectionStart, selectionEnd);
}
}

return commentedRange;
}

@NotNull
@Override
public Collection<? extends Couple<TextRange>> getCommentRangesToDelete(
@NotNull CharSequence text) {
Collection<Couple<TextRange>> ranges = new ArrayList<>();

// should use nearest after all pairs (* *)

int start = getNearest((String) text);
TextRange prefixRange = expandRange(text, start, start + 2);

int end = ((String) text).lastIndexOf("*)");
TextRange suffixRange = expandRange(text, end, end + 2);

ranges.add(Couple.of(prefixRange, suffixRange));
return ranges;
}

@NotNull
private TextRange expandRange(@NotNull CharSequence chars, int delOffset1, int delOffset2) {
int offset1 = CharArrayUtil.shiftBackward(chars, delOffset1 - 1, " \t");
if (offset1 < 0 || chars.charAt(offset1) == '\n' || chars.charAt(offset1) == '\r') {
int offset2 = CharArrayUtil.shiftForward(chars, delOffset2, " \t");
if (offset2 == chars.length()
|| chars.charAt(offset2) == '\r'
|| chars.charAt(offset2) == '\n') {
delOffset1 = (offset1 < 0) ? offset1 + 1 : offset1;
if (offset2 < chars.length()) {
delOffset2 = offset2 + 1;
if (chars.charAt(offset2) == '\r'
&& offset2 + 1 < chars.length()
&& chars.charAt(offset2 + 1) == '\n') {
delOffset2++;
}

return commentedRange;
}

@Override
public @NotNull Collection<? extends Couple<TextRange>> getCommentRangesToDelete(@NotNull CharSequence text) {
Collection<Couple<TextRange>> ranges = new ArrayList<>();

// should use nearest after all pairs (* *)

int start = getNearest((String) text);
TextRange prefixRange = expandRange(text, start, start + 2);

int end = ((String) text).lastIndexOf("*)");
TextRange suffixRange = expandRange(text, end, end + 2);

ranges.add(Couple.of(prefixRange, suffixRange));
return ranges;
}

private @NotNull TextRange expandRange(@NotNull CharSequence chars, int delOffset1, int delOffset2) {
int offset1 = CharArrayUtil.shiftBackward(chars, delOffset1 - 1, " \t");
if (offset1 < 0 || chars.charAt(offset1) == '\n' || chars.charAt(offset1) == '\r') {
int offset2 = CharArrayUtil.shiftForward(chars, delOffset2, " \t");
if (offset2 == chars.length()
|| chars.charAt(offset2) == '\r'
|| chars.charAt(offset2) == '\n') {
delOffset1 = (offset1 < 0) ? offset1 + 1 : offset1;
if (offset2 < chars.length()) {
delOffset2 = offset2 + 1;
if (chars.charAt(offset2) == '\r'
&& offset2 + 1 < chars.length()
&& chars.charAt(offset2 + 1) == '\n') {
delOffset2++;
}
}
}
}
}
return new TextRange(delOffset1, delOffset2);
}
return new TextRange(delOffset1, delOffset2);
}

private static int getNearest(@NotNull String text) {
int result = text.indexOf("(*");
return result == -1 ? text.length() : result;
}
private static int getNearest(@NotNull String text) {
int result = text.indexOf("(*");
return result == -1 ? text.length() : result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,11 @@ static final class OpamLibrary extends SyntheticLibrary implements ItemPresentat
private final String myOpamSwitch;

private @Nullable VirtualFile getOpamSwitchLocation() {
return VirtualFileManager.getInstance().findFileByNioPath(Path.of(myOpamRoot, myOpamSwitch));
try {
return VirtualFileManager.getInstance().findFileByNioPath(Path.of(myOpamRoot, myOpamSwitch));
} catch (InvalidPathException e) {
return null;
}
}

public OpamLibrary(@NotNull String opamRoot, @NotNull String opamSwitch) {
Expand Down
Loading

0 comments on commit 9e3ed25

Please sign in to comment.