def lsp_renames(self) -> Iterator[RenameFile]: """Get all File rename operations.""" for old_name, new_name in self.refactoring.get_renames(): yield RenameFile( old_uri=from_fs_path(old_name), new_uri=from_fs_path(new_name), options=RenameFileOptions( ignore_if_exists=True, overwrite=True ), )
def get_location(self, location: str) -> Tuple[str, Optional[int]]: if not location: conf = pathlib.Path(self.app.confdir, "conf.py") return (str(conf), None) path, *parts = location.split(":") lineno = None # On windows the rest of the path will be the first element of parts if IS_WIN: path += f":{parts.pop(0)}" if len(parts) == 1: try: lineno = int(parts[0]) except ValueError: pass if len(parts) == 2: # TODO: There's a possibility that there is an error in a docstring in a # *.py file somewhere. In which case parts would look like # ['docstring of {dotted.name}', '{lineno}'] # # e.g. ['docstring of esbonio.lsp.sphinx.SphinxLanguageServer.get_domains', '8'] # # It would be good to handle this case and look up the correct line # number to place a diagnostic. pass return (Uri.from_fs_path(path), lineno)
def exception_to_diagnostic(exc: BaseException): """Convert an exception into a diagnostic we can send to the client.""" # Config errors sometimes wrap the true cause of the problem if isinstance(exc, ConfigError) and exc.__cause__ is not None: exc = exc.__cause__ if isinstance(exc, SyntaxError): path = pathlib.Path(exc.filename or "") line = (exc.lineno or 1) - 1 else: tb = exc.__traceback__ frame = traceback.extract_tb(tb)[-1] path = pathlib.Path(frame.filename) line = (frame.lineno or 1) - 1 message = type(exc).__name__ if exc.args.count == 0 else exc.args[0] diagnostic = Diagnostic( range=Range( start=Position(line=line, character=0), end=Position(line=line + 1, character=0), ), message=message, severity=DiagnosticSeverity.Error, ) return Uri.from_fs_path(str(path)), diagnostic
def lsp_initialize(self, params: InitializeParams) -> InitializeResult: """Method that initializes language server. It will compute and return server capabilities based on registered features. """ logger.info('Language server initialized %s', params) self._server.process_id = params.process_id # Initialize server capabilities self.client_capabilities = params.capabilities self.server_capabilities = ServerCapabilitiesBuilder( self.client_capabilities, {**self.fm.features, **self.fm.builtin_features}.keys(), self.fm.feature_options, list(self.fm.commands.keys()), self._server.sync_kind, ).build() logger.debug('Server capabilities: %s', self.server_capabilities.dict()) root_path = params.root_path root_uri = params.root_uri or from_fs_path(root_path) # Initialize the workspace workspace_folders = params.workspace_folders or [] self.workspace = Workspace(root_uri, self._server.sync_kind, workspace_folders) self.trace = Trace.Off return InitializeResult(capabilities=self.server_capabilities)
def ref_definition(self, label: str) -> List[Location]: """Goto definition implementation for ``:ref:`` targets""" if not self.rst.app or not self.rst.app.env: return [] types = set(self.rst.get_role_target_types("ref")) std = self.rst.get_domain("std") if std is None: return [] docname = self.find_docname_for_label(label, std, types) if docname is None: return [] path = self.rst.app.env.doc2path(docname) uri = Uri.from_fs_path(path) doctree = self.rst.get_initial_doctree(uri) if doctree is None: return [] uri = None line = None for node in doctree.traverse(condition=nodes.target): if "refid" not in node: continue if doctree.nameids.get(label, "") == node["refid"]: uri = Uri.from_fs_path(node.source) line = node.line break if uri is None or line is None: return [] return [ Location( uri=uri, range=Range( start=Position(line=line - 1, character=0), end=Position(line=line, character=0), ), ) ]
def _get_locations(defs: List[Name]) -> List[types.Location]: return [ types.Location( from_fs_path(d.module_path), types.Range(types.Position(d.line - 1, d.column), types.Position(d.line - 1, d.column + len(d.name)))) for d in defs if d.module_path ]
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
def lsp_text_document_edits(self) -> Iterator[TextDocumentEdit]: """Get all text document edits.""" changed_files = self.refactoring.get_changed_files() for path, changed_file in changed_files.items(): uri = from_fs_path(path) text_edits = lsp_text_edits(changed_file) yield TextDocumentEdit( text_document=VersionedTextDocumentIdentifier( uri=uri, version=None, # type: ignore ), edits=text_edits, )
def _get_document_changes( ls: LanguageServer, refactoring: Refactoring) -> List[types.TextDocumentEdit]: result = [] for fn, changes in refactoring.get_changed_files().items(): text_edits = _get_text_edits(changes) if text_edits: uri = from_fs_path(fn) result.append( types.TextDocumentEdit( types.VersionedTextDocumentIdentifier( uri, ls.workspace.get_document(uri).version), text_edits)) return result
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))
def read_error_file(self, path: str): with open(path, "r") as jsfile: data = json.load(jsfile) for file, content in data.items(): uri = from_fs_path(file) for severity_label, record_list in content.items(): severity = DiagnosticSeverity.Error # To change if we have something else than error for r in record_list: position = Position(line=r["line"], character=r["column"]) diagnostic = Diagnostic( range=Range(start=position, end=position), message="Parse error : rejected token. ", source="Verible Syntax", code="syntax-error", severity=severity) logger.info(f"Register error {uri}:{r['line']}") self._register_diagnostic(uri, diagnostic)
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))
def get_references(doc: Dict[str, str], symbol: str) -> List[Location]: """Given a representation of a document and a symbol string, return the Location of every use of that symbol within the document.""" current_line = 0 output = [] symbol_len = len(symbol) uri = from_fs_path(doc["path"]) for line in doc["source"].split("\n"): for index in [ i for i in range(len(line)) if line.startswith(symbol, i) ]: output.append( Location( uri=uri, range=Range( start=Position(line=current_line, character=index), end=Position(line=current_line, character=index + symbol_len), ), )) current_line += 1 return output
def sourcepos2position(pos: birdeec.SourcePos, main_src_uri: str) -> (Position, str): if not pos: return None uri = from_fs_path( pos.source_path) if pos.source_idx != -1 else main_src_uri return (Position(pos.line - 1, pos.pos - 1), uri)
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()
def test_get_missing_document(tmpdir, workspace): doc_path = tmpdir.join("test_document.py") doc_path.write(DOC_TEXT) doc_uri = uris.from_fs_path(str(doc_path)) assert workspace.get_document(doc_uri).source == DOC_TEXT
def lsp_location(name: Name) -> Location: """Get LSP location from Jedi definition.""" return Location(uri=from_fs_path(name.module_path), range=lsp_range(name))
def workspace(tmpdir): """Return a workspace.""" return Workspace(uris.from_fs_path(str(tmpdir)), Mock())
# # # 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. # ############################################################################ import os from pygls import uris from pygls.types import TextDocumentItem, WorkspaceFolder from pygls.workspace import Workspace DOC_URI = uris.from_fs_path(__file__) DOC_TEXT = '''test''' DOC = TextDocumentItem(DOC_URI, 'plaintext', 0, DOC_TEXT) def test_add_folder(workspace): dir_uri = os.path.dirname(DOC_URI) dir_name = 'test' workspace.add_folder(WorkspaceFolder(dir_uri, dir_name)) assert workspace.folders[dir_uri].name == dir_name def test_get_document(workspace): workspace.put_document(DOC) assert workspace.get_document(DOC_URI).source == DOC_TEXT
def initialize_server(server): server.lsp.bf_initialize( InitializeParams(process_id=1234, capabilities=ClientCapabilities(), root_uri=from_fs_path(WORKSPACE_PATH)))
def run_incremental(self, files: T.Optional[T.List[str]] = None): for f in files: if f not in self.filelist: self.filelist.append(f) self.clear_file(from_fs_path(f)) self._run(incr=True, force_fset=files)
def path(self,val): self._path = uris.from_fs_path(os.path.abspath(os.path.join(self.root_path,val)))
def _(*args, **kwargs): ... @client.feature("esbonio/buildComplete") def _(*args, **kwargs): ... return client @pytest_lsp.fixture( scope="session", config=[ ClientServerConfig( client="visual_studio_code", client_factory=make_esbonio_client, server_command=[sys.executable, "-m", "esbonio"], root_uri=uri.from_fs_path(str(root_path)), ), ClientServerConfig( client="neovim", client_factory=make_esbonio_client, server_command=[sys.executable, "-m", "esbonio"], root_uri=uri.from_fs_path(str(root_path)), ), ], ) async def client(client_: Client): # Wait for the server to initialize. await client_.wait_for_notification("esbonio/buildComplete")
def test_win_from_fs_path(path, uri): assert uris.from_fs_path(path) == uri