Skip to content

Commit d0fe8a7

Browse files
committed
[FEATURE] CSV Usages Handler added
- includes several code reworks for better re-use and improved performance Fixes #30
1 parent 3b395b3 commit d0fe8a7

20 files changed

+250
-95
lines changed
Lines changed: 8 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package net.seesharpsoft.intellij.plugins.csv;
22

3-
import com.intellij.lang.annotation.*;
3+
import com.intellij.lang.annotation.Annotation;
4+
import com.intellij.lang.annotation.AnnotationHolder;
5+
import com.intellij.lang.annotation.Annotator;
6+
import com.intellij.lang.annotation.HighlightSeverity;
47
import com.intellij.openapi.editor.markup.AttributesFlyweight;
58
import com.intellij.openapi.editor.markup.TextAttributes;
69
import com.intellij.psi.PsiElement;
@@ -9,45 +12,27 @@
912
import net.seesharpsoft.intellij.plugins.csv.psi.CsvTypes;
1013
import org.jetbrains.annotations.NotNull;
1114

12-
import java.util.Map;
13-
1415
public class CsvAnnotator implements Annotator {
1516

1617
private static final TextAttributes EMPTY_TEXT_ATTRIBUTES = TextAttributes.fromFlyweight(AttributesFlyweight.create(null, null, 0, null, null, null));
1718

1819
@Override
1920
public void annotate(@NotNull final PsiElement element, @NotNull AnnotationHolder holder) {
20-
if (CsvHelper.getElementType(element) != CsvTypes.FIELD) {
21+
if (CsvHelper.getElementType(element) != CsvTypes.FIELD || !(element.getContainingFile() instanceof CsvFile)) {
2122
return;
2223
}
2324

24-
AnnotationSession currentAnnotationSession = holder.getCurrentAnnotationSession();
25-
Map<Integer, CsvColumnInfo<PsiElement>> columnInfoMap = currentAnnotationSession.getUserData(CsvHelper.COLUMN_INFO_KEY);
26-
if (columnInfoMap == null) {
27-
columnInfoMap = CsvHelper.createColumnInfoMap((CsvFile)element.getContainingFile());
28-
currentAnnotationSession.putUserData(CsvHelper.COLUMN_INFO_KEY, columnInfoMap);
29-
}
30-
31-
CsvColumnInfo<PsiElement> columnInfo = getColumnInfo(element, columnInfoMap);
25+
CsvFile csvFile = (CsvFile)element.getContainingFile();
26+
CsvColumnInfo<PsiElement> columnInfo = csvFile.getMyColumnInfoMap().getColumnInfo(element);
3227

3328
if (columnInfo != null) {
3429
PsiElement headerElement = columnInfo.getHeaderElement();
3530
String message = XmlStringUtil.escapeString(headerElement == null ? "" : headerElement.getText(), true);
3631
String tooltip = XmlStringUtil.wrapInHtml(String.format("%s<br /><br />Column: %s<br />Index: %d", XmlStringUtil.escapeString(element.getText(), true), message, columnInfo.getColumnIndex()));
3732

38-
Annotation annotation = holder.createAnnotation(HighlightSeverity.WARNING, element.getTextRange(), message, tooltip);
33+
Annotation annotation = holder.createAnnotation(HighlightSeverity.INFORMATION, element.getTextRange(), message, tooltip);
3934
annotation.setEnforcedTextAttributes(EMPTY_TEXT_ATTRIBUTES);
4035
annotation.setNeedsUpdateOnTyping(false);
4136
}
4237
}
43-
44-
protected CsvColumnInfo<PsiElement> getColumnInfo(@NotNull final PsiElement element, @NotNull Map<Integer, CsvColumnInfo<PsiElement>> columnInfoMap) {
45-
for (Map.Entry<Integer, CsvColumnInfo<PsiElement>> entry : columnInfoMap.entrySet()) {
46-
CsvColumnInfo<PsiElement> columnInfo = entry.getValue();
47-
if (columnInfo.containsElement(element)) {
48-
return columnInfo;
49-
}
50-
}
51-
return null;
52-
}
5338
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package net.seesharpsoft.intellij.plugins.csv;
2+
3+
import java.util.Collections;
4+
import java.util.HashMap;
5+
import java.util.Map;
6+
7+
public class CsvColumnInfoMap<T> {
8+
9+
private final Map<Integer, CsvColumnInfo<T>> infoColumnMap;
10+
private final Map<T, CsvColumnInfo<T>> reverseInfoColumnMap;
11+
12+
public CsvColumnInfoMap(Map<Integer, CsvColumnInfo<T>> infoColumnMap) {
13+
this.infoColumnMap = infoColumnMap;
14+
this.reverseInfoColumnMap = new HashMap<>();
15+
buildReverseMap();
16+
}
17+
18+
private void buildReverseMap() {
19+
for (CsvColumnInfo<T> columnInfo : this.infoColumnMap.values()) {
20+
for (T element : columnInfo.getElements()) {
21+
this.reverseInfoColumnMap.put(element, columnInfo);
22+
}
23+
}
24+
}
25+
26+
public CsvColumnInfo<T> getColumnInfo(T element) {
27+
return reverseInfoColumnMap.get(element);
28+
}
29+
30+
public CsvColumnInfo<T> getColumnInfo(int columnIndex) {
31+
return infoColumnMap.get(columnIndex);
32+
}
33+
34+
public Map<Integer, CsvColumnInfo<T>> getColumnInfos() {
35+
return Collections.unmodifiableMap(this.infoColumnMap);
36+
}
37+
}

src/main/java/net/seesharpsoft/intellij/plugins/csv/CsvHelper.java

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import com.intellij.lang.*;
44
import com.intellij.lexer.Lexer;
55
import com.intellij.openapi.project.Project;
6-
import com.intellij.openapi.util.Key;
76
import com.intellij.psi.PsiElement;
87
import com.intellij.psi.PsiManager;
98
import com.intellij.psi.TokenType;
@@ -22,8 +21,6 @@
2221

2322
public class CsvHelper {
2423

25-
public static final Key<Map<Integer, CsvColumnInfo<PsiElement>>> COLUMN_INFO_KEY = Key.create("COLUMN_INFO_KEY");
26-
2724
// replaces PsiElementFactory.SERVICE.getInstance(element.getProject()).createDummyHolder("<undefined>", CsvTypes.FIELD, null);
2825
// https://github.com/SeeSharpSoft/intellij-csv-validator/issues/4
2926
public static PsiElement createEmptyCsvField(Project project) {
@@ -45,7 +42,19 @@ public static IElementType getElementType(PsiElement element) {
4542
}
4643

4744
public static PsiElement getParentFieldElement(PsiElement element) {
48-
if (CsvHelper.getElementType(element) == TokenType.WHITE_SPACE) {
45+
IElementType elementType = CsvHelper.getElementType(element);
46+
47+
if(elementType == CsvTypes.COMMA || elementType == CsvTypes.CRLF) {
48+
element = element.getPrevSibling();
49+
elementType = CsvHelper.getElementType(element);
50+
}
51+
52+
if(elementType == CsvTypes.RECORD) {
53+
element = element.getLastChild();
54+
elementType = CsvHelper.getElementType(element);
55+
}
56+
57+
if (elementType == TokenType.WHITE_SPACE) {
4958
if (CsvHelper.getElementType(element.getParent()) == CsvTypes.FIELD) {
5059
element = element.getParent();
5160
} else if (CsvHelper.getElementType(element.getPrevSibling()) == CsvTypes.FIELD) {
@@ -56,14 +65,15 @@ public static PsiElement getParentFieldElement(PsiElement element) {
5665
element = null;
5766
}
5867
} else {
59-
while (element != null && CsvHelper.getElementType(element) != CsvTypes.FIELD) {
68+
while (element != null && elementType != CsvTypes.FIELD) {
6069
element = element.getParent();
70+
elementType = CsvHelper.getElementType(element);
6171
}
6272
}
6373
return element;
6474
}
6575

66-
public static Map<Integer, CsvColumnInfo<PsiElement>> createColumnInfoMap(CsvFile csvFile) {
76+
public static CsvColumnInfoMap<PsiElement> createColumnInfoMap(CsvFile csvFile) {
6777
Map<Integer, CsvColumnInfo<PsiElement>> columnInfoMap = new HashMap<>();
6878
CsvRecord[] records = PsiTreeUtil.getChildrenOfType(csvFile, CsvRecord.class);
6979
int row = 0;
@@ -81,7 +91,6 @@ public static Map<Integer, CsvColumnInfo<PsiElement>> createColumnInfoMap(CsvFil
8191
}
8292
++row;
8393
}
84-
return columnInfoMap;
94+
return new CsvColumnInfoMap(columnInfoMap);
8595
}
86-
8796
}

src/main/java/net/seesharpsoft/intellij/plugins/csv/formatter/CsvFormattingInfo.java

Lines changed: 4 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,13 @@
33
import com.intellij.formatting.SpacingBuilder;
44
import com.intellij.lang.ASTNode;
55
import com.intellij.psi.codeStyle.CodeStyleSettings;
6-
import net.seesharpsoft.intellij.plugins.csv.settings.CsvCodeStyleSettings;
76
import net.seesharpsoft.intellij.plugins.csv.CsvColumnInfo;
7+
import net.seesharpsoft.intellij.plugins.csv.CsvColumnInfoMap;
8+
import net.seesharpsoft.intellij.plugins.csv.settings.CsvCodeStyleSettings;
89

9-
import java.util.HashMap;
1010
import java.util.Map;
1111

12-
public class CsvFormattingInfo {
13-
private Map<Integer, CsvColumnInfo<ASTNode>> infoColumnMap;
14-
15-
private Map<ASTNode, CsvColumnInfo<ASTNode>> reverseInfoColumnMap;
12+
public class CsvFormattingInfo extends CsvColumnInfoMap<ASTNode> {
1613

1714
public SpacingBuilder getSpacingBuilder() {
1815
return spacingBuilder;
@@ -31,27 +28,8 @@ public CodeStyleSettings getCodeStyleSettings() {
3128
private CodeStyleSettings codeStyleSettings;
3229

3330
public CsvFormattingInfo(CodeStyleSettings codeStyleSettings, SpacingBuilder spacingBuilder, Map<Integer, CsvColumnInfo<ASTNode>> infoColumnMap) {
34-
this.infoColumnMap = infoColumnMap;
31+
super(infoColumnMap);
3532
this.spacingBuilder = spacingBuilder;
3633
this.codeStyleSettings = codeStyleSettings;
37-
buildReverseMap();
38-
}
39-
40-
private void buildReverseMap() {
41-
reverseInfoColumnMap = new HashMap<>();
42-
for (CsvColumnInfo<ASTNode> columnInfo : infoColumnMap.values()) {
43-
for (ASTNode node : columnInfo.getElements()) {
44-
reverseInfoColumnMap.put(node, columnInfo);
45-
}
46-
}
47-
}
48-
49-
public CsvColumnInfo getColumnInfo(ASTNode node) {
50-
return reverseInfoColumnMap.get(node);
51-
}
52-
53-
public CsvColumnInfo getColumnInfo(int columnIndex) {
54-
return infoColumnMap.get(columnIndex);
5534
}
56-
5735
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package net.seesharpsoft.intellij.plugins.csv.highlighter;
2+
3+
import com.intellij.codeInsight.highlighting.HighlightUsagesHandlerBase;
4+
import com.intellij.openapi.editor.Caret;
5+
import com.intellij.openapi.editor.Editor;
6+
import com.intellij.psi.PsiElement;
7+
import com.intellij.util.Consumer;
8+
import net.seesharpsoft.intellij.plugins.csv.CsvColumnInfo;
9+
import net.seesharpsoft.intellij.plugins.csv.CsvHelper;
10+
import net.seesharpsoft.intellij.plugins.csv.psi.CsvFile;
11+
import org.jetbrains.annotations.NotNull;
12+
13+
import java.util.Collections;
14+
import java.util.List;
15+
16+
public class CsvHighlightUsagesHandler extends HighlightUsagesHandlerBase<PsiElement> {
17+
18+
protected CsvHighlightUsagesHandler(@NotNull Editor editor, @NotNull CsvFile file) {
19+
super(editor, file);
20+
}
21+
22+
protected CsvFile getCsvFile() {
23+
return (CsvFile)this.myFile;
24+
}
25+
26+
@Override
27+
public List<PsiElement> getTargets() {
28+
Caret primaryCaret = this.myEditor.getCaretModel().getPrimaryCaret();
29+
PsiElement myFocusedFieldElement = CsvHelper.getParentFieldElement(this.myFile.getViewProvider().findElementAt(primaryCaret.getOffset()));
30+
31+
if (myFocusedFieldElement == null) {
32+
return Collections.emptyList();
33+
}
34+
35+
CsvColumnInfo<PsiElement> columnInfo = getCsvFile().getMyColumnInfoMap().getColumnInfo(myFocusedFieldElement);
36+
return columnInfo == null ? Collections.emptyList() : Collections.unmodifiableList(columnInfo.getElements());
37+
}
38+
39+
@Override
40+
protected void selectTargets(List<PsiElement> list, Consumer<List<PsiElement>> consumer) {
41+
consumer.consume(list);
42+
}
43+
44+
@Override
45+
public void computeUsages(List<PsiElement> list) {
46+
list.forEach(element -> {
47+
if (element != null && !element.getText().isEmpty()) { this.addOccurrence(element); }
48+
});
49+
}
50+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package net.seesharpsoft.intellij.plugins.csv.highlighter;
2+
3+
import com.intellij.codeInsight.highlighting.HighlightUsagesHandlerBase;
4+
import com.intellij.codeInsight.highlighting.HighlightUsagesHandlerFactory;
5+
import com.intellij.openapi.editor.Editor;
6+
import com.intellij.psi.PsiFile;
7+
import net.seesharpsoft.intellij.plugins.csv.psi.CsvFile;
8+
import org.jetbrains.annotations.NotNull;
9+
import org.jetbrains.annotations.Nullable;
10+
11+
public class CsvHighlightUsagesHandlerFactory implements HighlightUsagesHandlerFactory {
12+
@Nullable
13+
@Override
14+
public HighlightUsagesHandlerBase createHighlightUsagesHandler(@NotNull Editor editor, @NotNull PsiFile psiFile) {
15+
if (psiFile instanceof CsvFile) {
16+
return new CsvHighlightUsagesHandler(editor, (CsvFile)psiFile);
17+
}
18+
return null;
19+
}
20+
}

src/main/java/net/seesharpsoft/intellij/plugins/csv/intention/CsvShiftColumnLeftIntentionAction.java

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,11 @@
55
import com.intellij.psi.PsiElement;
66
import com.intellij.util.IncorrectOperationException;
77
import net.seesharpsoft.intellij.plugins.csv.CsvColumnInfo;
8+
import net.seesharpsoft.intellij.plugins.csv.CsvColumnInfoMap;
89
import net.seesharpsoft.intellij.plugins.csv.CsvHelper;
910
import net.seesharpsoft.intellij.plugins.csv.psi.CsvFile;
1011
import org.jetbrains.annotations.NotNull;
1112

12-
import java.util.Map;
13-
1413
public class CsvShiftColumnLeftIntentionAction extends CsvShiftColumnIntentionAction {
1514

1615
public CsvShiftColumnLeftIntentionAction() {
@@ -19,27 +18,20 @@ public CsvShiftColumnLeftIntentionAction() {
1918

2019
@Override
2120
public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement psiElement) throws IncorrectOperationException {
22-
CsvFile psiFile = (CsvFile)psiElement.getContainingFile();
21+
CsvFile csvFile = (CsvFile)psiElement.getContainingFile();
2322

2423
psiElement = CsvHelper.getParentFieldElement(psiElement);
2524

26-
Map<Integer, CsvColumnInfo<PsiElement>> columnInfoMap = CsvHelper.createColumnInfoMap(psiFile);
27-
28-
CsvColumnInfo<PsiElement> rightColumnInfo = null;
29-
for (CsvColumnInfo columnInfo : columnInfoMap.values()) {
30-
if (columnInfo.containsElement(psiElement)) {
31-
rightColumnInfo = columnInfo;
32-
break;
33-
}
34-
}
25+
CsvColumnInfoMap<PsiElement> columnInfoMap = csvFile.getMyColumnInfoMap();
26+
CsvColumnInfo<PsiElement> rightColumnInfo = columnInfoMap.getColumnInfo(psiElement);
3527

3628
// column must be at least index 1 to be shifted left
3729
if (rightColumnInfo == null || rightColumnInfo.getColumnIndex() < 1) {
3830
return;
3931
}
4032

41-
CsvColumnInfo<PsiElement> leftColumnInfo = columnInfoMap.get(rightColumnInfo.getColumnIndex() - 1);
33+
CsvColumnInfo<PsiElement> leftColumnInfo = columnInfoMap.getColumnInfo(rightColumnInfo.getColumnIndex() - 1);
4234

43-
changeLeftAndRightColumnOrder(project, psiFile, leftColumnInfo, rightColumnInfo);
35+
changeLeftAndRightColumnOrder(project, csvFile, leftColumnInfo, rightColumnInfo);
4436
}
4537
}

src/main/java/net/seesharpsoft/intellij/plugins/csv/intention/CsvShiftColumnRightIntentionAction.java

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,11 @@
55
import com.intellij.psi.PsiElement;
66
import com.intellij.util.IncorrectOperationException;
77
import net.seesharpsoft.intellij.plugins.csv.CsvColumnInfo;
8+
import net.seesharpsoft.intellij.plugins.csv.CsvColumnInfoMap;
89
import net.seesharpsoft.intellij.plugins.csv.CsvHelper;
910
import net.seesharpsoft.intellij.plugins.csv.psi.CsvFile;
1011
import org.jetbrains.annotations.NotNull;
1112

12-
import java.util.Map;
13-
1413
public class CsvShiftColumnRightIntentionAction extends CsvShiftColumnIntentionAction {
1514

1615
public CsvShiftColumnRightIntentionAction() {
@@ -19,27 +18,20 @@ public CsvShiftColumnRightIntentionAction() {
1918

2019
@Override
2120
public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement psiElement) throws IncorrectOperationException {
22-
CsvFile psiFile = (CsvFile)psiElement.getContainingFile();
21+
CsvFile csvFile = (CsvFile)psiElement.getContainingFile();
2322

2423
psiElement = CsvHelper.getParentFieldElement(psiElement);
2524

26-
Map<Integer, CsvColumnInfo<PsiElement>> columnInfoMap = CsvHelper.createColumnInfoMap(psiFile);
27-
28-
CsvColumnInfo<PsiElement> leftColumnInfo = null;
29-
for (CsvColumnInfo columnInfo : columnInfoMap.values()) {
30-
if (columnInfo.containsElement(psiElement)) {
31-
leftColumnInfo = columnInfo;
32-
break;
33-
}
34-
}
25+
CsvColumnInfoMap<PsiElement> columnInfoMap = csvFile.getMyColumnInfoMap();
26+
CsvColumnInfo<PsiElement> leftColumnInfo = columnInfoMap.getColumnInfo(psiElement);
3527

3628
// column must be at least index 1 to be shifted left
37-
if (leftColumnInfo == null || leftColumnInfo.getColumnIndex() + 1 >= columnInfoMap.size()) {
29+
if (leftColumnInfo == null || leftColumnInfo.getColumnIndex() + 1 >= columnInfoMap.getColumnInfos().size()) {
3830
return;
3931
}
4032

41-
CsvColumnInfo<PsiElement> rightColumnInfo = columnInfoMap.get(leftColumnInfo.getColumnIndex() + 1);
33+
CsvColumnInfo<PsiElement> rightColumnInfo = columnInfoMap.getColumnInfo(leftColumnInfo.getColumnIndex() + 1);
4234

43-
changeLeftAndRightColumnOrder(project, psiFile, leftColumnInfo, rightColumnInfo);
35+
changeLeftAndRightColumnOrder(project, csvFile, leftColumnInfo, rightColumnInfo);
4436
}
4537
}

0 commit comments

Comments
 (0)