Beispiel #1
0
def construct_editor(qtbot, *args, **kwargs):
    os.environ['SPY_TEST_USE_INTROSPECTION'] = 'True'
    app = qapplication()
    lsp_manager = LSPManager(parent=None)
    editor = CodeEditor(parent=None)
    kwargs['language'] = 'Python'
    editor.setup_editor(*args, **kwargs)
    wrapper = LSPEditorWrapper(None, editor, lsp_manager)

    lsp_manager.register_plugin_type(
        LSPEventTypes.DOCUMENT, wrapper.sig_initialize)
    with qtbot.waitSignal(wrapper.sig_initialize, timeout=30000):
        editor.filename = 'test.py'
        editor.language = 'Python'
        lsp_manager.start_lsp_client('python')

    text = ("def some_function():\n"  # D100, D103: Missing docstring
            "    \n"  # W293 trailing spaces
            "    a = 1 # a comment\n"  # E261 two spaces before inline comment
            "\n"
            "    a += s\n"  # Undefined variable s
            "    return a\n"
            )
    editor.set_text(text)
    with qtbot.waitSignal(editor.lsp_response_signal, timeout=30000):
        editor.document_did_open()

    yield editor, lsp_manager
    os.environ['SPY_TEST_USE_INTROSPECTION'] = 'False'
    lsp_manager.closing_plugin()
Beispiel #2
0
def construct_editor(text):
    app = qapplication()
    editor = CodeEditor(parent=None)
    editor.setup_editor(language='Python')
    editor.set_text(text)
    cursor = editor.textCursor()
    cursor.movePosition(QTextCursor.End)
    editor.setTextCursor(cursor)
    return editor
Beispiel #3
0
def get_indent_fix(text, indent_chars=" " * 4):
    app = qapplication()
    editor = CodeEditor(parent=None)
    editor.setup_editor(language='Python', indent_chars=indent_chars)

    editor.set_text(text)
    cursor = editor.textCursor()
    cursor.movePosition(QTextCursor.End)
    editor.setTextCursor(cursor)
    editor.fix_indent()
    return to_text_string(editor.toPlainText())
Beispiel #4
0
def get_indent_fix(text):
    app = qapplication()
    editor = CodeEditor(parent=None)
    editor.setup_editor(language='Python')

    editor.set_text(text)
    cursor = editor.textCursor()
    cursor.movePosition(QTextCursor.End)
    editor.setTextCursor(cursor)
    editor.fix_indent()
    return to_text_string(editor.toPlainText())
Beispiel #5
0
def outline_explorer_bot2(qtbot):
    editor = CodeEditor()
    editor = CodeEditor(None)
    editor.set_language('py', 'test_file.py')
    editor.set_text(dedent(code))

    outline_explorer = OutlineExplorerWidget()
    outline_explorer.set_current_editor(editor, 'test_file.py', False, False)

    qtbot.addWidget(outline_explorer)

    return outline_explorer, qtbot
Beispiel #6
0
def outline_explorer_bot(qtbot):
    editor = CodeEditor()
    editor = CodeEditor(None)
    editor.set_language('py', 'test_outline_explorer.py')
    editor.set_text(text)

    outline_explorer = OutlineExplorerWidget()
    outline_explorer.set_current_editor(
            editor, 'test_outline_explorer.py', False, False)

    qtbot.addWidget(outline_explorer)

    return outline_explorer, qtbot
def construct_editor(*args, **kwargs):
    """Construct editor with some text for testing extra selections."""
    app = qapplication()
    editor = CodeEditor(parent=None)
    kwargs['language'] = 'Python'
    editor.setup_editor(*args, **kwargs)

    text = ("def some_function():\n"
            "    some_variable = 1\n"
            "    some_variable += 2\n"
            "    return some_variable\n"
            "# %%")
    editor.set_text(text)
    return editor
def get_indent_fix(text, indent_chars=" " * 4, tab_stop_width_spaces=4,
                   sol=False, forward=True, language='Python'):
    """Return text with last line's indentation fixed."""
    app = qapplication()
    editor = CodeEditor(parent=None)
    editor.setup_editor(language=language, indent_chars=indent_chars,
                        tab_stop_width_spaces=tab_stop_width_spaces)

    editor.set_text(text)
    cursor = editor.textCursor()
    cursor.movePosition(QTextCursor.End)
    if sol:
        lines = text.splitlines(True)
        repeat = len(lines[-1].lstrip())
        cursor.movePosition(QTextCursor.Left, n=repeat)
    editor.setTextCursor(cursor)
    editor.fix_indent(forward=forward)
    return to_text_string(editor.toPlainText())
Beispiel #9
0
def construct_editor(*args, **kwargs):
    app = qapplication()
    editor = CodeEditor(parent=None)
    kwargs['language'] = 'Python'
    editor.setup_editor(*args, **kwargs)

    text = ("def some_function():\n"
            "    \n"  # W293 trailing spaces
            "    a = 1 # a comment\n"  # E261 two spaces before inline comment
            "\n"
            "    a += s\n"  # Undefined variable s
            "    return a\n"
            )
    editor.set_text(text)
    source_code = to_binary_string(editor.toPlainText())
    results = check_with_pyflakes(source_code) + check_with_pep8(source_code)
    editor.process_code_analysis(results)

    return editor
Beispiel #10
0
def construct_editor(*args, **kwargs):
    app = qapplication()
    editor = CodeEditor(parent=None)
    kwargs['language'] = 'Python'
    editor.setup_editor(*args, **kwargs)

    text = (
        "def some_function():\n"
        "    \n"  # W293 trailing spaces
        "    a = 1 # a comment\n"  # E261 two spaces before inline comment
        "\n"
        "    a += s\n"  # Undefined variable s
        "    return a\n")
    editor.set_text(text)
    source_code = to_binary_string(editor.toPlainText())
    results = check_with_pyflakes(source_code) + check_with_pep8(source_code)
    editor.process_code_analysis(results)

    return editor
Beispiel #11
0
def get_fold_levels():
    """setup editor and return fold levels."""
    app = qapplication()
    editor = CodeEditor(parent=None)
    editor.setup_editor(language='Python')

    text = (
        '# dummy test file\n'
        'class a():\n'  # fold-block level-0
        '    self.b = 1\n'
        '    print(self.b)\n'
        '    \n'
        '    def some_method(self):\n'  # fold-block level-1
        '        self.b = 3\n'
        '\n'
        '    def other_method(self):\n'  # fold-block level-1
        '         a = (1,\n'  # fold-block level-2
        '              2,\n'
        '              3)\n')

    editor.set_text(text)
    return print_tree(editor, return_list=True)
Beispiel #12
0
def get_fold_levels():
    """setup editor and return fold levels."""
    app = qapplication()
    editor = CodeEditor(parent=None)
    editor.setup_editor(language='Python')

    text = ('# dummy test file\n'
            'class a():\n'  # fold-block level-0
            '    self.b = 1\n'
            '    print(self.b)\n'
            '    \n'
            '    def some_method(self):\n'  # fold-block level-1
            '        self.b = 3\n'
            '\n'
            '    def other_method(self):\n'  # fold-block level-1
            '\n' # a blank line (should be ignored)
            '  # a comment with arbitrary indentation\n' # should be ignored
            '         a = (1,\n'  # fold-block level-2
            '              2,\n'
            '              3)\n'
            )

    editor.set_text(text)
    return print_tree(editor, return_list=True)
Beispiel #13
0
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