diff --git a/pylsp_rope/plugin.py b/pylsp_rope/plugin.py index 7278952..c966390 100644 --- a/pylsp_rope/plugin.py +++ b/pylsp_rope/plugin.py @@ -13,6 +13,7 @@ get_resources, rope_changeset_to_workspace_edit, new_project, + is_virtual_document, ) @@ -68,6 +69,11 @@ def pylsp_code_actions( ) -> List[typing.CodeAction]: logger.info("textDocument/codeAction: %s %s %s", document, range, context) + # Skip virtual documents (e.g., notebook cells) + if is_virtual_document(document.uri): + logger.debug("Skipping code actions for virtual document: %s", document.uri) + return [] + class info: current_document, resource = get_resource(workspace, document.uri) position = range["start"] @@ -185,7 +191,9 @@ def pylsp_rename( return None logger.info("textDocument/rename: %s %s %s", document, position, new_name) - project = new_project(workspace) # FIXME: we shouldn't have to always keep creating new projects here + project = new_project( + workspace + ) # FIXME: we shouldn't have to always keep creating new projects here document, resource = get_resource(workspace, document.uri, project=project) rename = Rename( diff --git a/pylsp_rope/project.py b/pylsp_rope/project.py index 087584a..17de33b 100644 --- a/pylsp_rope/project.py +++ b/pylsp_rope/project.py @@ -23,6 +23,22 @@ logger = logging.getLogger(__name__) +def is_virtual_document(document_uri: DocumentUri) -> bool: + """ + Check if a document URI represents a virtual document (e.g., notebook cell). + + Virtual documents have URI schemes other than 'file' (including empty schemes) + and don't correspond to actual files on the filesystem. + """ + try: + parsed_uri = uris.urlparse(document_uri) + scheme = parsed_uri[0] if len(parsed_uri) > 0 else "" + return scheme != "file" + except Exception: + # If we can't parse URI, treat it as virtual for safety + return True + + @lru_cache(maxsize=None) def get_project(workspace) -> rope.Project: """Get a cached rope Project or create one if it doesn't exist yet""" @@ -43,20 +59,29 @@ def get_resource( document_uri: DocumentUri, *, project: rope.Project = None, -) -> Tuple[workspace.Document, rope.Resource]: +) -> Tuple[workspace.Document, Optional[rope.Resource]]: """ Return a Document and Resource related to an LSP Document. `project` must be provided if not using instances of rope Project from `pylsp_rope.project.get_project()`. + + Returns None as resource if the document is virtual (e.g., notebook cell). """ document = workspace.get_document(document_uri) + + # Handle virtual documents (e.g., notebook cells) + if is_virtual_document(document_uri): + return document, None + project = project or get_project(workspace) resource = libutils.path_to_resource(project, document.path) return document, resource -def get_resources(workspace, documents: List[DocumentUri]) -> List[rope.Resource]: +def get_resources( + workspace, documents: List[DocumentUri] +) -> List[Optional[rope.Resource]]: if documents is None: return None return [get_resource(workspace, document_uri)[1] for document_uri in documents]