Skip to content

Commit 29bb86a

Browse files
msullivanilevkivskyi
authored andcommitted
Try to load default configuration values from mypy.ini (#32)
* Refactor configuration to use a config model object and a config loader This allows the config loading fallback logic to be more shared between the two places that use it. This also fixes saving the config, which silently (!) would fail because the fields were private. * Try to load default configuration values from mypy.ini
1 parent c848e22 commit 29bb86a

10 files changed

+94
-60
lines changed

build.gradle

+1
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,5 @@ intellij {
2727
}
2828

2929
dependencies {
30+
implementation 'org.ini4j:ini4j:0.5.4'
3031
}

resources/META-INF/plugin.xml

+2-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@
3131

3232
<extensions defaultExtensionNs="com.intellij">
3333
<toolWindow id="Mypy Terminal" icon="MypyIcons.MYPY_SMALL" anchor="bottom" factoryClass="com.dropbox.plugins.mypy_plugin.MypyToolWindowFactory"/>
34-
<projectService serviceImplementation="com.dropbox.plugins.mypy_plugin.MypyConfigService"/>
34+
<projectService serviceInterface="com.dropbox.plugins.mypy_plugin.MypyConfigService"
35+
serviceImplementation="com.dropbox.plugins.mypy_plugin.MypyConfigService"/>
3536
</extensions>
3637

3738
<actions>

src/com/dropbox/plugins/mypy_plugin/MypyConfig.form renamed to src/com/dropbox/plugins/mypy_plugin/MypyConfigDialog.form

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.dropbox.plugins.mypy_plugin.MypyConfig">
2+
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.dropbox.plugins.mypy_plugin.MypyConfigDialog">
33
<grid id="cbd77" binding="contentPane" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
44
<margin top="10" left="10" bottom="10" right="10"/>
55
<constraints>
6-
<xy x="48" y="54" width="436" height="297"/>
6+
<xy x="48" y="54" width="528" height="297"/>
77
</constraints>
88
<properties/>
99
<border type="none"/>

src/com/dropbox/plugins/mypy_plugin/MypyConfig.java renamed to src/com/dropbox/plugins/mypy_plugin/MypyConfigDialog.java

+9-18
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,37 @@
11
package com.dropbox.plugins.mypy_plugin;
22

3+
import com.dropbox.plugins.mypy_plugin.model.MypyConfig;
34
import com.intellij.openapi.project.Project;
45
import com.intellij.openapi.ui.DialogWrapper;
56
import com.intellij.openapi.ui.ValidationInfo;
67
import icons.MypyIcons;
78

89
import javax.swing.*;
910

10-
public final class MypyConfig extends DialogWrapper {
11+
public final class MypyConfigDialog extends DialogWrapper {
1112
private JPanel contentPane;
1213
private JLabel logo;
1314
private JTextField command;
1415
private JTextField path;
15-
private final MypyConfigService config;
16+
private final MypyConfigService configService;
1617

17-
MypyConfig(Project project) {
18+
MypyConfigDialog(Project project) {
1819
super(project);
1920
setModal(true);
2021
init();
2122
setTitle("Mypy Plugin Configuration");
22-
config = MypyConfigService.getInstance(project);
23-
String storedCmd = config != null ? config.getExecutableName() : null;
24-
if (storedCmd != null) {
25-
this.command.setText(storedCmd);
26-
} else {
27-
this.command.setText(MypyToolWindowFactory.DEFAULT_MYPY_COMMAND);
28-
}
29-
String storedPath = config != null ? config.getPathSuffix() : null;
30-
if (storedPath != null) {
31-
this.path.setText(storedPath);
32-
} else {
33-
this.path.setText(MypyToolWindowFactory.DEFAULT_MYPY_PATH_SUFFIX);
34-
}
23+
configService = MypyConfigService.getInstance(project);
24+
MypyConfig config = MypyConfigLoader.findMypyConfig(project);
25+
this.command.setText(config.getExecutableName());
26+
this.path.setText(config.getPathSuffix());
3527
logo.setIcon(MypyIcons.MYPY_BIG);
3628
command.setCaretPosition(0);
3729
path.setCaretPosition(0);
3830
}
3931

4032
@Override
4133
protected void doOKAction() {
42-
config.setExecutableName(command.getText());
43-
config.setPathSuffix(path.getText());
34+
configService.loadState(new MypyConfig(command.getText(), path.getText()));
4435
super.doOKAction();
4536
}
4637

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.dropbox.plugins.mypy_plugin;
2+
3+
import com.dropbox.plugins.mypy_plugin.model.MypyConfig;
4+
import com.intellij.openapi.project.Project;
5+
import org.ini4j.Ini;
6+
7+
import java.io.File;
8+
import java.io.IOException;
9+
10+
public class MypyConfigLoader {
11+
final static String DEFAULT_MYPY_COMMAND = "dmypy start -- --follow-imports=error ; dmypy check .";
12+
final static String DEFAULT_MYPY_PATH_SUFFIX = "";
13+
14+
public static MypyConfig findMypyConfig(Project project) {
15+
MypyConfigService configService = MypyConfigService.getInstance(project);
16+
if (configService != null && configService.getState() != null) {
17+
return configService.getState();
18+
}
19+
MypyConfig iniConfig = loadConfigFromIni(project);
20+
if (iniConfig != null) {
21+
return iniConfig;
22+
}
23+
return new MypyConfig(DEFAULT_MYPY_COMMAND, DEFAULT_MYPY_PATH_SUFFIX);
24+
}
25+
26+
public static MypyConfig loadConfigFromIni(Project project) {
27+
String directory = project.getBaseDir().getPath();
28+
File ini_file = new File(directory, "mypy.ini");
29+
Ini ini = null;
30+
try {
31+
ini = new Ini(ini_file);
32+
} catch (IOException e) {
33+
return null;
34+
}
35+
String command = ini.get("mypy", "x_pycharm_command");
36+
String path_suffix = ini.get("mypy", "x_pycharm_PATH");
37+
return new MypyConfig(
38+
command != null ? command : DEFAULT_MYPY_COMMAND,
39+
path_suffix != null ? path_suffix : DEFAULT_MYPY_PATH_SUFFIX);
40+
41+
}
42+
}

src/com/dropbox/plugins/mypy_plugin/MypyConfigService.java

+9-26
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,31 @@
11
package com.dropbox.plugins.mypy_plugin;
22

3+
import com.dropbox.plugins.mypy_plugin.model.MypyConfig;
34
import com.intellij.openapi.components.PersistentStateComponent;
45
import com.intellij.openapi.components.ServiceManager;
56
import com.intellij.openapi.components.State;
67
import com.intellij.openapi.components.Storage;
78
import com.intellij.openapi.project.Project;
8-
import com.intellij.util.xmlb.XmlSerializerUtil;
99
import org.jetbrains.annotations.NotNull;
1010
import org.jetbrains.annotations.Nullable;
1111

1212
@State(
13-
name="MypyConfigService",
13+
name = "MypyConfigService",
1414
storages = {
1515
@Storage("MypyConfig.xml")}
1616
)
17-
public final class MypyConfigService implements PersistentStateComponent<MypyConfigService> {
18-
private String executableName;
19-
private String pathSuffix;
17+
public final class MypyConfigService implements PersistentStateComponent<MypyConfig> {
18+
private MypyConfig config;
2019

21-
String getExecutableName() {
22-
return executableName;
23-
}
24-
25-
void setExecutableName(String executableName) {
26-
this.executableName = executableName;
27-
}
28-
29-
String getPathSuffix() {
30-
return pathSuffix;
31-
}
32-
33-
void setPathSuffix(String pathSuffix) {
34-
this.pathSuffix = pathSuffix;
35-
}
36-
37-
@NotNull
20+
@Nullable
3821
@Override
39-
public MypyConfigService getState() {
40-
return this;
22+
public MypyConfig getState() {
23+
return config;
4124
}
4225

4326
@Override
44-
public void loadState(@NotNull MypyConfigService config) {
45-
XmlSerializerUtil.copyBean(config, this);
27+
public void loadState(@NotNull MypyConfig config) {
28+
this.config = config;
4629
}
4730

4831
@Nullable

src/com/dropbox/plugins/mypy_plugin/MypyRunner.java

+5-10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.dropbox.plugins.mypy_plugin;
22

3+
import com.dropbox.plugins.mypy_plugin.model.MypyConfig;
34
import com.dropbox.plugins.mypy_plugin.model.MypyError;
45
import com.dropbox.plugins.mypy_plugin.model.MypyResult;
56
import com.intellij.openapi.application.ApplicationManager;
@@ -29,24 +30,18 @@ public final class MypyRunner {
2930
MypyResult runMypyDaemon() {
3031
Process process;
3132
String directory = project.getBaseDir().getPath();
32-
MypyConfigService config = MypyConfigService.getInstance(project);
33+
MypyConfig config = MypyConfigLoader.findMypyConfig(project);
3334

3435
ProcessBuilder processBuilder = new ProcessBuilder();
3536
Map<String, String> envProcess = processBuilder.environment();
3637
Map<String, String> env = System.getenv();
3738

3839
envProcess.putAll(env);
39-
String extraPath = config != null ? config.getPathSuffix() : null;
40-
if (extraPath == null) { // config deleted
41-
extraPath = MypyToolWindowFactory.DEFAULT_MYPY_PATH_SUFFIX;
42-
}
40+
String extraPath = config.getPathSuffix();
4341
if (!extraPath.equals("")) {
4442
envProcess.put("PATH", envProcess.get("PATH") + File.pathSeparator + extraPath);
4543
}
46-
String mypyCommand = config != null ? config.getExecutableName() : null;
47-
if ((mypyCommand == null) || (mypyCommand.equals(""))) {
48-
mypyCommand = MypyToolWindowFactory.DEFAULT_MYPY_COMMAND;
49-
}
44+
String mypyCommand = config.getExecutableName();
5045
processBuilder.command("/bin/bash", "-c", mypyCommand);
5146
processBuilder.redirectErrorStream(true);
5247
processBuilder.redirectInput(new File("/dev/null"));
@@ -79,7 +74,7 @@ MypyResult runMypyDaemon() {
7974
noteCount++;
8075
}
8176
} else if (line.matches("PASSED") | line.matches("FAILED")) {
82-
// these will bre shown in status line anyway
77+
// these will be shown in status line anyway
8378
break;
8479
} else {
8580
debug.add(new MypyError(line, MypyError.DEBUG));

src/com/dropbox/plugins/mypy_plugin/MypyTerminal.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ void initUI(ToolWindow toolWindow) {
171171
popup.add(sep);
172172
JBMenuItem configItem = new JBMenuItem("Configure plugin...");
173173
configItem.addActionListener(e -> {
174-
MypyConfig dialog = new MypyConfig(project);
174+
MypyConfigDialog dialog = new MypyConfigDialog(project);
175175
dialog.show();
176176
});
177177
popup.add(configItem);

src/com/dropbox/plugins/mypy_plugin/MypyToolWindowFactory.java

-2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@
1111

1212

1313
public final class MypyToolWindowFactory implements ToolWindowFactory, DumbAware {
14-
final static String DEFAULT_MYPY_PATH_SUFFIX = "";
15-
final static String DEFAULT_MYPY_COMMAND = "dmypy start -- --follow-imports=error ; dmypy check .";
1614
final public static String MYPY_PLUGIN_ID = "Mypy Terminal";
1715
final public static boolean DEBUG_BUILD = false;
1816
private final static HashMap<Project, MypyTerminal> instances = new HashMap<>();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.dropbox.plugins.mypy_plugin.model;
2+
3+
public class MypyConfig {
4+
public String executableName;
5+
public String pathSuffix;
6+
7+
public MypyConfig() {
8+
// This is so the serialization system can handle this
9+
}
10+
11+
public MypyConfig(String executableName, String pathSuffix) {
12+
this.executableName = executableName;
13+
this.pathSuffix = pathSuffix;
14+
}
15+
16+
public String getExecutableName() {
17+
return executableName;
18+
}
19+
20+
public String getPathSuffix() {
21+
return pathSuffix;
22+
}
23+
}

0 commit comments

Comments
 (0)