projections.rs

 1// Projections allow users to associate files within a project as projections of
 2// one another. Inspired by https://github.com/tpope/vim-projectionist .
 3//
 4// Take, for example, a newly generated Phoenix project. Among other files, one
 5// can find the page controller module and its corresponding test file in:
 6//
 7// - `lib/app_web/controllers/page_controller.ex`
 8// - `lib/app_web/controllers/page_controller_test.exs`
 9//
10// From the point of view of the controller module, one can say that the test
11// file is a projection of the controller module, and vice versa.
12//
13// TODO!:
14// - [ ] Implement `:a` to open alternate file
15// - [ ] Implement `:as` to open alternate file in split
16// - [ ] Implement `:av` to open alternate file in vertical split
17// - [ ] Implement actually updating the state from the `projections.json` file
18// - [ ] Make this work with excerpts in multibuffers
19
20use crate::Vim;
21use editor::Editor;
22use gpui::Context;
23use gpui::Window;
24use gpui::actions;
25use project::ProjectItem;
26use project::ProjectPath;
27use util::rel_path::RelPath;
28
29actions!(
30    vim,
31    [
32        /// Opens a projection of the current file.
33        OpenProjection,
34    ]
35);
36
37pub fn register(editor: &mut Editor, cx: &mut Context<Vim>) {
38    Vim::action(editor, cx, Vim::open_projection);
39}
40
41impl Vim {
42    pub fn open_projection(
43        &mut self,
44        _: &OpenProjection,
45        window: &mut Window,
46        cx: &mut Context<Self>,
47    ) {
48        // Implementation for opening a projection
49        dbg!("[vim] attempting to open projection...");
50        self.update_editor(cx, |_vim, editor, cx| {
51            let project_path = editor
52                .buffer()
53                .read(cx)
54                .as_singleton()
55                .and_then(|buffer| buffer.read(cx).project_path(cx));
56
57            // User is editing an empty buffer, can't even find a projection.
58            if project_path.is_none() {
59                return;
60            }
61
62            if let Some(project_path) = project_path
63                && let Some(workspace) = editor.workspace()
64            {
65                dbg!(&project_path);
66                if project_path.path.as_unix_str()
67                    == "lib/phx_new_web/controllers/page_controller.ex"
68                {
69                    dbg!("[vim] opening projection...");
70                    workspace
71                        .update(cx, |workspace, cx| {
72                            let worktree_id = project_path.worktree_id;
73                            let mut project_path = ProjectPath::root_path(worktree_id);
74                            project_path.path = RelPath::unix(
75                                "test/phx_new_web/controllers/page_controller_test.exs",
76                            )
77                            .unwrap()
78                            .into_arc();
79                            dbg!(&project_path);
80
81                            workspace.open_path(project_path, None, true, window, cx)
82                        })
83                        .detach();
84                }
85            }
86        });
87    }
88}