intellij-lsp/intellij-lsp-plugin

View on GitHub
src/main/scala/com/github/gtache/lsp/settings/gui/ServersGUI.java

Summary

Maintainability
C
1 day
Test Coverage
F
0%
/*
 *     Copyright 2017-2018 Guillaume Tâche
 *
 *     Licensed under the Apache License, Version 2.0 (the "License");
 *     you may not use this file except in compliance with the License.
 *     You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *     Unless required by applicable law or agreed to in writing, software
 *     distributed under the License is distributed on an "AS IS" BASIS,
 *     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *     See the License for the specific language governing permissions and
 *     limitations under the License.
 */
package com.github.gtache.lsp.settings.gui;

import com.github.gtache.lsp.PluginMain$;
import com.github.gtache.lsp.client.languageserver.serverdefinition.*;
import com.github.gtache.lsp.settings.LSPState;
import com.github.gtache.lsp.utils.Utils;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.ui.ComboBox;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.TextBrowseFolderListener;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.uiDesigner.core.GridConstraints;
import com.intellij.uiDesigner.core.GridLayoutManager;
import com.intellij.uiDesigner.core.Spacer;
import com.intellij.util.ui.JBUI;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ItemEvent;
import java.util.*;
import java.util.List;
import java.util.stream.Collectors;

/**
 * The GUI for the LSP ServerDefinition settings
 */ //TODO improve
public final class ServersGUI implements LSPGUI {

    private static final String EXT_LABEL = "Extension";
    private static final String EXT_TOOLTIP = "e.g. scala, java, c, js, ...";
    private static final String EXT = "ext";
    private static final String MAINCLASS = "mainclass";
    private static final String ARGS = "args";
    private static final String PACKGE = "packge";
    private static final String COMMAND = "command";
    private static final String PATH = "path";
    private static final Logger LOG = Logger.getInstance(ServersGUI.class);
    private static final String FILE_PATH_LABEL = "Path";
    private final LSPState state = state();
    private final JPanel rootPanel;
    private final List<ServersGUIRow> rows = new ArrayList<>(5);
    private final Map<String, UserConfigurableServerDefinition> serverDefinitions = new LinkedHashMap<>(5);

    public ServersGUI() {
        rootPanel = new JPanel();
        rootPanel.setLayout(new BoxLayout(rootPanel, BoxLayout.Y_AXIS));
        rootPanel.add(createArtifactRow("", "", "", ""));
    }

    @Override
    public JPanel getRootPanel() {
        return rootPanel;
    }

    public Collection<ServersGUIRow> getRows() {
        return rows;
    }

    public void clear() {
        rows.clear();
        serverDefinitions.clear();
        rootPanel.removeAll();
    }

    public void addServerDefinition(final UserConfigurableServerDefinition serverDefinition) {
        if (serverDefinition != null) {
            serverDefinitions.put(serverDefinition.ext(), serverDefinition);
            if (serverDefinition.getClass().equals(ArtifactLanguageServerDefinition.class)) {
                final ArtifactLanguageServerDefinition def = (ArtifactLanguageServerDefinition) serverDefinition;
                rootPanel.add(createArtifactRow(def.ext(), def.packge(), def.mainClass(), Utils.arrayToString(def.args(), " ")));
            } else if (serverDefinition.getClass().equals(ExeLanguageServerDefinition.class)) {
                final ExeLanguageServerDefinition def = (ExeLanguageServerDefinition) serverDefinition;
                rootPanel.add(createExeRow(def.ext(), def.path(), Utils.arrayToString(def.args(), " ")));
            } else if (serverDefinition.getClass().equals(RawCommandServerDefinition.class)) {
                final RawCommandServerDefinition def = (RawCommandServerDefinition) serverDefinition;
                rootPanel.add(createCommandRow(def.ext(), Utils.arrayToString(def.command(), " ")));
            } else {
                LOG.error("Unknown UserConfigurableServerDefinition : " + serverDefinition);
            }
        }
    }

    @Override
    public void apply() {
        final List<String> extensions = rows.stream().map(row -> row.getText(EXT)).collect(Collectors.toList());
        final Set<String> distinct = new ArrayList<>(extensions).stream().distinct().collect(Collectors.toSet());
        distinct.forEach(extensions::remove);
        if (!extensions.isEmpty()) {
            Messages.showWarningDialog(extensions.stream().reduce((f, s) -> "Duplicate : " + f + Utils.lineSeparator() + s).orElse("Error while getting extensions") + Utils.lineSeparator() + "Unexpected behavior may occur", "Duplicate Extensions");
        }
        //TODO manage without restarting
        //Messages.showInfoMessage("The changes will be applied after restarting the IDE.", "LSP Settings");
        serverDefinitions.clear();
        for (final ServersGUIRow row : rows) {
            final String[] arr = row.toStringArray();
            final String ext = row.getText(EXT);
            final UserConfigurableServerDefinition serverDefinition = UserConfigurableServerDefinition$.MODULE$.fromArray(arr);
            if (serverDefinition != null) {
                serverDefinitions.put(ext, serverDefinition);
            }
        }
        LSPState.getInstance().setExtToServ(serverDefinitions);
        PluginMain$.MODULE$.setExtToServerDefinition(serverDefinitions);
    }

    @Override
    public boolean isModified() {
        if (serverDefinitions.size() == rows.stream().filter(row -> Arrays.stream(row.toStringArray()).skip(1).anyMatch(s -> s != null && !s.isEmpty())).collect(Collectors.toList()).size()) {
            for (final ServersGUIRow row : rows) {
                final UserConfigurableServerDefinition stateDef = serverDefinitions.get(row.getText(EXT));
                final UserConfigurableServerDefinition rowDef = UserConfigurableServerDefinition$.MODULE$.fromArray(row.toStringArray());
                if (rowDef != null && !rowDef.equals(stateDef)) {
                    return true;
                }
            }
            return false;
        } else {
            return true;
        }
    }

    @Override
    public void reset() {
        this.clear();
        if (state.getExtToServ() != null && !state.getExtToServ().isEmpty()) {
            for (final UserConfigurableServerDefinition serverDefinition : state.getExtToServ().values()) {
                addServerDefinition(serverDefinition);
            }
        } else {
            rootPanel.add(createArtifactRow("", "", "", ""));
        }
    }

    private JComboBox<String> createComboBox(final JPanel panel, final String selected) {
        final JComboBox<String> typeBox = new ComboBox<>();
        final ConfigurableTypes[] types = ConfigurableTypes.values();
        for (final ConfigurableTypes type : types) {
            typeBox.addItem(type.getTyp());
        }
        typeBox.setSelectedItem(selected);
        typeBox.addItemListener(e -> {
            if (e.getStateChange() == ItemEvent.SELECTED) {
                final int idx = getComponentIndex(panel);
                if (e.getItem().equals(ConfigurableTypes.ARTIFACT.getTyp())) {
                    rootPanel.add(createArtifactRow("", "", "", ""), idx);
                    rootPanel.remove(panel);
                    rows.remove(idx);
                } else if (e.getItem().equals(ConfigurableTypes.RAWCOMMAND.getTyp())) {
                    rootPanel.add(createCommandRow("", ""), idx);
                    rootPanel.remove(panel);
                    rows.remove(idx);
                } else if (e.getItem().equals(ConfigurableTypes.EXE.getTyp())) {
                    rootPanel.add(createExeRow("", "", ""), idx);
                    rootPanel.remove(panel);
                    rows.remove(idx);
                } else {
                    LOG.error("Unknown type : " + e.getItem());
                }
            }
        });
        return typeBox;
    }

    private JButton createNewRowButton() {
        final JButton newRowButton = new JButton();
        newRowButton.setText("+");
        newRowButton.addActionListener(e -> rootPanel.add(createArtifactRow("", "", "", "")));
        return newRowButton;
    }

    private JButton createRemoveRowButton(final JPanel panel) {
        final JButton removeRowButton = new JButton();
        removeRowButton.setText("-");
        removeRowButton.addActionListener(e -> {
            final int idx = getComponentIndex(panel);
            rootPanel.remove(panel);
            rows.remove(idx);
        });
        return removeRowButton;
    }

    private JPanel createRow(final Collection<JComponent> labelFields, final String selectedItem) {
        final JPanel panel = new JPanel();
        int colIdx = 0;
        panel.setLayout(new GridLayoutManager(2, 17, JBUI.emptyInsets(), -1, -1));

        panel.add(new Spacer(), new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, 1, GridConstraints.SIZEPOLICY_FIXED, new Dimension(0, 10), new Dimension(0, 10), new Dimension(0, 10), 0, false));
        final JComboBox<String> typeBox = createComboBox(panel, selectedItem);
        panel.add(typeBox, new GridConstraints(0, colIdx++, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));

        final Iterator<JComponent> iterator = labelFields.iterator();
        while (iterator.hasNext()) {
            final JComponent label = iterator.next();
            final JComponent field = iterator.next();
            panel.add(new Spacer(), new GridConstraints(0, colIdx++, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_GROW, 1, null, null, null, 0, false));
            panel.add(label, new GridConstraints(0, colIdx++, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
            panel.add(field, new GridConstraints(0, colIdx++, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension(150, -1), null, 0, false));
        }

        panel.add(new Spacer(), new GridConstraints(0, 14, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false));
        final JButton newRowButton = createNewRowButton();
        panel.add(newRowButton, new GridConstraints(0, 15, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        if (rows.isEmpty()) {
            panel.add(new Spacer(), new GridConstraints(0, 16, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_GROW, 1, null, null, null, 0, false));
        } else {
            final JButton removeRowButton = createRemoveRowButton(panel);
            panel.add(removeRowButton, new GridConstraints(0, 16, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        }

        panel.setAlignmentX(Component.LEFT_ALIGNMENT);
        return panel;
    }

    private JPanel createArtifactRow(final String ext, final String serv, final String mainClass, final String args) {
        final JLabel extLabel = new JLabel(EXT_LABEL);
        final JTextField extField = new JTextField();
        extField.setToolTipText(EXT_TOOLTIP);
        extField.setText(ext);
        final JLabel packgeLabel = new JLabel("Artifact");
        final JTextField packgeField = new JTextField();
        packgeField.setToolTipText("e.g. ch.epfl.lamp:dotty-language-server_0.3:0.3.0-RC2");
        packgeField.setText(serv);
        final JLabel mainClassLabel = new JLabel("Main class");
        final JTextField mainClassField = new JTextField();
        mainClassField.setToolTipText("e.g. dotty.tools.languageserver.Main");
        mainClassField.setText(mainClass);
        final JLabel argsLabel = new JLabel("Args");
        final JTextField argsField = new JTextField();
        argsField.setToolTipText("e.g. -stdio");
        argsField.setText(args);

        final List<JComponent> components = Arrays.asList(extLabel, extField, packgeLabel, packgeField, mainClassLabel, mainClassField, argsLabel, argsField);
        final JPanel panel = createRow(components, ArtifactLanguageServerDefinition$.MODULE$.getPresentableTyp());
        final scala.collection.mutable.LinkedHashMap<String, JComponent> map = new scala.collection.mutable.LinkedHashMap<>();
        map.put(EXT, extField);
        map.put(PACKGE, packgeField);
        map.put(MAINCLASS, mainClassField);
        map.put(ARGS, argsField);
        rows.add(new ServersGUIRow(panel, ArtifactLanguageServerDefinition$.MODULE$.typ(), map));
        return panel;
    }

    private JPanel createExeRow(final String ext, final String path, final String args) {
        final JLabel extLabel = new JLabel(EXT_LABEL);
        final JTextField extField = new JTextField();
        extField.setToolTipText(EXT_TOOLTIP);
        extField.setText(ext);
        final JLabel pathLabel = new JLabel(FILE_PATH_LABEL);
        final TextFieldWithBrowseButton pathField = new TextFieldWithBrowseButton();
        pathField.setToolTipText("e.g. C:\\rustLS\\rls.exe");
        pathField.setText(path);
        pathField.addBrowseFolderListener(new TextBrowseFolderListener(new FileChooserDescriptor(true, false, true, true, true, false).withShowHiddenFiles(true)));
        final JLabel argsLabel = new JLabel("Args");
        final JTextField argsField = new JTextField();
        argsField.setToolTipText("e.g. -stdio");
        argsField.setText(args);

        final List<JComponent> components = Arrays.asList(extLabel, extField, pathLabel, pathField, argsLabel, argsField);
        final JPanel panel = createRow(components, ExeLanguageServerDefinition$.MODULE$.getPresentableTyp());
        final scala.collection.mutable.LinkedHashMap<String, JComponent> map = new scala.collection.mutable.LinkedHashMap<>();
        map.put(EXT, extField);
        map.put(PATH, pathField);
        map.put(ARGS, argsField);
        rows.add(new ServersGUIRow(panel, ExeLanguageServerDefinition$.MODULE$.typ(), map));
        return panel;
    }

    private JPanel createCommandRow(final String ext, final String command) {
        final JLabel extLabel = new JLabel(EXT_LABEL);
        final JTextField extField = new JTextField();
        extField.setToolTipText(EXT_TOOLTIP);
        extField.setText(ext);
        final JLabel commandLabel = new JLabel("Command");
        final TextFieldWithBrowseButton commandField = new TextFieldWithBrowseButton();
        commandField.setText(command);
        commandField.setToolTipText("e.g. python.exe -m C:\\python-ls\\pyls");
        commandField.addBrowseFolderListener(new TextBrowseFolderListener(new FileChooserDescriptor(true, false, true, true, true, false).withShowHiddenFiles(true)));

        final List<JComponent> components = Arrays.asList(extLabel, extField, commandLabel, commandField);
        final JPanel panel = createRow(components, RawCommandServerDefinition$.MODULE$.getPresentableTyp());
        final scala.collection.mutable.LinkedHashMap<String, JComponent> map = new scala.collection.mutable.LinkedHashMap<>();
        map.put(EXT, extField);
        map.put(COMMAND, commandField);
        rows.add(new ServersGUIRow(panel, RawCommandServerDefinition$.MODULE$.typ(), map));
        return panel;
    }

    private int getComponentIndex(final JComponent component) {
        for (int i = 0; i < rootPanel.getComponentCount(); ++i) {
            if (rootPanel.getComponent(i).equals(component)) {
                return i;
            }
        }
        return -1;
    }
}