Skip to content

Commit e04e4e0

Browse files
committed
[FEATURE] auto detect value separator
1 parent cdfcb7d commit e04e4e0

File tree

6 files changed

+79
-14
lines changed

6 files changed

+79
-14
lines changed

build.gradle

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ group 'net.seesharpsoft.intellij.plugins'
2727
version '2.14.3'
2828

2929
apply plugin: 'java'
30-
sourceCompatibility = javaVersion
31-
targetCompatibility = javaTargetVersion
30+
project.sourceCompatibility = JavaVersion.VERSION_11
31+
project.targetCompatibility = JavaVersion.VERSION_11
3232
tasks.withType(JavaCompile) { options.encoding = 'UTF-8' }
3333
repositories {
3434
mavenCentral()
@@ -60,8 +60,8 @@ sourceSets {
6060
apply plugin: 'idea'
6161
idea {
6262
project {
63-
jdkName = javaVersion
64-
languageLevel = javaVersion
63+
jdkName = JavaVersion.VERSION_11
64+
languageLevel = JavaVersion.VERSION_11
6565
vcs = 'Git'
6666
}
6767
module {

gradle.properties

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,3 @@
33
# https://www.jetbrains.com/intellij-repository/snapshots
44

55
name='CSV Plugin'
6-
javaVersion=11
7-
javaTargetVersion=11

src/main/java/net/seesharpsoft/intellij/plugins/csv/components/CsvFileAttributes.java

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,22 @@
55
import com.intellij.openapi.components.ServiceManager;
66
import com.intellij.openapi.components.State;
77
import com.intellij.openapi.components.Storage;
8+
import com.intellij.openapi.editor.Document;
9+
import com.intellij.openapi.fileEditor.FileDocumentManager;
810
import com.intellij.openapi.fileTypes.LanguageFileType;
911
import com.intellij.openapi.project.Project;
1012
import com.intellij.openapi.vfs.VirtualFile;
1113
import com.intellij.psi.PsiFile;
1214
import com.intellij.util.xmlb.XmlSerializerUtil;
1315
import com.intellij.util.xmlb.annotations.OptionTag;
16+
import net.seesharpsoft.commons.collection.Pair;
1417
import net.seesharpsoft.intellij.plugins.csv.*;
1518
import net.seesharpsoft.intellij.plugins.csv.settings.CsvEditorSettings;
19+
import org.apache.commons.lang.StringUtils;
1620
import org.jetbrains.annotations.NotNull;
1721
import org.jetbrains.annotations.Nullable;
1822

23+
import java.util.Arrays;
1924
import java.util.HashMap;
2025
import java.util.Map;
2126

@@ -87,12 +92,18 @@ public boolean canChangeValueSeparator(@NotNull PsiFile psiFile) {
8792
return language.isKindOf(CsvLanguage.INSTANCE) && !(language instanceof CsvSeparatorHolder);
8893
}
8994

95+
private void setFileSeparator(@NotNull Project project, @NotNull VirtualFile virtualFile, @NotNull CsvValueSeparator separator) {
96+
Attribute attribute = getFileAttribute(project, virtualFile, true);
97+
if (attribute != null) {
98+
attribute.separator = separator;
99+
}
100+
}
101+
90102
public void setFileSeparator(@NotNull PsiFile psiFile, @NotNull CsvValueSeparator separator) {
91103
if (!canChangeValueSeparator(psiFile)) {
92104
return;
93105
}
94-
Attribute attribute = getFileAttribute(psiFile.getProject(), psiFile.getOriginalFile().getVirtualFile(), true);
95-
attribute.separator = separator;
106+
setFileSeparator(psiFile.getProject(), psiFile.getOriginalFile().getVirtualFile(), separator);
96107
}
97108

98109
public void resetValueSeparator(@NotNull PsiFile psiFile) {
@@ -105,18 +116,51 @@ public void resetValueSeparator(@NotNull PsiFile psiFile) {
105116
}
106117
}
107118

119+
private @NotNull
120+
CsvValueSeparator guessOrGetValueSeparator(Project project, VirtualFile virtualFile) {
121+
return CsvEditorSettings.getInstance().isGuessValueSeparator() ?
122+
guessValueSeparator(project, virtualFile) :
123+
CsvEditorSettings.getInstance().getDefaultValueSeparator();
124+
}
125+
126+
private @NotNull
127+
CsvValueSeparator guessValueSeparator(Project project, VirtualFile virtualFile) {
128+
Document document = FileDocumentManager.getInstance().getDocument(virtualFile);
129+
final String text = document == null ? "" : document.getText();
130+
Pair<CsvValueSeparator, Integer> separatorWithCount =
131+
Arrays.stream(CsvValueSeparator.values())
132+
// count
133+
.map(separator -> {
134+
String character = separator.getCharacter();
135+
return Pair.of(separator, StringUtils.countMatches(text, character));
136+
})
137+
// ignore non-matched separators
138+
.filter(p -> p.getSecond() > 0)
139+
// get the one with most hits
140+
.max((p1, p2) -> p1.getSecond() - p2.getSecond())
141+
// failsafe (e.g. empty document)
142+
.orElse(null);
143+
144+
CsvValueSeparator valueSeparator = separatorWithCount != null ?
145+
separatorWithCount.getFirst() :
146+
CsvEditorSettings.getInstance().getDefaultValueSeparator();
147+
148+
setFileSeparator(project, virtualFile, valueSeparator);
149+
return valueSeparator;
150+
}
151+
108152
public @NotNull
109153
CsvValueSeparator getValueSeparator(Project project, VirtualFile virtualFile) {
110154
if (project == null || virtualFile == null || !(virtualFile.getFileType() instanceof LanguageFileType)) {
111155
return CsvEditorSettings.getInstance().getDefaultValueSeparator();
112156
}
113157
Language language = ((LanguageFileType) virtualFile.getFileType()).getLanguage();
114158
if (language instanceof CsvSeparatorHolder) {
115-
return ((CsvSeparatorHolder) language).getSeparator();
159+
return ((CsvSeparatorHolder) language).getSeparator();
116160
}
117161
Attribute attribute = getFileAttribute(project, virtualFile);
118162
return attribute == null || attribute.separator == null ?
119-
CsvEditorSettings.getInstance().getDefaultValueSeparator() :
163+
guessOrGetValueSeparator(project, virtualFile) :
120164
attribute.separator;
121165
}
122166

@@ -127,7 +171,9 @@ public boolean hasValueSeparatorAttribute(@NotNull Project project, @NotNull Vir
127171

128172
public void setEscapeCharacter(@NotNull PsiFile psiFile, @NotNull CsvEscapeCharacter escapeCharacter) {
129173
Attribute attribute = getFileAttribute(psiFile.getProject(), psiFile.getOriginalFile().getVirtualFile(), true);
130-
attribute.escapeCharacter = escapeCharacter;
174+
if (attribute != null) {
175+
attribute.escapeCharacter = escapeCharacter;
176+
}
131177
}
132178

133179
public void resetEscapeSeparator(@NotNull PsiFile psiFile) {

src/main/java/net/seesharpsoft/intellij/plugins/csv/settings/CsvEditorSettings.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ public static final class OptionSet {
8484
public boolean KEEP_TRAILING_SPACES = false;
8585
public String COMMENT_INDICATOR = COMMENT_INDICATOR_DEFAULT;
8686
public ValueColoring VALUE_COLORING = ValueColoring.RAINBOW;
87+
public boolean GUESS_VALUE_SEPARATOR = true;
8788

8889
public OptionSet() {
8990
EditorSettingsExternalizable editorSettingsExternalizable = EditorSettingsExternalizable.getInstance();
@@ -312,6 +313,14 @@ public void setHeaderRowFixed(boolean headerRowFixed) {
312313
getState().TABLE_HEADER_ROW_FIXED = headerRowFixed;
313314
}
314315

316+
public boolean isGuessValueSeparator() {
317+
return getState().GUESS_VALUE_SEPARATOR;
318+
}
319+
320+
public void setGuessValueSeparator(boolean guessValueSeparator) {
321+
getState().GUESS_VALUE_SEPARATOR = guessValueSeparator;
322+
}
323+
315324
public boolean checkCurrentPluginVersion(String actualVersion) {
316325
if (!actualVersion.equals(getState().CURRENT_PLUGIN_VERSION)) {
317326
getState().CURRENT_PLUGIN_VERSION = actualVersion;

src/main/java/net/seesharpsoft/intellij/plugins/csv/settings/CsvEditorSettingsProvider.form

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@
343343
</component>
344344
</children>
345345
</grid>
346-
<grid id="29095" layout-manager="GridLayoutManager" row-count="1" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
346+
<grid id="29095" layout-manager="GridLayoutManager" row-count="1" column-count="4" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
347347
<margin top="0" left="0" bottom="0" right="0"/>
348348
<constraints>
349349
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
@@ -363,7 +363,7 @@
363363
</component>
364364
<hspacer id="f2aa1">
365365
<constraints>
366-
<grid row="0" column="2" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
366+
<grid row="0" column="3" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
367367
</constraints>
368368
</hspacer>
369369
<component id="65f7" class="javax.swing.JComboBox" binding="comboValueSeparator" custom-create="true">
@@ -372,6 +372,14 @@
372372
</constraints>
373373
<properties/>
374374
</component>
375+
<component id="aed54" class="javax.swing.JCheckBox" binding="cbGuessSeparator">
376+
<constraints>
377+
<grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
378+
</constraints>
379+
<properties>
380+
<text value="Initial separator guessing"/>
381+
</properties>
382+
</component>
375383
</children>
376384
</grid>
377385
<grid id="7eea1" layout-manager="GridLayoutManager" row-count="1" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">

src/main/java/net/seesharpsoft/intellij/plugins/csv/settings/CsvEditorSettingsProvider.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ public class CsvEditorSettingsProvider implements EditorOptionsProvider {
4343
private JTextField tfCommentIndicator;
4444
private JComboBox comboValueColoring;
4545
private JCheckBox cbHeaderRowFixed;
46+
private JCheckBox cbGuessSeparator;
4647

4748
@NotNull
4849
@Override
@@ -94,7 +95,8 @@ public boolean isModified() {
9495
isModified(cbKeepTrailingWhitespaces, csvEditorSettings.getKeepTrailingSpaces()) ||
9596
isModified(tfCommentIndicator, csvEditorSettings.getCommentIndicator()) ||
9697
!Objects.equals(comboValueColoring.getSelectedItem(), csvEditorSettings.getValueColoring()) ||
97-
isModified(cbHeaderRowFixed, csvEditorSettings.isHeaderRowFixed());
98+
isModified(cbHeaderRowFixed, csvEditorSettings.isHeaderRowFixed()) ||
99+
isModified(cbGuessSeparator, csvEditorSettings.isGuessValueSeparator());
98100
}
99101

100102
@Override
@@ -120,6 +122,7 @@ public void reset() {
120122
tfCommentIndicator.setText(csvEditorSettings.getCommentIndicator());
121123
comboValueColoring.setSelectedItem(csvEditorSettings.getValueColoring());
122124
cbHeaderRowFixed.setSelected(csvEditorSettings.isHeaderRowFixed());
125+
cbGuessSeparator.setSelected(csvEditorSettings.isGuessValueSeparator());
123126
}
124127

125128
@Override
@@ -145,6 +148,7 @@ public void apply() throws ConfigurationException {
145148
csvEditorSettings.setCommentIndicator(tfCommentIndicator.getText());
146149
csvEditorSettings.setValueColoring((CsvEditorSettings.ValueColoring) comboValueColoring.getSelectedItem());
147150
csvEditorSettings.setHeaderRowFixed(cbHeaderRowFixed.isSelected());
151+
csvEditorSettings.setGuessValueSeparator(cbGuessSeparator.isSelected());
148152
}
149153

150154
protected void createUIComponents() {

0 commit comments

Comments
 (0)