Skip to content
This repository has been archived by the owner on Mar 25, 2019. It is now read-only.

Commit

Permalink
Guess board file (#102)
Browse files Browse the repository at this point in the history
  • Loading branch information
Ilia Motornyi authored May 5, 2018
1 parent b49bda3 commit f74a002
Show file tree
Hide file tree
Showing 6 changed files with 196 additions and 38 deletions.
71 changes: 41 additions & 30 deletions src/xyz/elmot/clion/cubemx/ConvertProject.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.exception.RootRuntimeException;
import com.jetbrains.cidr.cpp.cmake.workspace.CMakeWorkspace;
import com.jetbrains.cidr.cpp.execution.CMakeAppRunConfiguration;
import org.apache.commons.lang.text.StrSubstitutor;
import org.jdom.Attribute;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.xpath.XPath;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import xyz.elmot.clion.openocd.Informational;
import xyz.elmot.clion.openocd.OpenOcdConfiguration;
import xyz.elmot.clion.openocd.OpenOcdConfigurationType;

import java.io.IOException;
Expand Down Expand Up @@ -55,27 +56,8 @@ public ConvertProject() {

public static void updateProject(Project project) {
if (project == null) return;
Element cProject = detectAndLoadFile(project, CPROJECT_FILE_NAME);
Element dotProject = detectAndLoadFile(project, PROJECT_FILE_NAME);
if (dotProject == null || cProject == null) {
return;
}
Context context = new Context(cProject);
ProjectData projectData = new ProjectData();
//noinspection ConstantConditions
projectData.setProjectName(dotProject.getChild("name").getText());
try {
String linkerScript = fetchValueBySuperClass(context, "fr.ac6.managedbuild.tool.gnu.cross.c.linker.script");
projectData.setLinkerScript(linkerScript.replace("../", ""));
projectData.setMcuFamily(fetchValueBySuperClass(context, "fr.ac6.managedbuild.option.gnu.cross.mcu"));
projectData.setLinkerFlags(fetchValueBySuperClass(context, "gnu.c.link.option.ldflags"));

projectData.setDefines(loadDefines(context));
projectData.setIncludes(loadIncludes(context));
projectData.setSources(loadSources(context));
} catch (JDOMException e) {
Messages.showErrorDialog(project, "Xml data error", String.format("XML data retrieval error\n Key: %s ", context.currentKey));
}
ProjectData projectData = loadProjectData(project);
if (projectData == null) return;

Application application = ApplicationManager.getApplication();
application.saveAll();
Expand Down Expand Up @@ -127,6 +109,32 @@ public static void updateProject(Project project) {
);
}

@Nullable
public static ProjectData loadProjectData(Project project) {
Element cProject = detectAndLoadFile(project, CPROJECT_FILE_NAME);
Element dotProject = detectAndLoadFile(project, PROJECT_FILE_NAME);
if (dotProject == null || cProject == null) {
return null;
}
Context context = new Context(cProject);
ProjectData projectData = new ProjectData();
//noinspection ConstantConditions
projectData.setProjectName(dotProject.getChild("name").getText());
try {
String linkerScript = fetchValueBySuperClass(context, "fr.ac6.managedbuild.tool.gnu.cross.c.linker.script");
projectData.setLinkerScript(linkerScript.replace("../", ""));
projectData.setMcuFamily(fetchValueBySuperClass(context, "fr.ac6.managedbuild.option.gnu.cross.mcu"));
projectData.setLinkerFlags(fetchValueBySuperClass(context, "gnu.c.link.option.ldflags"));
projectData.setBoard(fetchValueBySuperClass(context, "fr.ac6.managedbuild.option.gnu.cross.board"));
projectData.setDefines(loadDefines(context));
projectData.setIncludes(loadIncludes(context));
projectData.setSources(loadSources(context));
} catch (JDOMException e) {
Messages.showErrorDialog(project, "Xml data error", String.format("XML data retrieval error\n Key: %s ", context.currentKey));
}
return projectData;
}

@NotNull
private static String loadCmakeTemplateFromResources() throws IOException {
return FileUtil.loadTextAndClose(ConvertProject.class.getResourceAsStream("tmpl_CMakeLists.txt"));
Expand All @@ -153,14 +161,17 @@ private static void modifyCMakeConfigs(Project project, ProjectData projectData)
if (runManager.findConfigurationByTypeAndName(OpenOcdConfigurationType.TYPE_ID, name) == null) {
RunnerAndConfigurationSettings newRunConfig = runManager.createRunConfiguration(name, factory);
newRunConfig.setSingleton(true);
((CMakeAppRunConfiguration) newRunConfig.getConfiguration()).setupDefaultTargetAndExecutable();
ApplicationManager.getApplication().invokeLater(() ->
ApplicationManager.getApplication().runWriteAction(() ->
{
runManager.addConfiguration(newRunConfig);
runManager.makeStable(newRunConfig);
runManager.setSelectedConfiguration(newRunConfig);
}));
OpenOcdConfiguration configuration = (OpenOcdConfiguration) newRunConfig.getConfiguration();
configuration.setupDefaultTargetAndExecutable();
ApplicationManager.getApplication().invokeLater(() -> {
configuration.setBoardConfigFile(SelectBoardDialog.selectBoardByPriority(projectData, project));
ApplicationManager.getApplication().runWriteAction(() ->
{
runManager.addConfiguration(newRunConfig);
runManager.makeStable(newRunConfig);
runManager.setSelectedConfiguration(newRunConfig);
});
});
}
}

Expand Down
11 changes: 10 additions & 1 deletion src/xyz/elmot/clion/cubemx/ProjectData.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
* (c) elmot on 28.9.2017.
*/
@SuppressWarnings({"WeakerAccess", "unused"})
class ProjectData {
public class ProjectData {
private String projectName;
private String linkerScript;
private String mcuFamily;
Expand All @@ -17,6 +17,7 @@ class ProjectData {
private String includes;
private String sources;
private String mcpu;
private String board;

public void setProjectName(String projectName) {
this.projectName = projectName;
Expand Down Expand Up @@ -88,6 +89,10 @@ public String getMcpu() {
return mcpu;
}

public String getBoard() {
return board;
}

public void setDefines(String defines) {
this.defines = defines;
}
Expand All @@ -100,6 +105,10 @@ public void setSources(String sources) {
this.sources = sources;
}

public void setBoard(String board) {
this.board = board;
}

@Override
public String toString() {
return "projectName='" + projectName + '\'' +
Expand Down
116 changes: 116 additions & 0 deletions src/xyz/elmot/clion/cubemx/SelectBoardDialog.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package xyz.elmot.clion.cubemx;

import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.ListSpeedSearch;
import com.intellij.ui.components.JBList;
import com.intellij.ui.components.JBScrollPane;
import xyz.elmot.clion.openocd.OpenOcdSettingsState;

import javax.swing.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;

import static xyz.elmot.clion.openocd.OpenOcdComponent.require;

public class SelectBoardDialog extends DialogWrapper {
private static Logger LOGGER = Logger.getInstance(DialogWrapper.class);
private final String[] values;
private int result = 0;

private SelectBoardDialog(Project project, String[] values) {
super(project, false, false);
this.values = values;
setTitle("Board Config Files");
init();
}

@Override
protected JComponent createCenterPanel() {
//todo normal texts
JBList<String> boardList = new JBList<>(values);
boardList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
boardList.setSelectedIndex(result);
boardList.addListSelectionListener(e -> result = boardList.getSelectedIndex());
boardList.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (!e.isPopupTrigger() && e.getClickCount() > 1) {
clickDefaultButton();
}
}
});
new ListSpeedSearch<>(boardList);
return new JBScrollPane(boardList);
}

public static String selectBoardByPriority(ProjectData projectData, Project project) {
try {
List<Pair<String, Integer>> keywordWeight = new ArrayList<>();
String board = Objects.toString(projectData.getBoard(), "").toUpperCase();
if (board.isEmpty()) {
LOGGER.info("Board is not defined in the project");
return null;
}
keywordWeight.add(Pair.pair(board, 1000));
Stream.of("NUCLEO", "EVAL").filter(board::contains).findFirst().ifPresent(s -> keywordWeight.add(Pair.pair(s, 100)));
if (board.contains("DISCOVERY")) {
keywordWeight.add(Pair.pair("DISCOVERY", 100));
keywordWeight.add(Pair.pair("DISC", 20));
} else if (board.contains("DISC")) {
keywordWeight.add(Pair.pair("DISC", 100));
keywordWeight.add(Pair.pair("DISCOVERY", 20));
}
String mcuFamily = Objects.toString(projectData.getMcuFamily(), "").toUpperCase();
for (int i = mcuFamily.length() - 1; i >= 6; i--) {
keywordWeight.add(Pair.pair(mcuFamily.substring(0, i), i));
}
OpenOcdSettingsState ocdSettings = project.getComponent(OpenOcdSettingsState.class);
VirtualFile ocdHome = require(LocalFileSystem.getInstance().findFileByPath(ocdSettings.openOcdHome));
VirtualFile ocdScripts = require(OpenOcdSettingsState.findOcdScripts(ocdHome));
VirtualFile[] ocdBoards = require(ocdScripts.findChild("board")).getChildren();
Stream<String> boardByScores =
Stream.of(ocdBoards).parallel().map(ocdBoard ->
{
try {
String text = VfsUtil.loadText(ocdBoard).toUpperCase();
int weight = keywordWeight.parallelStream()
.filter(entry -> text.contains(entry.getFirst()))
.mapToInt(pair -> pair.getSecond()).sum();
return Pair.pair(ocdBoard.getName(), weight);
} catch (IOException e) {
e.printStackTrace();
return Pair.pair(ocdBoard.getName(), 0);
}
}

)
// Show all
//.filter(p -> p.getSecond() != 0)
.sorted(Comparator.comparingInt(p -> -p.getSecond()))
.map(p -> p.getFirst());
String[] values = boardByScores.toArray(String[]::new);
SelectBoardDialog dialog = new SelectBoardDialog(project, values);
dialog.show();
int i = dialog.getExitCode();
if (i == OK_EXIT_CODE) {
return "board/" + dialog.values[dialog.result];
}
} catch (Throwable e) {
LOGGER.error(e);
}
return null;
}

}
2 changes: 1 addition & 1 deletion src/xyz/elmot/clion/openocd/OpenOcdComponent.java
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ public static GeneralCommandLine createOcdCommandLine(OpenOcdConfiguration confi
}

@NotNull
private static VirtualFile require(VirtualFile fileToCheck) throws ConfigurationException {
public static VirtualFile require(VirtualFile fileToCheck) throws ConfigurationException {
if (fileToCheck == null) {
openOcdNotFound();
}
Expand Down
30 changes: 26 additions & 4 deletions src/xyz/elmot/clion/openocd/OpenOcdConfigurationEditor.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,22 @@
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.ui.components.fields.IntegerField;
import com.intellij.ui.components.panels.HorizontalBox;
import com.intellij.util.ui.GridBag;
import com.jetbrains.cidr.cpp.execution.CMakeAppRunConfiguration;
import com.jetbrains.cidr.cpp.execution.CMakeAppRunConfigurationSettingsEditor;
import com.jetbrains.cidr.cpp.execution.CMakeBuildConfigurationHelper;
import org.jdesktop.swingx.JXRadioGroup;
import org.jetbrains.annotations.NotNull;
import xyz.elmot.clion.cubemx.ConvertProject;
import xyz.elmot.clion.cubemx.ProjectData;
import xyz.elmot.clion.cubemx.SelectBoardDialog;
import xyz.elmot.clion.openocd.OpenOcdConfiguration.DownloadType;
import xyz.elmot.clion.openocd.OpenOcdConfiguration.ResetType;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;

public class OpenOcdConfigurationEditor extends CMakeAppRunConfigurationSettingsEditor {
private IntegerField gdbPort;
Expand Down Expand Up @@ -58,7 +63,6 @@ protected void resetEditorFrom(@NotNull CMakeAppRunConfiguration cMakeAppRunConf

boardConfigFile.setText(ocd.getBoardConfigFile());


gdbPort.setText("" + ocd.getGdbPort());

telnetPort.setText("" + ocd.getTelnetPort());
Expand All @@ -76,9 +80,8 @@ protected void createEditorInner(JPanel panel, GridBag gridBag) {
}
}

panel.add(new JLabel("Board config file"), gridBag.nextLine().next());
boardConfigFile = new FileChooseInput.BoardCfg("Board config", VfsUtil.getUserHomeDir(), this::getOpenocdHome);
panel.add(boardConfigFile, gridBag.next().coverLine());
JPanel boardPanel = createBoardSelector(panel, gridBag);
panel.add(boardPanel, gridBag.next().coverLine());

JPanel portsPanel = new JPanel(new FlowLayout(FlowLayout.LEADING));

Expand All @@ -97,6 +100,25 @@ protected void createEditorInner(JPanel panel, GridBag gridBag) {
panel.add(resetGroup, gridBag.next());
}

@NotNull
private JPanel createBoardSelector(JPanel panel, GridBag gridBag) {
panel.add(new JLabel("Board config file"), gridBag.nextLine().next());
JPanel boardPanel = new HorizontalBox();
boardPanel.add(new JButton(new AbstractAction("Assist...") {
@Override
public void actionPerformed(ActionEvent e) {
ProjectData projectData = ConvertProject.loadProjectData(myProject);
String selectedBoard = SelectBoardDialog.selectBoardByPriority(projectData, myProject);
if(selectedBoard!=null && !"".equals(selectedBoard)) {
boardConfigFile.setText(selectedBoard);
}
}
}));
boardConfigFile = new FileChooseInput.BoardCfg("Board config", VfsUtil.getUserHomeDir(), this::getOpenocdHome);
boardPanel.add(boardConfigFile);
return boardPanel;
}

private IntegerField addPortInput(JPanel portsPanel, String label, int defaultValue) {
portsPanel.add(new JLabel(label + ": "));
IntegerField field = new IntegerField(label, 1024, 65535);
Expand Down
4 changes: 2 additions & 2 deletions src/xyz/elmot/clion/openocd/OpenOcdConfigurationType.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,13 @@ public static Icon getPluginIcon() {
}

@Override
public SettingsEditor<? extends CMakeAppRunConfiguration> createEditor(@NotNull Project project) {
public OpenOcdConfigurationEditor createEditor(@NotNull Project project) {
return new OpenOcdConfigurationEditor(project, getHelper(project));
}

@NotNull
@Override
protected CMakeAppRunConfiguration createRunConfiguration(@NotNull Project project, @NotNull ConfigurationFactory configurationFactory) {
protected OpenOcdConfiguration createRunConfiguration(@NotNull Project project, @NotNull ConfigurationFactory configurationFactory) {
return new OpenOcdConfiguration(project, factory, "");
}
}

0 comments on commit f74a002

Please sign in to comment.