class LSPServerEditor(QDialog): DEFAULT_HOST = '127.0.0.1' DEFAULT_PORT = 2084 DEFAULT_CMD = '' DEFAULT_ARGS = '' DEFAULT_CONFIGURATION = '{}' DEFAULT_EXTERNAL = False DEFAULT_STDIO = False HOST_REGEX = re.compile(r'^\w+([.]\w+)*$') NON_EMPTY_REGEX = re.compile(r'^\S+$') JSON_VALID = _('Valid JSON') JSON_INVALID = _('Invalid JSON') MIN_SIZE = QSize(850, 600) INVALID_CSS = "QLineEdit {border: 1px solid red;}" VALID_CSS = "QLineEdit {border: 1px solid green;}" def __init__(self, parent, language=None, cmd='', host='127.0.0.1', port=2084, args='', external=False, stdio=False, configurations={}, **kwargs): super(LSPServerEditor, self).__init__(parent) description = _( "To create a new server configuration, you need to select a " "programming language, set the command to start its associated " "server and enter any arguments that should be passed to it on " "startup. Additionally, you can set the server's hostname and " "port if connecting to an external server, " "or to a local one using TCP instead of stdio pipes." "<br><br>" "<i>Note</i>: You can use the placeholders <tt>{host}</tt> and " "<tt>{port}</tt> in the server arguments field to automatically " "fill in the respective values.<br>" ) self.parent = parent self.external = external # Widgets self.server_settings_description = QLabel(description) self.lang_cb = QComboBox(self) self.external_cb = QCheckBox(_('External server'), self) self.host_label = QLabel(_('Host:')) self.host_input = QLineEdit(self) self.port_label = QLabel(_('Port:')) self.port_spinner = QSpinBox(self) self.cmd_label = QLabel(_('Command:')) self.cmd_input = QLineEdit(self) self.args_label = QLabel(_('Arguments:')) self.args_input = QLineEdit(self) self.json_label = QLabel(self.JSON_VALID, self) self.conf_label = QLabel(_('<b>Server Configuration:</b>')) self.conf_input = CodeEditor(None) self.bbox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.button_ok = self.bbox.button(QDialogButtonBox.Ok) self.button_cancel = self.bbox.button(QDialogButtonBox.Cancel) # Widget setup self.setMinimumSize(self.MIN_SIZE) self.setWindowTitle(_('LSP server editor')) self.server_settings_description.setWordWrap(True) self.lang_cb.setToolTip( _('Programming language provided by the LSP server')) self.lang_cb.addItem(_('Select a language')) self.lang_cb.addItems(LSP_LANGUAGES) self.button_ok.setEnabled(False) if language is not None: idx = LSP_LANGUAGES.index(language) self.lang_cb.setCurrentIndex(idx + 1) self.button_ok.setEnabled(True) self.host_input.setPlaceholderText('127.0.0.1') self.host_input.setText(host) self.host_input.textChanged.connect(lambda x: self.validate()) self.port_spinner.setToolTip(_('TCP port number of the server')) self.port_spinner.setMinimum(1) self.port_spinner.setMaximum(60000) self.port_spinner.setValue(port) self.cmd_input.setText(cmd) self.cmd_input.setPlaceholderText('/absolute/path/to/command') self.args_input.setToolTip( _('Additional arguments required to start the server')) self.args_input.setText(args) self.args_input.setPlaceholderText(r'--host {host} --port {port}') self.conf_input.setup_editor( language='json', color_scheme=CONF.get('appearance', 'selected'), wrap=False, edge_line=True, highlight_current_line=True, highlight_current_cell=True, occurrence_highlighting=True, auto_unindent=True, font=get_font(), filename='config.json', folding=False ) self.conf_input.set_language('json', 'config.json') self.conf_input.setToolTip(_('Additional LSP server configuration ' 'set at runtime. JSON required')) try: conf_text = json.dumps(configurations, indent=4, sort_keys=True) except Exception: conf_text = '{}' self.conf_input.set_text(conf_text) self.external_cb.setToolTip( _('Check if the server runs on a remote location')) self.external_cb.setChecked(external) self.stdio_cb = QCheckBox(_('Use stdio pipes for communication'), self) self.stdio_cb.setToolTip(_('Check if the server communicates ' 'using stdin/out pipes')) self.stdio_cb.setChecked(stdio) # Layout setup hlayout = QHBoxLayout() general_vlayout = QVBoxLayout() general_vlayout.addWidget(self.server_settings_description) vlayout = QVBoxLayout() lang_group = QGroupBox(_('Language')) lang_layout = QVBoxLayout() lang_layout.addWidget(self.lang_cb) lang_group.setLayout(lang_layout) vlayout.addWidget(lang_group) server_group = QGroupBox(_('Language server')) server_layout = QGridLayout() server_layout.addWidget(self.cmd_label, 0, 0) server_layout.addWidget(self.cmd_input, 0, 1) server_layout.addWidget(self.args_label, 1, 0) server_layout.addWidget(self.args_input, 1, 1) server_group.setLayout(server_layout) vlayout.addWidget(server_group) address_group = QGroupBox(_('Server address')) host_layout = QVBoxLayout() host_layout.addWidget(self.host_label) host_layout.addWidget(self.host_input) port_layout = QVBoxLayout() port_layout.addWidget(self.port_label) port_layout.addWidget(self.port_spinner) conn_info_layout = QHBoxLayout() conn_info_layout.addLayout(host_layout) conn_info_layout.addLayout(port_layout) address_group.setLayout(conn_info_layout) vlayout.addWidget(address_group) advanced_group = QGroupBox(_('Advanced')) advanced_layout = QVBoxLayout() advanced_layout.addWidget(self.external_cb) advanced_layout.addWidget(self.stdio_cb) advanced_group.setLayout(advanced_layout) vlayout.addWidget(advanced_group) conf_layout = QVBoxLayout() conf_layout.addWidget(self.conf_label) conf_layout.addWidget(self.conf_input) conf_layout.addWidget(self.json_label) vlayout.addStretch() hlayout.addLayout(vlayout, 2) hlayout.addLayout(conf_layout, 3) general_vlayout.addLayout(hlayout) general_vlayout.addWidget(self.bbox) self.setLayout(general_vlayout) self.form_status(False) # Signals if not external: self.cmd_input.textChanged.connect(lambda x: self.validate()) self.external_cb.stateChanged.connect(self.set_local_options) self.stdio_cb.stateChanged.connect(self.set_stdio_options) self.lang_cb.currentIndexChanged.connect(self.lang_selection_changed) self.conf_input.textChanged.connect(self.validate) self.bbox.accepted.connect(self.accept) self.bbox.rejected.connect(self.reject) # Final setup if language is not None: self.form_status(True) self.validate() if stdio: self.set_stdio_options(True) if external: self.set_local_options(True) @Slot() def validate(self): host_text = self.host_input.text() cmd_text = self.cmd_input.text() if not self.HOST_REGEX.match(host_text): self.button_ok.setEnabled(False) self.host_input.setStyleSheet(self.INVALID_CSS) if bool(host_text): self.host_input.setToolTip(_('Hostname must be valid')) else: self.host_input.setToolTip( _('Hostname or IP address of the host on which the server ' 'is running. Must be non empty.')) else: self.host_input.setStyleSheet(self.VALID_CSS) self.host_input.setToolTip(_('Hostname is valid')) self.button_ok.setEnabled(True) if not self.external: if not self.NON_EMPTY_REGEX.match(cmd_text): self.button_ok.setEnabled(False) self.cmd_input.setStyleSheet(self.INVALID_CSS) self.cmd_input.setToolTip( _('Command used to start the LSP server locally. Must be ' 'non empty')) return if find_program(cmd_text) is None: self.button_ok.setEnabled(False) self.cmd_input.setStyleSheet(self.INVALID_CSS) self.cmd_input.setToolTip(_('Program was not found ' 'on your system')) else: self.cmd_input.setStyleSheet(self.VALID_CSS) self.cmd_input.setToolTip(_('Program was found on your ' 'system')) self.button_ok.setEnabled(True) try: json.loads(self.conf_input.toPlainText()) try: self.json_label.setText(self.JSON_VALID) except Exception: pass except ValueError: try: self.json_label.setText(self.JSON_INVALID) self.button_ok.setEnabled(False) except Exception: pass def form_status(self, status): self.host_input.setEnabled(status) self.port_spinner.setEnabled(status) self.external_cb.setEnabled(status) self.stdio_cb.setEnabled(status) self.cmd_input.setEnabled(status) self.args_input.setEnabled(status) self.conf_input.setEnabled(status) self.json_label.setVisible(status) @Slot() def lang_selection_changed(self): idx = self.lang_cb.currentIndex() if idx == 0: self.set_defaults() self.form_status(False) self.button_ok.setEnabled(False) else: server = self.parent.get_server_by_lang(LSP_LANGUAGES[idx - 1]) self.form_status(True) if server is not None: self.host_input.setText(server.host) self.port_spinner.setValue(server.port) self.external_cb.setChecked(server.external) self.stdio_cb.setChecked(server.stdio) self.cmd_input.setText(server.cmd) self.args_input.setText(server.args) self.conf_input.set_text(json.dumps(server.configurations)) self.json_label.setText(self.JSON_VALID) self.button_ok.setEnabled(True) else: self.set_defaults() def set_defaults(self): self.cmd_input.setStyleSheet('') self.host_input.setStyleSheet('') self.host_input.setText(self.DEFAULT_HOST) self.port_spinner.setValue(self.DEFAULT_PORT) self.external_cb.setChecked(self.DEFAULT_EXTERNAL) self.stdio_cb.setChecked(self.DEFAULT_STDIO) self.cmd_input.setText(self.DEFAULT_CMD) self.args_input.setText(self.DEFAULT_ARGS) self.conf_input.set_text(self.DEFAULT_CONFIGURATION) self.json_label.setText(self.JSON_VALID) @Slot(bool) @Slot(int) def set_local_options(self, enabled): self.external = enabled self.cmd_input.setEnabled(True) self.args_input.setEnabled(True) if enabled: self.cmd_input.setEnabled(False) self.cmd_input.setStyleSheet('') self.args_input.setEnabled(False) self.stdio_cb.stateChanged.disconnect() self.stdio_cb.setChecked(False) self.stdio_cb.setEnabled(False) else: self.cmd_input.setEnabled(True) self.args_input.setEnabled(True) self.stdio_cb.setEnabled(True) self.stdio_cb.setChecked(False) self.stdio_cb.stateChanged.connect(self.set_stdio_options) try: self.validate() except Exception: pass @Slot(bool) @Slot(int) def set_stdio_options(self, enabled): self.stdio = enabled if enabled: self.cmd_input.setEnabled(True) self.args_input.setEnabled(True) self.external_cb.stateChanged.disconnect() self.external_cb.setChecked(False) self.external_cb.setEnabled(False) self.host_input.setStyleSheet('') self.host_input.setEnabled(False) self.port_spinner.setEnabled(False) else: self.cmd_input.setEnabled(True) self.args_input.setEnabled(True) self.external_cb.setChecked(False) self.external_cb.setEnabled(True) self.external_cb.stateChanged.connect(self.set_local_options) self.host_input.setEnabled(True) self.port_spinner.setEnabled(True) try: self.validate() except Exception: pass def get_options(self): language_idx = self.lang_cb.currentIndex() language = LSP_LANGUAGES[language_idx - 1] host = self.host_input.text() port = int(self.port_spinner.value()) external = self.external_cb.isChecked() stdio = self.stdio_cb.isChecked() args = self.args_input.text() cmd = self.cmd_input.text() configurations = json.loads(self.conf_input.toPlainText()) server = LSPServer(language=language.lower(), cmd=cmd, args=args, host=host, port=port, external=external, stdio=stdio, configurations=configurations) return server
class LSPServerEditor(QDialog): DEFAULT_HOST = '127.0.0.1' DEFAULT_PORT = 2084 DEFAULT_CMD = '' DEFAULT_ARGS = '' DEFAULT_CONFIGURATION = '{}' DEFAULT_EXTERNAL = False HOST_REGEX = re.compile(r'^\w+([.]\w+)*$') NON_EMPTY_REGEX = re.compile(r'^\S+$') JSON_VALID = _('JSON valid') JSON_INVALID = _('JSON invalid') def __init__(self, parent, language=None, cmd='', host='127.0.0.1', port=2084, args='', external=False, configurations={}, **kwargs): super(LSPServerEditor, self).__init__(parent) self.parent = parent self.external = external bbox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.button_ok = bbox.button(QDialogButtonBox.Ok) self.button_cancel = bbox.button(QDialogButtonBox.Cancel) self.button_ok.setEnabled(False) description = _('To create a new configuration, ' 'you need to select a programming ' 'language, along with a executable ' 'name for the server to execute ' '(If the instance is local), ' 'and the host and port. Finally, ' 'you need to provide the ' 'arguments that the server accepts. ' 'The placeholders <tt>%(host)s</tt> and ' '<tt>%(port)s</tt> refer to the host ' 'and the port, respectively.') server_settings_description = QLabel(description) server_settings_description.setWordWrap(True) lang_label = QLabel(_('Language:')) self.lang_cb = QComboBox(self) self.lang_cb.setToolTip(_('Programming language provided ' 'by the LSP server')) self.lang_cb.addItem(_('Select a language')) self.lang_cb.addItems(LSP_LANGUAGES) if language is not None: idx = LSP_LANGUAGES.index(language) self.lang_cb.setCurrentIndex(idx + 1) self.button_ok.setEnabled(True) host_label = QLabel(_('Host:')) self.host_input = QLineEdit(self) self.host_input.setToolTip(_('Name of the host that will provide ' 'access to the server')) self.host_input.setText(host) self.host_input.textChanged.connect(lambda x: self.validate()) port_label = QLabel(_('Port:')) self.port_spinner = QSpinBox(self) self.port_spinner.setToolTip(_('TCP port number of the server')) self.port_spinner.setMinimum(1) self.port_spinner.setMaximum(60000) self.port_spinner.setValue(port) cmd_label = QLabel(_('Command to execute:')) self.cmd_input = QLineEdit(self) self.cmd_input.setToolTip(_('Command used to start the ' 'LSP server locally')) self.cmd_input.setText(cmd) if not external: self.cmd_input.textChanged.connect(lambda x: self.validate()) args_label = QLabel(_('Server arguments:')) self.args_input = QLineEdit(self) self.args_input.setToolTip(_('Additional arguments required to ' 'start the server')) self.args_input.setText(args) conf_label = QLabel(_('LSP Server Configurations:')) self.conf_input = CodeEditor(None) self.conf_input.textChanged.connect(self.validate) color_scheme = CONF.get('color_schemes', 'selected') self.conf_input.setup_editor( language='JSON', color_scheme=color_scheme, wrap=False, edge_line=True, highlight_current_line=True, highlight_current_cell=True, occurrence_highlighting=True, auto_unindent=True, font=get_font(), filename='config.json') self.conf_input.setToolTip(_('Additional LSP server configurations ' 'set at runtime. JSON required')) conf_text = '{}' try: conf_text = json.dumps(configurations, indent=4, sort_keys=True) except Exception: pass self.conf_input.set_text(conf_text) self.json_label = QLabel(self.JSON_VALID, self) self.external_cb = QCheckBox(_('External server'), self) self.external_cb.setToolTip(_('Check if the server runs ' 'on a remote location')) self.external_cb.setChecked(external) self.external_cb.stateChanged.connect(self.set_local_options) hlayout = QHBoxLayout() general_vlayout = QVBoxLayout() general_vlayout.addWidget(server_settings_description) vlayout = QVBoxLayout() lang_layout = QVBoxLayout() lang_layout.addWidget(lang_label) lang_layout.addWidget(self.lang_cb) # layout2 = QHBoxLayout() # layout2.addLayout(lang_layout) lang_layout.addWidget(self.external_cb) vlayout.addLayout(lang_layout) host_layout = QVBoxLayout() host_layout.addWidget(host_label) host_layout.addWidget(self.host_input) port_layout = QVBoxLayout() port_layout.addWidget(port_label) port_layout.addWidget(self.port_spinner) conn_info_layout = QHBoxLayout() conn_info_layout.addLayout(host_layout) conn_info_layout.addLayout(port_layout) vlayout.addLayout(conn_info_layout) cmd_layout = QVBoxLayout() cmd_layout.addWidget(cmd_label) cmd_layout.addWidget(self.cmd_input) vlayout.addLayout(cmd_layout) args_layout = QVBoxLayout() args_layout.addWidget(args_label) args_layout.addWidget(self.args_input) vlayout.addLayout(args_layout) conf_layout = QVBoxLayout() conf_layout.addWidget(conf_label) conf_layout.addWidget(self.conf_input) conf_layout.addWidget(self.json_label) hlayout.addLayout(vlayout) hlayout.addLayout(conf_layout) general_vlayout.addLayout(hlayout) general_vlayout.addWidget(bbox) self.setLayout(general_vlayout) bbox.accepted.connect(self.accept) bbox.rejected.connect(self.reject) self.lang_cb.currentIndexChanged.connect( self.lang_selection_changed) self.form_status(False) if language is not None: self.form_status(True) self.validate() @Slot() def validate(self): host_text = self.host_input.text() cmd_text = self.cmd_input.text() if not self.HOST_REGEX.match(host_text): self.button_ok.setEnabled(False) self.host_input.setStyleSheet("QLineEdit{border: 1px solid red;}") self.host_input.setToolTip('Hostname must be valid') return else: self.host_input.setStyleSheet( "QLineEdit{border: 1px solid green;}") self.host_input.setToolTip('Hostname is valid') self.button_ok.setEnabled(True) if not self.external: if not self.NON_EMPTY_REGEX.match(cmd_text): self.button_ok.setEnabled(False) self.cmd_input.setStyleSheet( "QLineEdit{border: 1px solid red;}") self.cmd_input.setToolTip('Command must be non empty') return if find_program(cmd_text) is None: self.button_ok.setEnabled(False) self.cmd_input.setStyleSheet( "QLineEdit{border: 1px solid red;}") self.cmd_input.setToolTip('Program was not found ' 'on your system') return else: self.cmd_input.setStyleSheet( "QLineEdit{border: 1px solid green;}") self.cmd_input.setToolTip('Program was found on your system') self.button_ok.setEnabled(True) try: json.loads(self.conf_input.toPlainText()) try: self.json_label.setText(self.JSON_VALID) except: pass except (ValueError, json.decoder.JSONDecodeError): try: self.json_label.setText(self.JSON_INVALID) self.button_ok.setEnabled(False) except: pass def form_status(self, status): self.host_input.setEnabled(status) self.port_spinner.setEnabled(status) self.external_cb.setEnabled(status) self.cmd_input.setEnabled(status) self.args_input.setEnabled(status) self.conf_input.setEnabled(status) self.json_label.setVisible(status) @Slot() def lang_selection_changed(self): idx = self.lang_cb.currentIndex() if idx == 0: self.set_defaults() self.form_status(False) self.button_ok.setEnabled(False) else: server = self.parent.get_server_by_lang(LSP_LANGUAGES[idx - 1]) self.form_status(True) if server is not None: self.host_input.setText(server.host) self.port_spinner.setValue(server.port) self.external_cb.setChecked(server.external) self.cmd_input.setText(server.cmd) self.args_input.setText(server.args) self.conf_input.set_text(json.dumps(server.configurations)) self.json_label.setText(self.JSON_VALID) self.button_ok.setEnabled(True) else: self.set_defaults() def set_defaults(self): self.cmd_input.setStyleSheet('') self.host_input.setStyleSheet('') self.host_input.setText(self.DEFAULT_HOST) self.port_spinner.setValue(self.DEFAULT_PORT) self.external_cb.setChecked(self.DEFAULT_EXTERNAL) self.cmd_input.setText(self.DEFAULT_CMD) self.args_input.setText(self.DEFAULT_ARGS) self.conf_input.set_text(self.DEFAULT_CONFIGURATION) self.json_label.setText(self.JSON_VALID) @Slot(bool) @Slot(int) def set_local_options(self, enabled): self.external = enabled self.cmd_input.setEnabled(True) self.args_input.setEnabled(True) if enabled: self.cmd_input.setEnabled(False) self.cmd_input.setStyleSheet('') self.args_input.setEnabled(False) try: self.validate() except: pass def get_options(self): language_idx = self.lang_cb.currentIndex() language = LSP_LANGUAGES[language_idx - 1] host = self.host_input.text() port = int(self.port_spinner.value()) external = self.external_cb.isChecked() args = self.args_input.text() cmd = self.cmd_input.text() configurations = json.loads(self.conf_input.toPlainText()) server = LSPServer(language=language.lower(), cmd=cmd, args=args, host=host, port=port, external=external, configurations=configurations) return server
class LSPServerEditor(QDialog): DEFAULT_HOST = '127.0.0.1' DEFAULT_PORT = 2084 DEFAULT_CMD = '' DEFAULT_ARGS = '' DEFAULT_CONFIGURATION = '{}' DEFAULT_EXTERNAL = False HOST_REGEX = re.compile(r'^\w+([.]\w+)*$') NON_EMPTY_REGEX = re.compile(r'^\S+$') JSON_VALID = _('JSON valid') JSON_INVALID = _('JSON invalid') def __init__(self, parent, language=None, cmd='', host='127.0.0.1', port=2084, args='', external=False, configurations={}, **kwargs): super(LSPServerEditor, self).__init__(parent) self.parent = parent self.external = external bbox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.button_ok = bbox.button(QDialogButtonBox.Ok) self.button_cancel = bbox.button(QDialogButtonBox.Cancel) self.button_ok.setEnabled(False) description = _('To create a new configuration, ' 'you need to select a programming ' 'language, along with a executable ' 'name for the server to execute ' '(If the instance is local), ' 'and the host and port. Finally, ' 'you need to provide the ' 'arguments that the server accepts. ' 'The placeholders <tt>%(host)s</tt> and ' '<tt>%(port)s</tt> refer to the host ' 'and the port, respectively.') server_settings_description = QLabel(description) server_settings_description.setWordWrap(True) lang_label = QLabel(_('Language:')) self.lang_cb = QComboBox(self) self.lang_cb.setToolTip(_('Programming language provided ' 'by the LSP server')) self.lang_cb.addItem(_('Select a language')) self.lang_cb.addItems(LSP_LANGUAGES) if language is not None: idx = LSP_LANGUAGES.index(language) self.lang_cb.setCurrentIndex(idx + 1) self.button_ok.setEnabled(True) host_label = QLabel(_('Host:')) self.host_input = QLineEdit(self) self.host_input.setToolTip(_('Name of the host that will provide ' 'access to the server')) self.host_input.setText(host) self.host_input.textChanged.connect(lambda x: self.validate()) port_label = QLabel(_('Port:')) self.port_spinner = QSpinBox(self) self.port_spinner.setToolTip(_('TCP port number of the server')) self.port_spinner.setMinimum(1) self.port_spinner.setMaximum(60000) self.port_spinner.setValue(port) cmd_label = QLabel(_('Command to execute:')) self.cmd_input = QLineEdit(self) self.cmd_input.setToolTip(_('Command used to start the ' 'LSP server locally')) self.cmd_input.setText(cmd) if not external: self.cmd_input.textChanged.connect(lambda x: self.validate()) args_label = QLabel(_('Server arguments:')) self.args_input = QLineEdit(self) self.args_input.setToolTip(_('Additional arguments required to ' 'start the server')) self.args_input.setText(args) conf_label = QLabel(_('LSP Server Configurations:')) self.conf_input = CodeEditor(None) self.conf_input.textChanged.connect(self.validate) color_scheme = CONF.get('appearance', 'selected') self.conf_input.setup_editor( language='JSON', color_scheme=color_scheme, wrap=False, edge_line=True, highlight_current_line=True, highlight_current_cell=True, occurrence_highlighting=True, auto_unindent=True, font=get_font(), filename='config.json') self.conf_input.setToolTip(_('Additional LSP server configurations ' 'set at runtime. JSON required')) conf_text = '{}' try: conf_text = json.dumps(configurations, indent=4, sort_keys=True) except Exception: pass self.conf_input.set_text(conf_text) self.json_label = QLabel(self.JSON_VALID, self) self.external_cb = QCheckBox(_('External server'), self) self.external_cb.setToolTip(_('Check if the server runs ' 'on a remote location')) self.external_cb.setChecked(external) self.external_cb.stateChanged.connect(self.set_local_options) hlayout = QHBoxLayout() general_vlayout = QVBoxLayout() general_vlayout.addWidget(server_settings_description) vlayout = QVBoxLayout() lang_layout = QVBoxLayout() lang_layout.addWidget(lang_label) lang_layout.addWidget(self.lang_cb) # layout2 = QHBoxLayout() # layout2.addLayout(lang_layout) lang_layout.addWidget(self.external_cb) vlayout.addLayout(lang_layout) host_layout = QVBoxLayout() host_layout.addWidget(host_label) host_layout.addWidget(self.host_input) port_layout = QVBoxLayout() port_layout.addWidget(port_label) port_layout.addWidget(self.port_spinner) conn_info_layout = QHBoxLayout() conn_info_layout.addLayout(host_layout) conn_info_layout.addLayout(port_layout) vlayout.addLayout(conn_info_layout) cmd_layout = QVBoxLayout() cmd_layout.addWidget(cmd_label) cmd_layout.addWidget(self.cmd_input) vlayout.addLayout(cmd_layout) args_layout = QVBoxLayout() args_layout.addWidget(args_label) args_layout.addWidget(self.args_input) vlayout.addLayout(args_layout) conf_layout = QVBoxLayout() conf_layout.addWidget(conf_label) conf_layout.addWidget(self.conf_input) conf_layout.addWidget(self.json_label) hlayout.addLayout(vlayout) hlayout.addLayout(conf_layout) general_vlayout.addLayout(hlayout) general_vlayout.addWidget(bbox) self.setLayout(general_vlayout) bbox.accepted.connect(self.accept) bbox.rejected.connect(self.reject) self.lang_cb.currentIndexChanged.connect( self.lang_selection_changed) self.form_status(False) if language is not None: self.form_status(True) self.validate() @Slot() def validate(self): host_text = self.host_input.text() cmd_text = self.cmd_input.text() if not self.HOST_REGEX.match(host_text): self.button_ok.setEnabled(False) self.host_input.setStyleSheet("QLineEdit{border: 1px solid red;}") self.host_input.setToolTip('Hostname must be valid') return else: self.host_input.setStyleSheet( "QLineEdit{border: 1px solid green;}") self.host_input.setToolTip('Hostname is valid') self.button_ok.setEnabled(True) if not self.external: if not self.NON_EMPTY_REGEX.match(cmd_text): self.button_ok.setEnabled(False) self.cmd_input.setStyleSheet( "QLineEdit{border: 1px solid red;}") self.cmd_input.setToolTip('Command must be non empty') return if find_program(cmd_text) is None: self.button_ok.setEnabled(False) self.cmd_input.setStyleSheet( "QLineEdit{border: 1px solid red;}") self.cmd_input.setToolTip('Program was not found ' 'on your system') return else: self.cmd_input.setStyleSheet( "QLineEdit{border: 1px solid green;}") self.cmd_input.setToolTip('Program was found on your system') self.button_ok.setEnabled(True) try: json.loads(self.conf_input.toPlainText()) try: self.json_label.setText(self.JSON_VALID) except: pass except (ValueError, json.decoder.JSONDecodeError): try: self.json_label.setText(self.JSON_INVALID) self.button_ok.setEnabled(False) except: pass def form_status(self, status): self.host_input.setEnabled(status) self.port_spinner.setEnabled(status) self.external_cb.setEnabled(status) self.cmd_input.setEnabled(status) self.args_input.setEnabled(status) self.conf_input.setEnabled(status) self.json_label.setVisible(status) @Slot() def lang_selection_changed(self): idx = self.lang_cb.currentIndex() if idx == 0: self.set_defaults() self.form_status(False) self.button_ok.setEnabled(False) else: server = self.parent.get_server_by_lang(LSP_LANGUAGES[idx - 1]) self.form_status(True) if server is not None: self.host_input.setText(server.host) self.port_spinner.setValue(server.port) self.external_cb.setChecked(server.external) self.cmd_input.setText(server.cmd) self.args_input.setText(server.args) self.conf_input.set_text(json.dumps(server.configurations)) self.json_label.setText(self.JSON_VALID) self.button_ok.setEnabled(True) else: self.set_defaults() def set_defaults(self): self.cmd_input.setStyleSheet('') self.host_input.setStyleSheet('') self.host_input.setText(self.DEFAULT_HOST) self.port_spinner.setValue(self.DEFAULT_PORT) self.external_cb.setChecked(self.DEFAULT_EXTERNAL) self.cmd_input.setText(self.DEFAULT_CMD) self.args_input.setText(self.DEFAULT_ARGS) self.conf_input.set_text(self.DEFAULT_CONFIGURATION) self.json_label.setText(self.JSON_VALID) @Slot(bool) @Slot(int) def set_local_options(self, enabled): self.external = enabled self.cmd_input.setEnabled(True) self.args_input.setEnabled(True) if enabled: self.cmd_input.setEnabled(False) self.cmd_input.setStyleSheet('') self.args_input.setEnabled(False) try: self.validate() except: pass def get_options(self): language_idx = self.lang_cb.currentIndex() language = LSP_LANGUAGES[language_idx - 1] host = self.host_input.text() port = int(self.port_spinner.value()) external = self.external_cb.isChecked() args = self.args_input.text() cmd = self.cmd_input.text() configurations = json.loads(self.conf_input.toPlainText()) server = LSPServer(language=language.lower(), cmd=cmd, args=args, host=host, port=port, external=external, configurations=configurations) return server