[Design] Handling untitled files #12336
Replies: 2 comments 5 replies
-
Thanks for writing this up! It would help my understanding to have a bit of higher-level discussion of what behavior we want to present around untitled files, which might influence how we want to represent them internally. (Maybe some assumptions are made about the behavior we want, which aren't clear to me.) For example, here is one possible set of behaviors:
The second point makes the implicit assumption that we always know which project an untitled file is part of. Do we? Does LSP provide enough information for us to know this, given that our usual methods would rely on locating the file in a tree relative to configs and package directories? If not, I'm not sure how we can resolve any imports (other than perhaps stdlib ones, with some guess at a Python version) from an untitled file. The third point is also debatable. It would also be possible to try to use some heuristic to decide where in the project structure we think the untitled file might belong, which would allow us to guess at a resolution for relative imports. I'm not sure if we want to do this or not. (How does pyright handle relative imports in untitled files?) |
Beta Was this translation helpful? Give feedback.
-
Thanks for writing this proposal. Is this proposal specifically to handle the "untitled" scheme i.e., non-existant file in an editor? Or, is this more so for any non-"file" scheme document? My main motivation for this question is that the "untitled" scheme is specific to VS Code but other editors could provide a different scheme for either non-existant files or any other unknown files. Another motivation is the following comment from one of the linked reference:
I'm assuming it's the later based on this:
I think this might be as a follow-up but we also need to think about untitled notebooks but they probably need to be handled in a similar, if not the same, way as untitled files. I might have a question or two regarding the implementation when I'm working on it but going through the existing types based on your implementation proposal, it looks good to me. |
Beta Was this translation helpful? Give feedback.
-
This is a proposal for the design changes needed to support untitled (technically, any non-
file://
) files.Background
LSP specification
The LSP specifies that a document is identified by a
URI
. Technically, the URI can use any schema, although the only two used by VS code today are:file://
: For files stored on disk (there are no guarantees that the file hasn't been deleted after opening it). This convention is explained in theDocumentFilter
example.untitled://
: This seems VS Code specific, but other editors (e.g. neovim) might adopt it too. VS Code uses this schema for untitled documents.There's an open issue to standardize a
buffer://
schema.Resources
Existing Red Knot concepts
The following Red Knot concepts are relevant for this design proposal:
System
is an abstraction of the environment in which Red Knot runs. It exposes methods to read files and directories, get the current working directory, and more. The LSP, CLI, and tests have customSystem
implementations. Most methods have aSystemPath
(a thin wrapper aroundPath
) argument.File
: A file that Red Knot supports. It stores metadata about the file and its path. TheFilePath
is either aSystemPath
(seeSystem
) or aVendoredPath
.VendoredPath
: A path to a file that is vendored with Ruff (included in Ruff's binary).Proposal
My key insights from the LSP specification are:
file
schema.untitled
is the only other specified schema.Ruff/Red Knot wants special handling for file-paths because module resolution, configuration discovery etc. is only possible for files stored on disk.
I propose that we extend
FilePath
with a newFilePath::SystemVirtual
(stores aSystemVirtualPathBuf
) variant that is an opaque wrapper aroundString
(or&str
). Other thanSystemPath
, this path will not expose any query or mutation methods likeparent()
,ancestors
,join
, etc. Handling all nonfile
schema as an opaque string means we can easily support more schemas in the future.The two main downsides of this approach that I see are:
read_virtual_path_to_string
,read_virtual_path_to_notebook
, andvirtual_path_metadata
methods toSystem
that match theirSystemPath
counterpart. I considered introducing a newAnySystemPath
enum that's either aSystemPath
orVirtualSystemPath,
, but I prefer different method names because not all methods will have virtual counterparts (e.g., `walk_directory).Required changes
I quickly added a new variant. Most changes look trivial. The only exception is that the module resolver uses
FilePath
in places where it only supportsSystemPath
andVendoredPath
. The solution here is easy, introduce a new module-resolverFilePath
enum that only supports these two variants.Alternatives
Make
SystemPath
an enumInstead of adding a new variant to
FilePath
, changeSystemPath
to an enum with two variants. I prefer extendingFilePath
instead because:SystemPath
an enum means we can no longer implementAsRef
onSystemPathBuf
, which complicates the implementation a lot.join
,parent
,ancestors
, etc., for virtual paths are unclear. It shouldn't matter because we should never call these functions on a virtual path, but I would rather have this statically enforced.System
, but it does have the disadvantage that allSystem
methods accept virtual paths, even if these operations aren't supported.Beta Was this translation helpful? Give feedback.
All reactions