Restore completion provider tests

Co-authored-by: Cole Miller <cole@zed.dev>
This commit is contained in:
Agus Zubiaga 2025-08-13 11:16:03 -03:00
parent 6ed2155b9a
commit d26f80ebad
2 changed files with 370 additions and 380 deletions

View file

@ -180,7 +180,7 @@ pub struct MentionLink<'a>(&'a MentionUri);
impl fmt::Display for MentionLink<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "[{}]({})", self.0.name(), self.0.to_uri())
write!(f, "[@{}]({})", self.0.name(), self.0.to_uri())
}
}

View file

@ -1034,438 +1034,428 @@ impl MentionCompletion {
}
}
// #[cfg(test)]
// mod tests {
// use super::*;
// use editor::AnchorRangeExt;
// use gpui::{EventEmitter, FocusHandle, Focusable, TestAppContext, VisualTestContext};
// use project::{Project, ProjectPath};
// use serde_json::json;
// use settings::SettingsStore;
// use std::{ops::Deref, rc::Rc};
// use util::path;
// use workspace::{AppState, Item};
#[cfg(test)]
mod tests {
use super::*;
use editor::AnchorRangeExt;
use gpui::{EventEmitter, FocusHandle, Focusable, TestAppContext, VisualTestContext};
use project::{Project, ProjectPath};
use serde_json::json;
use settings::SettingsStore;
use std::{ops::Deref, rc::Rc};
use util::path;
use workspace::{AppState, Item};
// #[test]
// fn test_mention_completion_parse() {
// assert_eq!(MentionCompletion::try_parse("Lorem Ipsum", 0), None);
#[test]
fn test_mention_completion_parse() {
assert_eq!(MentionCompletion::try_parse("Lorem Ipsum", 0), None);
// assert_eq!(
// MentionCompletion::try_parse("Lorem @", 0),
// Some(MentionCompletion {
// source_range: 6..7,
// mode: None,
// argument: None,
// })
// );
assert_eq!(
MentionCompletion::try_parse("Lorem @", 0),
Some(MentionCompletion {
source_range: 6..7,
mode: None,
argument: None,
})
);
// assert_eq!(
// MentionCompletion::try_parse("Lorem @file", 0),
// Some(MentionCompletion {
// source_range: 6..11,
// mode: Some(ContextPickerMode::File),
// argument: None,
// })
// );
assert_eq!(
MentionCompletion::try_parse("Lorem @file", 0),
Some(MentionCompletion {
source_range: 6..11,
mode: Some(ContextPickerMode::File),
argument: None,
})
);
// assert_eq!(
// MentionCompletion::try_parse("Lorem @file ", 0),
// Some(MentionCompletion {
// source_range: 6..12,
// mode: Some(ContextPickerMode::File),
// argument: None,
// })
// );
assert_eq!(
MentionCompletion::try_parse("Lorem @file ", 0),
Some(MentionCompletion {
source_range: 6..12,
mode: Some(ContextPickerMode::File),
argument: None,
})
);
// assert_eq!(
// MentionCompletion::try_parse("Lorem @file main.rs", 0),
// Some(MentionCompletion {
// source_range: 6..19,
// mode: Some(ContextPickerMode::File),
// argument: Some("main.rs".to_string()),
// })
// );
assert_eq!(
MentionCompletion::try_parse("Lorem @file main.rs", 0),
Some(MentionCompletion {
source_range: 6..19,
mode: Some(ContextPickerMode::File),
argument: Some("main.rs".to_string()),
})
);
// assert_eq!(
// MentionCompletion::try_parse("Lorem @file main.rs ", 0),
// Some(MentionCompletion {
// source_range: 6..19,
// mode: Some(ContextPickerMode::File),
// argument: Some("main.rs".to_string()),
// })
// );
assert_eq!(
MentionCompletion::try_parse("Lorem @file main.rs ", 0),
Some(MentionCompletion {
source_range: 6..19,
mode: Some(ContextPickerMode::File),
argument: Some("main.rs".to_string()),
})
);
// assert_eq!(
// MentionCompletion::try_parse("Lorem @file main.rs Ipsum", 0),
// Some(MentionCompletion {
// source_range: 6..19,
// mode: Some(ContextPickerMode::File),
// argument: Some("main.rs".to_string()),
// })
// );
assert_eq!(
MentionCompletion::try_parse("Lorem @file main.rs Ipsum", 0),
Some(MentionCompletion {
source_range: 6..19,
mode: Some(ContextPickerMode::File),
argument: Some("main.rs".to_string()),
})
);
// assert_eq!(
// MentionCompletion::try_parse("Lorem @main", 0),
// Some(MentionCompletion {
// source_range: 6..11,
// mode: None,
// argument: Some("main".to_string()),
// })
// );
assert_eq!(
MentionCompletion::try_parse("Lorem @main", 0),
Some(MentionCompletion {
source_range: 6..11,
mode: None,
argument: Some("main".to_string()),
})
);
// assert_eq!(MentionCompletion::try_parse("test@", 0), None);
// }
assert_eq!(MentionCompletion::try_parse("test@", 0), None);
}
// struct AtMentionEditor(Entity<Editor>);
struct AtMentionEditor(Entity<Editor>);
// impl Item for AtMentionEditor {
// type Event = ();
impl Item for AtMentionEditor {
type Event = ();
// fn include_in_nav_history() -> bool {
// false
// }
fn include_in_nav_history() -> bool {
false
}
// fn tab_content_text(&self, _detail: usize, _cx: &App) -> SharedString {
// "Test".into()
// }
// }
fn tab_content_text(&self, _detail: usize, _cx: &App) -> SharedString {
"Test".into()
}
}
// impl EventEmitter<()> for AtMentionEditor {}
impl EventEmitter<()> for AtMentionEditor {}
// impl Focusable for AtMentionEditor {
// fn focus_handle(&self, cx: &App) -> FocusHandle {
// self.0.read(cx).focus_handle(cx).clone()
// }
// }
impl Focusable for AtMentionEditor {
fn focus_handle(&self, cx: &App) -> FocusHandle {
self.0.read(cx).focus_handle(cx).clone()
}
}
// impl Render for AtMentionEditor {
// fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
// self.0.clone().into_any_element()
// }
// }
impl Render for AtMentionEditor {
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
self.0.clone().into_any_element()
}
}
// #[gpui::test]
// async fn test_context_completion_provider(cx: &mut TestAppContext) {
// init_test(cx);
#[gpui::test]
async fn test_context_completion_provider(cx: &mut TestAppContext) {
init_test(cx);
// let app_state = cx.update(AppState::test);
let app_state = cx.update(AppState::test);
// cx.update(|cx| {
// language::init(cx);
// editor::init(cx);
// workspace::init(app_state.clone(), cx);
// Project::init_settings(cx);
// });
cx.update(|cx| {
language::init(cx);
editor::init(cx);
workspace::init(app_state.clone(), cx);
Project::init_settings(cx);
});
// app_state
// .fs
// .as_fake()
// .insert_tree(
// path!("/dir"),
// json!({
// "editor": "",
// "a": {
// "one.txt": "",
// "two.txt": "",
// "three.txt": "",
// "four.txt": ""
// },
// "b": {
// "five.txt": "",
// "six.txt": "",
// "seven.txt": "",
// "eight.txt": "",
// }
// }),
// )
// .await;
app_state
.fs
.as_fake()
.insert_tree(
path!("/dir"),
json!({
"editor": "",
"a": {
"one.txt": "",
"two.txt": "",
"three.txt": "",
"four.txt": ""
},
"b": {
"five.txt": "",
"six.txt": "",
"seven.txt": "",
"eight.txt": "",
}
}),
)
.await;
// let project = Project::test(app_state.fs.clone(), [path!("/dir").as_ref()], cx).await;
// let window = cx.add_window(|window, cx| Workspace::test_new(project.clone(), window, cx));
// let workspace = window.root(cx).unwrap();
let project = Project::test(app_state.fs.clone(), [path!("/dir").as_ref()], cx).await;
let window = cx.add_window(|window, cx| Workspace::test_new(project.clone(), window, cx));
let workspace = window.root(cx).unwrap();
// let worktree = project.update(cx, |project, cx| {
// let mut worktrees = project.worktrees(cx).collect::<Vec<_>>();
// assert_eq!(worktrees.len(), 1);
// worktrees.pop().unwrap()
// });
// let worktree_id = worktree.read_with(cx, |worktree, _| worktree.id());
let worktree = project.update(cx, |project, cx| {
let mut worktrees = project.worktrees(cx).collect::<Vec<_>>();
assert_eq!(worktrees.len(), 1);
worktrees.pop().unwrap()
});
let worktree_id = worktree.read_with(cx, |worktree, _| worktree.id());
// let mut cx = VisualTestContext::from_window(*window.deref(), cx);
let mut cx = VisualTestContext::from_window(*window.deref(), cx);
// let paths = vec![
// path!("a/one.txt"),
// path!("a/two.txt"),
// path!("a/three.txt"),
// path!("a/four.txt"),
// path!("b/five.txt"),
// path!("b/six.txt"),
// path!("b/seven.txt"),
// path!("b/eight.txt"),
// ];
let paths = vec![
path!("a/one.txt"),
path!("a/two.txt"),
path!("a/three.txt"),
path!("a/four.txt"),
path!("b/five.txt"),
path!("b/six.txt"),
path!("b/seven.txt"),
path!("b/eight.txt"),
];
// let mut opened_editors = Vec::new();
// for path in paths {
// let buffer = workspace
// .update_in(&mut cx, |workspace, window, cx| {
// workspace.open_path(
// ProjectPath {
// worktree_id,
// path: Path::new(path).into(),
// },
// None,
// false,
// window,
// cx,
// )
// })
// .await
// .unwrap();
// opened_editors.push(buffer);
// }
let mut opened_editors = Vec::new();
for path in paths {
let buffer = workspace
.update_in(&mut cx, |workspace, window, cx| {
workspace.open_path(
ProjectPath {
worktree_id,
path: Path::new(path).into(),
},
None,
false,
window,
cx,
)
})
.await
.unwrap();
opened_editors.push(buffer);
}
// let editor = workspace.update_in(&mut cx, |workspace, window, cx| {
// let editor = cx.new(|cx| {
// Editor::new(
// editor::EditorMode::full(),
// multi_buffer::MultiBuffer::build_simple("", cx),
// None,
// window,
// cx,
// )
// });
// workspace.active_pane().update(cx, |pane, cx| {
// pane.add_item(
// Box::new(cx.new(|_| AtMentionEditor(editor.clone()))),
// true,
// true,
// None,
// window,
// cx,
// );
// });
// editor
// });
let editor = workspace.update_in(&mut cx, |workspace, window, cx| {
let editor = cx.new(|cx| {
Editor::new(
editor::EditorMode::full(),
multi_buffer::MultiBuffer::build_simple("", cx),
None,
window,
cx,
)
});
workspace.active_pane().update(cx, |pane, cx| {
pane.add_item(
Box::new(cx.new(|_| AtMentionEditor(editor.clone()))),
true,
true,
None,
window,
cx,
);
});
editor
});
// let context_store = cx.new(|_| ContextStore::new(project.downgrade(), None));
let mention_set = Arc::new(Mutex::new(MentionSet::default()));
// let editor_entity = editor.downgrade();
// editor.update_in(&mut cx, |editor, window, cx| {
// let last_opened_buffer = opened_editors.last().and_then(|editor| {
// editor
// .downcast::<Editor>()?
// .read(cx)
// .buffer()
// .read(cx)
// .as_singleton()
// .as_ref()
// .map(Entity::downgrade)
// });
// window.focus(&editor.focus_handle(cx));
// editor.set_completion_provider(Some(Rc::new(ContextPickerCompletionProvider::new(
// workspace.downgrade(),
// context_store.downgrade(),
// None,
// None,
// editor_entity,
// last_opened_buffer,
// ))));
// });
let editor_entity = editor.downgrade();
editor.update_in(&mut cx, |editor, window, cx| {
window.focus(&editor.focus_handle(cx));
editor.set_completion_provider(Some(Rc::new(ContextPickerCompletionProvider::new(
mention_set.clone(),
workspace.downgrade(),
WeakEntity::new_invalid(),
WeakEntity::new_invalid(),
editor_entity,
))));
});
// cx.simulate_input("Lorem ");
cx.simulate_input("Lorem ");
// editor.update(&mut cx, |editor, cx| {
// assert_eq!(editor.text(cx), "Lorem ");
// assert!(!editor.has_visible_completions_menu());
// });
editor.update(&mut cx, |editor, cx| {
assert_eq!(editor.text(cx), "Lorem ");
assert!(!editor.has_visible_completions_menu());
});
// cx.simulate_input("@");
cx.simulate_input("@");
// editor.update(&mut cx, |editor, cx| {
// assert_eq!(editor.text(cx), "Lorem @");
// assert!(editor.has_visible_completions_menu());
// assert_eq!(
// current_completion_labels(editor),
// &[
// "seven.txt dir/b/",
// "six.txt dir/b/",
// "five.txt dir/b/",
// "four.txt dir/a/",
// "Files & Directories",
// "Symbols",
// "Fetch"
// ]
// );
// });
editor.update(&mut cx, |editor, cx| {
assert_eq!(editor.text(cx), "Lorem @");
assert!(editor.has_visible_completions_menu());
assert_eq!(
current_completion_labels(editor),
&[
"eight.txt dir/b/",
"seven.txt dir/b/",
"six.txt dir/b/",
"five.txt dir/b/",
"Files & Directories",
"Symbols",
"Threads",
"Fetch"
]
);
});
// // Select and confirm "File"
// editor.update_in(&mut cx, |editor, window, cx| {
// assert!(editor.has_visible_completions_menu());
// editor.context_menu_next(&editor::actions::ContextMenuNext, window, cx);
// editor.context_menu_next(&editor::actions::ContextMenuNext, window, cx);
// editor.context_menu_next(&editor::actions::ContextMenuNext, window, cx);
// editor.context_menu_next(&editor::actions::ContextMenuNext, window, cx);
// editor.confirm_completion(&editor::actions::ConfirmCompletion::default(), window, cx);
// });
// Select and confirm "File"
editor.update_in(&mut cx, |editor, window, cx| {
assert!(editor.has_visible_completions_menu());
editor.context_menu_next(&editor::actions::ContextMenuNext, window, cx);
editor.context_menu_next(&editor::actions::ContextMenuNext, window, cx);
editor.context_menu_next(&editor::actions::ContextMenuNext, window, cx);
editor.context_menu_next(&editor::actions::ContextMenuNext, window, cx);
editor.confirm_completion(&editor::actions::ConfirmCompletion::default(), window, cx);
});
// cx.run_until_parked();
cx.run_until_parked();
// editor.update(&mut cx, |editor, cx| {
// assert_eq!(editor.text(cx), "Lorem @file ");
// assert!(editor.has_visible_completions_menu());
// });
editor.update(&mut cx, |editor, cx| {
assert_eq!(editor.text(cx), "Lorem @file ");
assert!(editor.has_visible_completions_menu());
});
// cx.simulate_input("one");
cx.simulate_input("one");
// editor.update(&mut cx, |editor, cx| {
// assert_eq!(editor.text(cx), "Lorem @file one");
// assert!(editor.has_visible_completions_menu());
// assert_eq!(current_completion_labels(editor), vec!["one.txt dir/a/"]);
// });
editor.update(&mut cx, |editor, cx| {
assert_eq!(editor.text(cx), "Lorem @file one");
assert!(editor.has_visible_completions_menu());
assert_eq!(current_completion_labels(editor), vec!["one.txt dir/a/"]);
});
// editor.update_in(&mut cx, |editor, window, cx| {
// assert!(editor.has_visible_completions_menu());
// editor.confirm_completion(&editor::actions::ConfirmCompletion::default(), window, cx);
// });
editor.update_in(&mut cx, |editor, window, cx| {
assert!(editor.has_visible_completions_menu());
editor.confirm_completion(&editor::actions::ConfirmCompletion::default(), window, cx);
});
// editor.update(&mut cx, |editor, cx| {
// assert_eq!(editor.text(cx), "Lorem [@one.txt](@file:dir/a/one.txt) ");
// assert!(!editor.has_visible_completions_menu());
// assert_eq!(
// fold_ranges(editor, cx),
// vec![Point::new(0, 6)..Point::new(0, 37)]
// );
// });
editor.update(&mut cx, |editor, cx| {
assert_eq!(editor.text(cx), "Lorem [@one.txt](file:///dir/a/one.txt) ");
assert!(!editor.has_visible_completions_menu());
assert_eq!(
fold_ranges(editor, cx),
vec![Point::new(0, 6)..Point::new(0, 39)]
);
});
// cx.simulate_input(" ");
cx.simulate_input(" ");
// editor.update(&mut cx, |editor, cx| {
// assert_eq!(editor.text(cx), "Lorem [@one.txt](@file:dir/a/one.txt) ");
// assert!(!editor.has_visible_completions_menu());
// assert_eq!(
// fold_ranges(editor, cx),
// vec![Point::new(0, 6)..Point::new(0, 37)]
// );
// });
editor.update(&mut cx, |editor, cx| {
assert_eq!(editor.text(cx), "Lorem [@one.txt](file:///dir/a/one.txt) ");
assert!(!editor.has_visible_completions_menu());
assert_eq!(
fold_ranges(editor, cx),
vec![Point::new(0, 6)..Point::new(0, 39)]
);
});
// cx.simulate_input("Ipsum ");
cx.simulate_input("Ipsum ");
// editor.update(&mut cx, |editor, cx| {
// assert_eq!(
// editor.text(cx),
// "Lorem [@one.txt](@file:dir/a/one.txt) Ipsum ",
// );
// assert!(!editor.has_visible_completions_menu());
// assert_eq!(
// fold_ranges(editor, cx),
// vec![Point::new(0, 6)..Point::new(0, 37)]
// );
// });
editor.update(&mut cx, |editor, cx| {
assert_eq!(
editor.text(cx),
"Lorem [@one.txt](file:///dir/a/one.txt) Ipsum ",
);
assert!(!editor.has_visible_completions_menu());
assert_eq!(
fold_ranges(editor, cx),
vec![Point::new(0, 6)..Point::new(0, 39)]
);
});
// cx.simulate_input("@file ");
cx.simulate_input("@file ");
// editor.update(&mut cx, |editor, cx| {
// assert_eq!(
// editor.text(cx),
// "Lorem [@one.txt](@file:dir/a/one.txt) Ipsum @file ",
// );
// assert!(editor.has_visible_completions_menu());
// assert_eq!(
// fold_ranges(editor, cx),
// vec![Point::new(0, 6)..Point::new(0, 37)]
// );
// });
editor.update(&mut cx, |editor, cx| {
assert_eq!(
editor.text(cx),
"Lorem [@one.txt](file:///dir/a/one.txt) Ipsum @file ",
);
assert!(editor.has_visible_completions_menu());
assert_eq!(
fold_ranges(editor, cx),
vec![Point::new(0, 6)..Point::new(0, 39)]
);
});
// editor.update_in(&mut cx, |editor, window, cx| {
// editor.confirm_completion(&editor::actions::ConfirmCompletion::default(), window, cx);
// });
editor.update_in(&mut cx, |editor, window, cx| {
editor.confirm_completion(&editor::actions::ConfirmCompletion::default(), window, cx);
});
// cx.run_until_parked();
cx.run_until_parked();
// editor.update(&mut cx, |editor, cx| {
// assert_eq!(
// editor.text(cx),
// "Lorem [@one.txt](@file:dir/a/one.txt) Ipsum [@seven.txt](@file:dir/b/seven.txt) "
// );
// assert!(!editor.has_visible_completions_menu());
// assert_eq!(
// fold_ranges(editor, cx),
// vec![
// Point::new(0, 6)..Point::new(0, 37),
// Point::new(0, 45)..Point::new(0, 80)
// ]
// );
// });
editor.update(&mut cx, |editor, cx| {
assert_eq!(
editor.text(cx),
"Lorem [@one.txt](file:///dir/a/one.txt) Ipsum [@eight.txt](file:///dir/b/eight.txt) "
);
assert!(!editor.has_visible_completions_menu());
assert_eq!(
fold_ranges(editor, cx),
vec![
Point::new(0, 6)..Point::new(0, 39),
Point::new(0, 47)..Point::new(0, 84)
]
);
});
// cx.simulate_input("\n@");
cx.simulate_input("\n@");
// editor.update(&mut cx, |editor, cx| {
// assert_eq!(
// editor.text(cx),
// "Lorem [@one.txt](@file:dir/a/one.txt) Ipsum [@seven.txt](@file:dir/b/seven.txt) \n@"
// );
// assert!(editor.has_visible_completions_menu());
// assert_eq!(
// fold_ranges(editor, cx),
// vec![
// Point::new(0, 6)..Point::new(0, 37),
// Point::new(0, 45)..Point::new(0, 80)
// ]
// );
// });
editor.update(&mut cx, |editor, cx| {
assert_eq!(
editor.text(cx),
"Lorem [@one.txt](file:///dir/a/one.txt) Ipsum [@eight.txt](file:///dir/b/eight.txt) \n@"
);
assert!(editor.has_visible_completions_menu());
assert_eq!(
fold_ranges(editor, cx),
vec![
Point::new(0, 6)..Point::new(0, 39),
Point::new(0, 47)..Point::new(0, 84)
]
);
});
// editor.update_in(&mut cx, |editor, window, cx| {
// editor.confirm_completion(&editor::actions::ConfirmCompletion::default(), window, cx);
// });
editor.update_in(&mut cx, |editor, window, cx| {
editor.confirm_completion(&editor::actions::ConfirmCompletion::default(), window, cx);
});
// cx.run_until_parked();
cx.run_until_parked();
// editor.update(&mut cx, |editor, cx| {
// assert_eq!(
// editor.text(cx),
// "Lorem [@one.txt](@file:dir/a/one.txt) Ipsum [@seven.txt](@file:dir/b/seven.txt) \n[@six.txt](@file:dir/b/six.txt) "
// );
// assert!(!editor.has_visible_completions_menu());
// assert_eq!(
// fold_ranges(editor, cx),
// vec![
// Point::new(0, 6)..Point::new(0, 37),
// Point::new(0, 45)..Point::new(0, 80),
// Point::new(1, 0)..Point::new(1, 31)
// ]
// );
// });
// }
editor.update(&mut cx, |editor, cx| {
assert_eq!(
editor.text(cx),
"Lorem [@one.txt](file:///dir/a/one.txt) Ipsum [@eight.txt](file:///dir/b/eight.txt) \n[@seven.txt](file:///dir/b/seven.txt) "
);
assert!(!editor.has_visible_completions_menu());
assert_eq!(
fold_ranges(editor, cx),
vec![
Point::new(0, 6)..Point::new(0, 39),
Point::new(0, 47)..Point::new(0, 84),
Point::new(1, 0)..Point::new(1, 37)
]
);
});
}
// fn fold_ranges(editor: &Editor, cx: &mut App) -> Vec<Range<Point>> {
// let snapshot = editor.buffer().read(cx).snapshot(cx);
// editor.display_map.update(cx, |display_map, cx| {
// display_map
// .snapshot(cx)
// .folds_in_range(0..snapshot.len())
// .map(|fold| fold.range.to_point(&snapshot))
// .collect()
// })
// }
fn fold_ranges(editor: &Editor, cx: &mut App) -> Vec<Range<Point>> {
let snapshot = editor.buffer().read(cx).snapshot(cx);
editor.display_map.update(cx, |display_map, cx| {
display_map
.snapshot(cx)
.folds_in_range(0..snapshot.len())
.map(|fold| fold.range.to_point(&snapshot))
.collect()
})
}
// fn current_completion_labels(editor: &Editor) -> Vec<String> {
// let completions = editor.current_completions().expect("Missing completions");
// completions
// .into_iter()
// .map(|completion| completion.label.text.to_string())
// .collect::<Vec<_>>()
// }
fn current_completion_labels(editor: &Editor) -> Vec<String> {
let completions = editor.current_completions().expect("Missing completions");
completions
.into_iter()
.map(|completion| completion.label.text.to_string())
.collect::<Vec<_>>()
}
// pub(crate) fn init_test(cx: &mut TestAppContext) {
// cx.update(|cx| {
// let store = SettingsStore::test(cx);
// cx.set_global(store);
// theme::init(theme::LoadThemes::JustBase, cx);
// client::init_settings(cx);
// language::init(cx);
// Project::init_settings(cx);
// workspace::init_settings(cx);
// editor::init_settings(cx);
// });
// }
// }
pub(crate) fn init_test(cx: &mut TestAppContext) {
cx.update(|cx| {
let store = SettingsStore::test(cx);
cx.set_global(store);
theme::init(theme::LoadThemes::JustBase, cx);
client::init_settings(cx);
language::init(cx);
Project::init_settings(cx);
workspace::init_settings(cx);
editor::init_settings(cx);
});
}
}