From 7143d4017b8f2838930b40978285205034bc547a Mon Sep 17 00:00:00 2001 From: dino Date: Tue, 4 Nov 2025 00:00:33 +0000 Subject: [PATCH] chore(vim): add projections :sunrise: --- crates/vim/src/projections.rs | 88 +++++++++++++++++++++++++++++++++++ crates/vim/src/vim.rs | 2 + 2 files changed, 90 insertions(+) create mode 100644 crates/vim/src/projections.rs diff --git a/crates/vim/src/projections.rs b/crates/vim/src/projections.rs new file mode 100644 index 0000000000000000000000000000000000000000..9e242e66b40390b703ef297431441f15c5756913 --- /dev/null +++ b/crates/vim/src/projections.rs @@ -0,0 +1,88 @@ +// Projections allow users to associate files within a project as projections of +// one another. Inspired by https://github.com/tpope/vim-projectionist . +// +// Take, for example, a newly generated Phoenix project. Among other files, one +// can find the page controller module and its corresponding test file in: +// +// - `lib/app_web/controllers/page_controller.ex` +// - `lib/app_web/controllers/page_controller_test.exs` +// +// From the point of view of the controller module, one can say that the test +// file is a projection of the controller module, and vice versa. +// +// TODO!: +// - [ ] Implement `:a` to open alternate file +// - [ ] Implement `:as` to open alternate file in split +// - [ ] Implement `:av` to open alternate file in vertical split +// - [ ] Implement actually updating the state from the `projections.json` file +// - [ ] Make this work with excerpts in multibuffers + +use crate::Vim; +use editor::Editor; +use gpui::Context; +use gpui::Window; +use gpui::actions; +use project::ProjectItem; +use project::ProjectPath; +use util::rel_path::RelPath; + +actions!( + vim, + [ + /// Opens a projection of the current file. + OpenProjection, + ] +); + +pub fn register(editor: &mut Editor, cx: &mut Context) { + Vim::action(editor, cx, Vim::open_projection); +} + +impl Vim { + pub fn open_projection( + &mut self, + _: &OpenProjection, + window: &mut Window, + cx: &mut Context, + ) { + // Implementation for opening a projection + dbg!("[vim] attempting to open projection..."); + self.update_editor(cx, |_vim, editor, cx| { + let project_path = editor + .buffer() + .read(cx) + .as_singleton() + .and_then(|buffer| buffer.read(cx).project_path(cx)); + + // User is editing an empty buffer, can't even find a projection. + if project_path.is_none() { + return; + } + + if let Some(project_path) = project_path + && let Some(workspace) = editor.workspace() + { + dbg!(&project_path); + if project_path.path.as_unix_str() + == "lib/phx_new_web/controllers/page_controller.ex" + { + dbg!("[vim] opening projection..."); + workspace + .update(cx, |workspace, cx| { + let worktree_id = project_path.worktree_id; + let mut project_path = ProjectPath::root_path(worktree_id); + project_path.path = RelPath::unix( + "test/phx_new_web/controllers/page_controller_test.exs", + ) + .unwrap() + .into_arc(); + dbg!(&project_path); + + workspace.open_path(project_path, None, true, window, cx) + }) + .detach(); + } + } + }); + } +} diff --git a/crates/vim/src/vim.rs b/crates/vim/src/vim.rs index 6ffdbcce910c10229dc7c2e6df95055c5c812f28..0e292c0769c0ca4cf82460f7dae29501f4d00a6d 100644 --- a/crates/vim/src/vim.rs +++ b/crates/vim/src/vim.rs @@ -13,6 +13,7 @@ mod mode_indicator; mod motion; mod normal; mod object; +mod projections; mod replace; mod rewrap; mod state; @@ -942,6 +943,7 @@ impl Vim { visual::register(editor, cx); change_list::register(editor, cx); digraph::register(editor, cx); + projections::register(editor, cx); if editor.is_focused(window) { cx.defer_in(window, |vim, window, cx| {