Foundations for Open All the Things (#9353)

This is the beginning of setting up a flexible way to open items beyond
the text buffer -- think notebooks, images, GeoJSON, etc. The primary
requirement to allow opening an arbitrary file is `try_open` on the
`project::Item` trait. Now we can make new `Item`s for other types with
their own ways to render.

Under the hood, `register_project_item` uses this new opening scheme. It
supports a dynamic array of opener functions, that will handle specific
item types. By default, a `Buffer` should be able to be able to open any
file that another opener did not.

A key detail here is that the order of registration matters. The last
item has primacy. Here's an example:

```rust
workspace::register_project_item::<Editor>(cx);
workspace::register_project_item::<Notebook>(cx);
workspace::register_project_item::<ImageViewer>(cx);
```

When a project item (file) is attempted to be opened, it's first tried
with the `ImageViewer`, followed by the `Notebook`, then the `Editor`.

The tests are set up in a way that should make it _hopefully_ easy to
learn how to write a new opener. First to go after should probably be
image files.

Release Notes:

N/A

---------

Co-authored-by: Antonio Scandurra <me@as-cii.com>
Co-authored-by: Mikayla Maki <mikayla@zed.dev>
This commit is contained in:
Kyle Kelley 2024-03-14 18:01:40 -07:00 committed by GitHub
parent f9b9123606
commit 72d36d0213
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 369 additions and 39 deletions

View file

@ -118,6 +118,13 @@ const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5
pub const SERVER_PROGRESS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
pub trait Item {
fn try_open(
project: &Model<Project>,
path: &ProjectPath,
cx: &mut AppContext,
) -> Option<Task<Result<Model<Self>>>>
where
Self: Sized;
fn entry_id(&self, cx: &AppContext) -> Option<ProjectEntryId>;
fn project_path(&self, cx: &AppContext) -> Option<ProjectPath>;
}
@ -9616,6 +9623,14 @@ fn resolve_path(base: &Path, path: &Path) -> PathBuf {
}
impl Item for Buffer {
fn try_open(
project: &Model<Project>,
path: &ProjectPath,
cx: &mut AppContext,
) -> Option<Task<Result<Model<Self>>>> {
Some(project.update(cx, |project, cx| project.open_buffer(path.clone(), cx)))
}
fn entry_id(&self, cx: &AppContext) -> Option<ProjectEntryId> {
File::from_dyn(self.file()).and_then(|file| file.project_entry_id(cx))
}