Exemplo n.º 1
0
    def get_doctree(self,
                    *,
                    docname: Optional[str] = None,
                    uri: Optional[str] = None) -> Optional[Any]:
        """Return the initial doctree corresponding to the specified document.

        The ``docname`` of a document is its path relative to the project's ``srcdir``
        minus the extension e.g. the docname of the file ``docs/lsp/features.rst``
        would be ``lsp/features``.

        Parameters
        ----------
        docname:
           Returns the doctree that corresponds with the given docname
        uri:
           Returns the doctree that corresponds with the given uri.
        """

        if self.app is None or self.app.env is None or self.app.builder is None:
            return None

        if uri is not None:
            fspath = Uri.to_fs_path(uri)
            docname = self.app.env.path2doc(fspath)

        if docname is None:
            return None

        try:
            return self.app.env.get_and_resolve_doctree(
                docname, self.app.builder)
        except FileNotFoundError:
            self.logger.debug("Could not find doctree for '%s'", docname)
            # self.logger.debug(traceback.format_exc())
            return None
Exemplo n.º 2
0
    def get_location_type(self, doc: Document, position: Position) -> str:
        """Given a document and a position, return the kind of location that
        represents.

        This will return one of the following values:

        - ``rst``: Indicates that the position is within an ``*.rst`` document
        - ``py``: Indicates that the position is within code in a ``*.py`` document
        - ``docstring``: Indicates that the position is within a docstring in a
          ``*.py`` document.

        Parameters
        ----------
        doc:
           The document associated with the given position
        position:
           The position to determine the type of.
        """
        ext = pathlib.Path(Uri.to_fs_path(doc.uri)).suffix

        if ext == ".rst":
            return "rst"

        if ext == ".py":

            # Let's count how many pairs of triple quotes are "above" us in the file
            # even => we're outside a docstring
            # odd  => we're within a docstring
            source = self.text_to_position(doc, position)
            count = len(TRIPLE_QUOTE.findall(source))
            return "py" if count % 2 == 0 else "docstring"

        # Fallback to rst
        self.logger.debug("Unable to determine location type for uri: %s", doc.uri)
        return "rst"
Exemplo n.º 3
0
    def save(self, params: DidSaveTextDocumentParams):
        super().save(params)

        filepath = Uri.to_fs_path(params.text_document.uri)
        if filepath.endswith("conf.py"):
            if self.app:
                conf_dir = pathlib.Path(self.app.confdir)
            else:
                # The user's config is currently broken... where should their conf.py be?
                if self.user_config is not None:
                    config = typing.cast(InitializationOptions,
                                         self.user_config).sphinx
                else:
                    config = SphinxConfig()

                conf_dir = config.resolve_conf_dir(
                    self.workspace.root_uri) or pathlib.Path(".")

            if str(conf_dir / "conf.py") == filepath:
                self.clear_diagnostics("conf.py")
                self.sync_diagnostics()
                self.app = self._initialize_sphinx()

        else:
            self.clear_diagnostics("sphinx", params.text_document.uri)

        self.build()
Exemplo n.º 4
0
async def workspace_symbols(ls, params: WorkspaceSymbolParams):
    # query = params.query
    # if database.declarations == []:
    #     return None
    path = to_fs_path(
        "file:///c%3A/Users/eirik/Desktop/VSCode-SystemVerilog/verilog-examples/driver.sv"
    )
    return parse_workspace_symbols(path)
Exemplo n.º 5
0
def normalise_uri(uri: str) -> str:

    uri = Uri.from_fs_path(Uri.to_fs_path(uri))

    # Paths on windows are case insensitive.
    if IS_WIN:
        uri = uri.lower()

    return uri
Exemplo n.º 6
0
    def syntax_check(self, file: str):
        if file is not None:
            f = uris.to_fs_path(file)
            self.syntaxchecker.run_incremental([f])
        else:
            self.syntaxchecker.run()

        for file, diaglist in self.syntaxchecker.diagnostic_content.items():
            self.publish_diagnostics(file, diaglist)
Exemplo n.º 7
0
    def resolve_doctree_dir(self, root_uri: str, actual_conf_dir: str,
                            actual_build_dir: str) -> pathlib.Path:
        """Get the directory to use for doctrees based on the user's config.

        If ``doctree_dir`` is not set, this method will follow what ``sphinx-build``
        does.

        - If ``make_mode`` is true, this will be set to ``${buildDir}/doctrees``
        - If ``make_mode`` is false, this will be set to ``${buildDir}/.doctrees``

        Otherwise, if ``doctree_dir`` is set the following "variables" are handled by
        this method.

        - ``${workspaceRoot}`` which expands to the workspace root as provided by the
          language client.

        - ``${workspaceFolder}`` alias for ``${workspaceRoot}``, placeholder ready for
          multi-root support.

        - ``${confDir}`` which expands to the configured config dir.

        - ``${buildDir}`` which expands to the configured build dir.

        Parameters
        ----------
        root_uri
           The workspace root uri

        actual_conf_dir
           The fully resolved conf dir for the project

        actual_build_dir
           The fully resolved build dir for the project.
        """

        if self.doctree_dir is None:
            if self.make_mode:
                return pathlib.Path(actual_build_dir, "doctrees")

            return pathlib.Path(actual_build_dir, ".doctrees")

        root_dir = Uri.to_fs_path(root_uri)
        match = PATH_VAR_PATTERN.match(self.doctree_dir)

        if match and match.group(1) in {"workspaceRoot", "workspaceFolder"}:
            build = pathlib.Path(self.doctree_dir).parts[1:]
            return pathlib.Path(root_dir, *build).resolve()

        if match and match.group(1) == "confDir":
            build = pathlib.Path(self.doctree_dir).parts[1:]
            return pathlib.Path(actual_conf_dir, *build).resolve()

        if match and match.group(1) == "buildDir":
            build = pathlib.Path(self.doctree_dir).parts[1:]
            return pathlib.Path(actual_build_dir, *build).resolve()

        return pathlib.Path(self.doctree_dir).expanduser()
Exemplo n.º 8
0
def _get_workspace_folder_path(ls: LanguageServer, uri: str) -> str:
    # find workspace folder uri belongs to
    folders = sorted(
        (f.uri
         for f in ls.workspace.folders.values() if uri.startswith(f.uri)),
        key=len,
        reverse=True)
    if folders:
        return to_fs_path(folders[0])
    return ls.workspace.root_path
Exemplo n.º 9
0
    def __init__(self, root_uri, sync_kind=None, workspace_folders=None):
        self._root_uri = root_uri
        self._root_uri_scheme = uri_scheme(self._root_uri)
        self._root_path = to_fs_path(self._root_uri)
        self._sync_kind = sync_kind
        self._folders = {}
        self._docs = {}

        if workspace_folders is not None:
            for folder in workspace_folders:
                self.add_folder(folder)
Exemplo n.º 10
0
    def __init__(self, uri, source=None, version=None, local=True,
                 sync_kind=TextDocumentSyncKind.INCREMENTAL):
        self.uri = uri
        self.version = version
        self.path = to_fs_path(uri)
        self.filename = os.path.basename(self.path)

        self._local = local
        self._source = source

        self._is_sync_kind_full = sync_kind == TextDocumentSyncKind.FULL
        self._is_sync_kind_incremental = sync_kind == TextDocumentSyncKind.INCREMENTAL
        self._is_sync_kind_none = sync_kind == TextDocumentSyncKind.NONE
Exemplo n.º 11
0
    def complete_arguments(self, context: CompletionContext, domain: str,
                           name: str) -> List[CompletionItem]:

        if domain or name not in {"include", "literalinclude"}:
            return []

        if not self.rst.app:
            return []

        srcdir = self.rst.app.srcdir
        partial = context.match.group("argument")
        base = os.path.dirname(Uri.to_fs_path(context.doc.uri))
        items = complete_sphinx_filepaths(srcdir, base, partial)

        return [path_to_completion_item(context, p) for p in items]
Exemplo n.º 12
0
    def complete_targets(
        self, context: CompletionContext, name: str, domain: Optional[str]
    ) -> List[CompletionItem]:

        if domain or name != "download":
            return []

        if not self.rst.app:
            return []

        srcdir = self.rst.app.srcdir
        partial = context.match.group("label")
        base = os.path.dirname(Uri.to_fs_path(context.doc.uri))
        items = complete_sphinx_filepaths(srcdir, base, partial)

        return [path_to_completion_item(context, p) for p in items]
Exemplo n.º 13
0
    def resolve_doc(self, doc: Document, label: str) -> Optional[str]:

        if self.rst.app is None:
            return None

        srcdir = self.rst.app.srcdir
        currentdir = pathlib.Path(Uri.to_fs_path(doc.uri)).parent

        if label.startswith("/"):
            path = pathlib.Path(srcdir, label[1:] + ".rst")
        else:
            path = pathlib.Path(currentdir, label + ".rst")

        if not path.exists():
            return None

        return Uri.from_fs_path(str(path))
Exemplo n.º 14
0
    def resolve_conf_dir(self, root_uri: str) -> Optional[pathlib.Path]:
        """Get the conf dir to use based on the user's config.

        If ``conf_dir`` is not set, this method will attempt to find it by searching
        within the ``root_uri`` for a ``conf.py`` file. If multiple files are found, the
        first one found will be chosen.

        If ``conf_dir`` is set the following "variables" are handled by this method

        - ``${workspaceRoot}`` which expands to the workspace root as provided by the
          language client.

        - ``${workspaceFolder}`` alias for ``${workspaceRoot}``, placeholder ready for
          multi-root support.

        Parameters
        ----------
        root_uri
            The workspace root uri
        """
        root = Uri.to_fs_path(root_uri)

        if not self.conf_dir:
            ignore_paths = [".tox", "site-packages"]

            for candidate in pathlib.Path(root).glob("**/conf.py"):
                # Skip any files that obviously aren't part of the project
                if any(path in str(candidate) for path in ignore_paths):
                    continue

                return candidate.parent

            # Nothing found
            return None

        match = PATH_VAR_PATTERN.match(self.conf_dir)
        if not match or match.group(1) not in {
                "workspaceRoot", "workspaceFolder"
        }:
            return pathlib.Path(self.conf_dir).expanduser()

        conf = pathlib.Path(self.conf_dir).parts[1:]
        return pathlib.Path(root, *conf).resolve()
Exemplo n.º 15
0
    def resolve_src_dir(self, root_uri: str,
                        actual_conf_dir: str) -> pathlib.Path:
        """Get the src dir to use based on the user's config.

        By default the src dir will be the same as the conf dir, but this can
        be overriden by setting the ``src_dir`` field.

        There are a number of "variables" that can be included in the path,
        currently we support

        - ``${workspaceRoot}`` which expands to the workspace root as provided
          by the language client.

        - ``${workspaceFolder}`` alias for ``${workspaceRoot}``, placeholder ready for
          multi-root support.

        - ``${confDir}`` which expands to the configured config dir.

        Parameters
        ----------
        root_uri
           The workspace root uri

        actual_conf_dir
           The fully resolved conf dir for the project
        """

        if not self.src_dir:
            return pathlib.Path(actual_conf_dir)

        src_dir = self.src_dir
        root_dir = Uri.to_fs_path(root_uri)

        match = PATH_VAR_PATTERN.match(src_dir)
        if match and match.group(1) in {"workspaceRoot", "workspaceFolder"}:
            src = pathlib.Path(src_dir).parts[1:]
            return pathlib.Path(root_dir, *src).resolve()

        if match and match.group(1) == "confDir":
            src = pathlib.Path(src_dir).parts[1:]
            return pathlib.Path(actual_conf_dir, *src).resolve()

        return pathlib.Path(src_dir).expanduser()
Exemplo n.º 16
0
    def __init__(
        self,
        uri,
        project_root,
        language_name,
        project_name,
        mm_loader,
        source=None,
        version=None,
    ):
        super().__init__(uri, source, version, True)

        self.project_root = to_fs_path(project_root)
        self.project_name = project_name
        self.language_name = language_name
        self.mm_loader = mm_loader

        self._metamodel = None
        self.refresh_metamodel()
Exemplo n.º 17
0
    def resolve_path(self, doc: Document, argument: str) -> Optional[str]:

        if argument.startswith("/"):
            if not self.rst.app:
                return None

            basedir = pathlib.Path(self.rst.app.srcdir)

            # Remove the leading '/' otherwise is will wipe out the basedir when
            # concatenated
            argument = argument[1:]

        else:
            basedir = pathlib.Path(Uri.to_fs_path(doc.uri)).parent

        fpath = (basedir / argument).resolve()
        if not fpath.exists():
            return None

        return Uri.from_fs_path(str(fpath))
Exemplo n.º 18
0
def _mypy_check(ls: LanguageServer, uri: str, script: Script,
                result: List[types.Diagnostic]):
    from mypy import api
    assert jediEnvironment is not None
    version_info = jediEnvironment.version_info
    if config['diagnostic_on_change']:
        args = ['--command', script._code]
    else:
        args = [to_fs_path(uri)]
    lines = api.run([
        '--python-executable', jediEnvironment.executable, '--python-version',
        f'{version_info.major}.{version_info.minor}', '--config-file',
        get_mypy_config(ls,
                        uri), '--hide-error-context', '--show-column-numbers',
        '--show-error-codes', '--no-pretty', '--no-error-summary'
    ] + args)
    if lines[1]:
        ls.show_message(lines[1], types.MessageType.Error)
        return

    for line in lines[0].split('\n'):
        parts = line.split(':', 4)
        if len(parts) < 5:
            continue
        _fn, row, column, err_type, message = parts
        row = int(row) - 1
        column = int(column) - 1
        if err_type.strip() == 'note':
            severity = types.DiagnosticSeverity.Hint
        else:
            severity = types.DiagnosticSeverity.Warning
        result.append(
            types.Diagnostic(range=types.Range(
                start=types.Position(line=row, character=column),
                end=types.Position(line=row,
                                   character=len(script._code_lines[row]))),
                             message=message.strip(),
                             severity=severity,
                             source='mypy'))
    return result
Exemplo n.º 19
0
    def get_initial_doctree(self, uri: str) -> Optional[Any]:
        """Return the initial doctree corresponding to the specified document.

        An "initial" doctree can be thought of as the abstract syntax tree of a
        reStructuredText document. This method disables all role and directives
        from being executed, instead they are replaced with nodes that simply
        represent that they exist.

        Parameters
        ----------
        uri
           Returns the doctree that corresponds with the given uri.
        """
        filename = pathlib.Path(Uri.to_fs_path(uri))
        try:
            return read_initial_doctree(filename, self.logger)
        except FileNotFoundError:
            self.logger.debug(traceback.format_exc())
            return None
        except Exception:
            self.logger.error(traceback.format_exc())
            return None
Exemplo n.º 20
0
    def compile(self, uri, istr) -> bool:
        if self.uri == uri and istr == self.last_compiled_source:
            return self.last_status

        self.last_compiled_source = istr
        fspath = to_fs_path(uri)
        e = self._docompile(fspath, istr)
        self.uri = uri
        self.changed = False
        if not e:
            self.last_status = True
            self.last_successful_source[uri] = istr
            server.publish_diagnostics(uri, [])
            return True
        else:
            self.last_status = False
            if not birdeec.get_auto_completion_ast():
                diag = Diagnostic(
                    Range(Position(e.linenumber, e.pos + 1),
                          Position(e.linenumber, e.pos + 2)), e.msg)
                server.publish_diagnostics(uri, [diag])
            return False
Exemplo n.º 21
0
    def resolve_build_dir(self, root_uri: str,
                          actual_conf_dir: str) -> pathlib.Path:
        """Get the build dir to use based on the user's config.

        If nothing is specified in the given ``config``, this will choose a location
        within the user's cache dir (as determined by
        `appdirs <https://pypi.org/project/appdirs>`). The directory name will be a hash
        derived from the given ``conf_dir`` for the project.

        Alternatively the user (or least language client) can override this by setting
        either an absolute path, or a path based on the following "variables".

        - ``${workspaceRoot}`` which expands to the workspace root as provided
          by the language client.

        - ``${workspaceFolder}`` alias for ``${workspaceRoot}``, placeholder ready for
          multi-root support.

        - ``${confDir}`` which expands to the configured config dir.

        Parameters
        ----------
        root_uri
           The workspace root uri

        actual_conf_dir:
           The fully resolved conf dir for the project
        """

        if not self.build_dir:
            # Try to pick a sensible dir based on the project's location
            cache = appdirs.user_cache_dir("esbonio", "swyddfa")
            project = hashlib.md5(str(actual_conf_dir).encode()).hexdigest()

            return pathlib.Path(cache) / project

        root_dir = Uri.to_fs_path(root_uri)
        match = PATH_VAR_PATTERN.match(self.build_dir)

        if match and match.group(1) in {"workspaceRoot", "workspaceFolder"}:
            build = pathlib.Path(self.build_dir).parts[1:]
            return pathlib.Path(root_dir, *build).resolve()

        if match and match.group(1) == "confDir":
            build = pathlib.Path(self.build_dir).parts[1:]
            return pathlib.Path(actual_conf_dir, *build).resolve()

        # Convert path to/from uri so that any path quirks from windows are
        # automatically handled
        build_uri = Uri.from_fs_path(self.build_dir)
        build_dir = Uri.to_fs_path(build_uri)

        # But make sure paths starting with '~' are not corrupted
        if build_dir.startswith("/~"):
            build_dir = build_dir.replace("/~", "~")

        # But make sure (windows) paths starting with '~' are not corrupted
        if build_dir.startswith("\\~"):
            build_dir = build_dir.replace("\\~", "~")

        return pathlib.Path(build_dir).expanduser()
Exemplo n.º 22
0
def test_win_to_fs_path(uri, path):
    assert uris.to_fs_path(uri) == path