refactoring
This commit is contained in:
+400
-28
@@ -5,14 +5,16 @@
|
||||
//! фиксируют поведение самого приложения: документы, API, Lua и KeyMap.
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::path::Path;
|
||||
use std::rc::Rc;
|
||||
|
||||
use gpui_kit::{Keystroke, Modifiers, TestAppContext, px};
|
||||
use lsp_types::{Diagnostic, DiagnosticSeverity, Position, Range};
|
||||
|
||||
use crate::api::{AppApi, WindowCommand, drain_window_commands};
|
||||
use crate::app::MyApp;
|
||||
use crate::editor::{Language, Workspace};
|
||||
use crate::keymap::{KeyBinding, KeyMap, Modifiers as KeyModifiers};
|
||||
use crate::editor::{FocusAfterSync, Language, Workspace};
|
||||
use crate::keymap::{KeyBinding, KeyContext, KeyHandler, KeyMap, Modifiers as KeyModifiers};
|
||||
use crate::panel::PanelBlock;
|
||||
use crate::script::ScriptEngine;
|
||||
use crate::tree::TreeNode;
|
||||
@@ -55,17 +57,17 @@ fn lua_lsp_api_lists_no_servers_and_validates_config() {
|
||||
#[test]
|
||||
fn workspace_keeps_at_least_one_tab() {
|
||||
let mut state = Workspace::default();
|
||||
assert_eq!(state.documents().len(), 2);
|
||||
assert_eq!(state.active().name, "main.rs");
|
||||
assert_eq!(state.documents().len(), 1);
|
||||
assert_eq!(state.active().name, "untitled-1.txt");
|
||||
|
||||
// Открытие и закрытие новых вкладок.
|
||||
state.open_new();
|
||||
assert_eq!(state.documents().len(), 3);
|
||||
assert_eq!(state.active_index(), 2);
|
||||
|
||||
state.close(2);
|
||||
assert_eq!(state.documents().len(), 2);
|
||||
assert_eq!(state.active_index(), 1);
|
||||
|
||||
state.close(1);
|
||||
assert_eq!(state.active_index(), 0);
|
||||
|
||||
// Редактор не должен оставаться пустым.
|
||||
while state.documents().len() > 1 {
|
||||
state.close(0);
|
||||
@@ -83,7 +85,7 @@ fn closing_tab_before_active_keeps_the_same_document_active() {
|
||||
|
||||
state.close(0);
|
||||
assert_eq!(state.active().id, id);
|
||||
assert_eq!(state.active_index(), 1);
|
||||
assert_eq!(state.active_index(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -112,6 +114,8 @@ fn revision_changes_only_for_external_edits() {
|
||||
assert_ne!(state.revision(), revision);
|
||||
|
||||
// Переключение вкладки — тоже.
|
||||
state.open_new();
|
||||
state.set_active(0);
|
||||
let before_switch = state.revision();
|
||||
state.set_active(1);
|
||||
assert_ne!(state.revision(), before_switch);
|
||||
@@ -127,13 +131,15 @@ fn api_lists_tabs_and_closes_them_by_number() {
|
||||
tabs.iter()
|
||||
.map(|tab| (tab.index, tab.title.as_str()))
|
||||
.collect::<Vec<_>>(),
|
||||
vec![(0, "main.rs"), (1, "notes.md")]
|
||||
vec![(0, "untitled-1.txt")]
|
||||
);
|
||||
|
||||
// Несуществующий номер ничего не закрывает.
|
||||
assert!(!api.close_tab(99));
|
||||
assert_eq!(api.tabs().len(), 2);
|
||||
assert_eq!(api.tabs().len(), 1);
|
||||
|
||||
api.open_tab();
|
||||
assert_eq!(api.tabs().len(), 2);
|
||||
assert!(api.close_tab(1));
|
||||
assert_eq!(api.tabs().len(), 1);
|
||||
assert_eq!(workspace.borrow().documents().len(), 1);
|
||||
@@ -180,6 +186,7 @@ fn lua_script_can_set_tab_icons() {
|
||||
assert(app:tab_icon(0) == "file")
|
||||
assert(app:set_tab_icon(0, "book-open"))
|
||||
assert(app:tab_icon(0) == "book-open")
|
||||
app:open_tab()
|
||||
assert(app:tabs()[2].icon == "file")
|
||||
assert(not app:set_tab_icon(0, "no-such-icon"))
|
||||
assert(app:clear_tab_icon(0))
|
||||
@@ -200,7 +207,7 @@ fn api_save_writes_active_tab_to_file_named_after_it() {
|
||||
// Тест пишет во временный файл, а не в каталог проекта.
|
||||
let workspace = Rc::new(RefCell::new(Workspace::default()));
|
||||
let path = std::env::temp_dir().join(format!(
|
||||
"gpui-editor-test-save-{}-{}.rs",
|
||||
"qode-save-{}-{}.rs",
|
||||
std::process::id(),
|
||||
workspace.borrow().active().id
|
||||
));
|
||||
@@ -231,6 +238,8 @@ fn api_switches_tabs_forward_and_back_in_a_cycle() {
|
||||
let workspace = Rc::new(RefCell::new(Workspace::default()));
|
||||
let (api, _keymap) = install_api(workspace.clone());
|
||||
|
||||
api.open_tab();
|
||||
api.set_active_tab(0);
|
||||
assert_eq!(api.active_tab_index(), 0);
|
||||
|
||||
assert_eq!(api.next_tab(), 1);
|
||||
@@ -392,7 +401,8 @@ fn lua_tree_block_appends_sorts_and_removes_nodes() {
|
||||
|
||||
let panel = api.left_panel_handle();
|
||||
let panel = panel.borrow();
|
||||
let PanelBlock::Tree(tree) = &panel.blocks()[0];
|
||||
let PanelBlock::Tree { tree, title } = &panel.blocks()[0];
|
||||
assert_eq!(title, "Дерево");
|
||||
let rows = tree.borrow().rows();
|
||||
assert_eq!(
|
||||
rows.iter()
|
||||
@@ -414,6 +424,124 @@ fn lua_tree_block_appends_sorts_and_removes_nodes() {
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lua_bottom_panel_tree_has_a_tab_title_and_clears() {
|
||||
let workspace = Rc::new(RefCell::new(Workspace::default()));
|
||||
let (api, _keymap) = install_api(workspace);
|
||||
let bottom = api.bottom_panel_handle();
|
||||
|
||||
let dir = temp_script_dir("bottom-tree");
|
||||
let script = dir.join("bottom.lua");
|
||||
std::fs::write(
|
||||
&script,
|
||||
r#"
|
||||
diag_tree = app.bottom_panel:add_tree("Диагностика")
|
||||
diag_tree:append({
|
||||
{ id = "a", label = "a", expandable = true, expanded = true },
|
||||
}, "")
|
||||
diag_tree:append({
|
||||
{ id = "a:1", label = "ошибка" },
|
||||
}, "a")
|
||||
"#,
|
||||
)
|
||||
.expect("bottom.lua");
|
||||
let clear = dir.join("clear.lua");
|
||||
std::fs::write(&clear, "diag_tree:clear()\n").expect("clear.lua");
|
||||
|
||||
let engine = ScriptEngine::new(api).expect("движок Lua");
|
||||
engine.run_file(&script).expect("блок нижней панели");
|
||||
|
||||
{
|
||||
let panel = bottom.borrow();
|
||||
assert_eq!(panel.blocks().len(), 1);
|
||||
assert_eq!(panel.active(), 0);
|
||||
assert_eq!(panel.blocks()[0].title(), "Диагностика");
|
||||
let PanelBlock::Tree { tree, .. } = &panel.blocks()[0];
|
||||
assert_eq!(tree.borrow().rows().len(), 2);
|
||||
}
|
||||
|
||||
engine.run_file(&clear).expect("tree:clear");
|
||||
let panel = bottom.borrow();
|
||||
let PanelBlock::Tree { tree, .. } = &panel.blocks()[0];
|
||||
assert!(tree.borrow().rows().is_empty());
|
||||
drop(panel);
|
||||
|
||||
drop(engine);
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lua_diagnostics_handler_receives_every_server_and_file() {
|
||||
let workspace = Rc::new(RefCell::new(Workspace::default()));
|
||||
let (api, _keymap) = install_api(workspace.clone());
|
||||
|
||||
let dir = temp_script_dir("diagnostics-handler");
|
||||
let script = dir.join("diagnostics.lua");
|
||||
std::fs::write(
|
||||
&script,
|
||||
r#"
|
||||
app:on_lsp_diagnostics(0, function(servers)
|
||||
assert(#servers == 1, #servers)
|
||||
local entry = servers[1]
|
||||
assert(entry.server == "test")
|
||||
assert(entry.path ~= nil)
|
||||
assert(#entry.diagnostics == 2, #entry.diagnostics)
|
||||
|
||||
local first = entry.diagnostics[1]
|
||||
assert(first.line == 2)
|
||||
assert(first.character == 3)
|
||||
assert(first.end_line == 2)
|
||||
assert(first.end_character == 5)
|
||||
assert(first.severity == 1)
|
||||
assert(first.severity_name == "error")
|
||||
assert(first.message == "плохо")
|
||||
|
||||
assert(entry.diagnostics[2].severity_name == "warning")
|
||||
app:open_tab()
|
||||
end)
|
||||
"#,
|
||||
)
|
||||
.expect("diagnostics.lua");
|
||||
|
||||
let engine = ScriptEngine::new(api.clone()).expect("движок Lua");
|
||||
engine.run_file(&script).expect("регистрация обработчика");
|
||||
assert_eq!(api.diagnostics_delay(), Some(std::time::Duration::ZERO));
|
||||
|
||||
let uri = crate::lsp::path_to_uri(Path::new("/tmp/qode-diagnostics.go"));
|
||||
let diagnostics = vec![
|
||||
Diagnostic {
|
||||
range: Range::new(Position::new(2, 3), Position::new(2, 5)),
|
||||
severity: Some(DiagnosticSeverity::ERROR),
|
||||
message: "плохо".to_owned(),
|
||||
..Default::default()
|
||||
},
|
||||
Diagnostic {
|
||||
range: Range::new(Position::new(4, 0), Position::new(4, 1)),
|
||||
severity: Some(DiagnosticSeverity::WARNING),
|
||||
message: "осторожно".to_owned(),
|
||||
..Default::default()
|
||||
},
|
||||
];
|
||||
api.lsp_handle()
|
||||
.set_diagnostics_for_test(uri.as_str(), diagnostics);
|
||||
|
||||
let report = api.lsp_handle().diagnostics_snapshot();
|
||||
assert_eq!(report.len(), 1);
|
||||
assert_eq!(report[0].server, "test");
|
||||
assert_eq!(report[0].path.as_deref(), Some("/tmp/qode-diagnostics.go"));
|
||||
assert_eq!(report[0].diagnostics.len(), 2);
|
||||
|
||||
assert!(api.emit_diagnostics(report));
|
||||
assert_eq!(
|
||||
workspace.borrow().documents().len(),
|
||||
2,
|
||||
"обработчик должен был открыть новую вкладку"
|
||||
);
|
||||
|
||||
drop(engine);
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lua_list_dir_returns_sorted_entries_with_paths() {
|
||||
let workspace = Rc::new(RefCell::new(Workspace::default()));
|
||||
@@ -455,7 +583,7 @@ fn lua_list_dir_returns_sorted_entries_with_paths() {
|
||||
/// Временный каталог с уникальным именем для Lua-сценариев.
|
||||
fn temp_script_dir(prefix: &str) -> std::path::PathBuf {
|
||||
let dir = std::env::temp_dir().join(format!(
|
||||
"gpui-editor-test-{prefix}-{}-{}",
|
||||
"qode-{prefix}-{}-{}",
|
||||
std::process::id(),
|
||||
std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
@@ -482,7 +610,7 @@ fn lua_script_can_include_files_and_control_the_app() {
|
||||
std::fs::write(
|
||||
&main,
|
||||
format!(
|
||||
"include({:?})\nlua_config()\napp:next_tab()\napp:set_language(1, \"python\")\n",
|
||||
"include({:?})\nlua_config()\napp:open_tab()\napp:set_language(1, \"python\")\n",
|
||||
helper.to_string_lossy()
|
||||
),
|
||||
)
|
||||
@@ -500,7 +628,7 @@ fn lua_script_can_include_files_and_control_the_app() {
|
||||
assert_eq!(
|
||||
state.active_index(),
|
||||
1,
|
||||
"app:next_tab() не переключил вкладку"
|
||||
"app:open_tab() не переключил вкладку"
|
||||
);
|
||||
assert_eq!(
|
||||
state.documents()[1].language,
|
||||
@@ -538,6 +666,55 @@ fn api_opens_file_from_disk_and_detects_language() {
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lua_open_controls_focus_and_cursor() {
|
||||
let workspace = Rc::new(RefCell::new(Workspace::default()));
|
||||
let (api, _keymap) = install_api(workspace.clone());
|
||||
|
||||
let dir = temp_script_dir("lua-open-focus");
|
||||
let path = dir.join("main.go");
|
||||
std::fs::write(&path, "package main\n\nfunc main() {}\n").unwrap();
|
||||
let engine = ScriptEngine::new_in(api, &dir).expect("движок Lua");
|
||||
|
||||
// Без второго аргумента фокус остаётся прежним.
|
||||
let plain = dir.join("plain.lua");
|
||||
std::fs::write(&plain, format!("app:open({:?})\n", path.to_string_lossy())).unwrap();
|
||||
engine.run_file(&plain).expect("app:open без позиции");
|
||||
assert_eq!(
|
||||
workspace.borrow_mut().take_focus_after_sync(),
|
||||
Some(FocusAfterSync::Keep)
|
||||
);
|
||||
|
||||
// Пустая таблица — фокус в редактор, курсор на месте.
|
||||
let focus = dir.join("focus.lua");
|
||||
std::fs::write(
|
||||
&focus,
|
||||
format!("app:open({:?}, {{}})\n", path.to_string_lossy()),
|
||||
)
|
||||
.unwrap();
|
||||
engine.run_file(&focus).expect("app:open с пустой таблицей");
|
||||
assert_eq!(
|
||||
workspace.borrow_mut().take_focus_after_sync(),
|
||||
Some(FocusAfterSync::Editor(None))
|
||||
);
|
||||
|
||||
// Строка 2, столбец 5 — байтовое смещение 19.
|
||||
let at = dir.join("at.lua");
|
||||
std::fs::write(
|
||||
&at,
|
||||
format!("app:open({:?}, {{2, 5}})\n", path.to_string_lossy()),
|
||||
)
|
||||
.unwrap();
|
||||
engine.run_file(&at).expect("app:open с позицией");
|
||||
assert_eq!(
|
||||
workspace.borrow_mut().take_focus_after_sync(),
|
||||
Some(FocusAfterSync::Editor(Some(19)))
|
||||
);
|
||||
|
||||
drop(engine);
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn api_open_missing_file_creates_an_empty_buffer() {
|
||||
let workspace = Rc::new(RefCell::new(Workspace::default()));
|
||||
@@ -647,8 +824,13 @@ fn lua_key_bindings_match_press_release_and_modifiers() {
|
||||
key_char: None,
|
||||
};
|
||||
let fire = |keystroke: &Keystroke, pressed: bool| {
|
||||
for callback in keymap.borrow().callbacks_for(keystroke, pressed) {
|
||||
callback.call::<()>(()).expect("Lua-обработчик");
|
||||
for handler in keymap
|
||||
.borrow()
|
||||
.handlers_for(KeyContext::Global, keystroke, pressed)
|
||||
{
|
||||
if let KeyHandler::Lua(callback) = handler {
|
||||
callback.call::<()>(()).expect("Lua-обработчик");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -713,6 +895,81 @@ fn lua_key_bindings_match_press_release_and_modifiers() {
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lua_keymap_accepts_command_names_and_nil() {
|
||||
let workspace = Rc::new(RefCell::new(Workspace::default()));
|
||||
let (api, keymap) = install_api(workspace);
|
||||
|
||||
let dir = temp_script_dir("key-commands");
|
||||
let script = dir.join("keys.lua");
|
||||
std::fs::write(
|
||||
&script,
|
||||
r#"
|
||||
app:map_key("<C-n>", "next_tab")
|
||||
app:map_completion_key("<C-n>", "completion_next")
|
||||
|
||||
local ok, err = pcall(function()
|
||||
app:map_key("<C-x>", "no_such_command")
|
||||
end)
|
||||
assert(not ok)
|
||||
assert(tostring(err):find("доступны", 1, true), tostring(err))
|
||||
"#,
|
||||
)
|
||||
.expect("keys.lua");
|
||||
|
||||
let engine = ScriptEngine::new(api).expect("движок Lua");
|
||||
engine
|
||||
.run_file(&script)
|
||||
.expect("команды должны назначиться");
|
||||
|
||||
let stroke = Keystroke {
|
||||
modifiers: Modifiers {
|
||||
control: true,
|
||||
..Default::default()
|
||||
},
|
||||
key: "n".to_owned(),
|
||||
key_char: None,
|
||||
};
|
||||
assert!(matches!(
|
||||
keymap
|
||||
.borrow()
|
||||
.handlers_for(KeyContext::Global, &stroke, true)
|
||||
.as_slice(),
|
||||
[KeyHandler::App(crate::keymap::AppCommand::NextTab)]
|
||||
));
|
||||
assert!(matches!(
|
||||
keymap
|
||||
.borrow()
|
||||
.handlers_for(KeyContext::Completion, &stroke, true)
|
||||
.as_slice(),
|
||||
[KeyHandler::Completion(
|
||||
crate::keymap::CompletionCommand::Next
|
||||
)]
|
||||
));
|
||||
|
||||
// nil удаляет привязку, не оставляя заглушку.
|
||||
std::fs::write(
|
||||
&script,
|
||||
"app:map_key(\"<C-n>\", nil)\napp:map_completion_key(\"<C-n>\", nil)\n",
|
||||
)
|
||||
.expect("keys.lua");
|
||||
engine.run_file(&script).expect("привязки должны удалиться");
|
||||
assert!(
|
||||
keymap
|
||||
.borrow()
|
||||
.handlers_for(KeyContext::Global, &stroke, true)
|
||||
.is_empty()
|
||||
);
|
||||
assert!(
|
||||
keymap
|
||||
.borrow()
|
||||
.handlers_for(KeyContext::Completion, &stroke, true)
|
||||
.is_empty()
|
||||
);
|
||||
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn language_names_cover_all_supported_grammars() {
|
||||
for (name, expected) in [
|
||||
@@ -737,6 +994,19 @@ fn language_names_cover_all_supported_grammars() {
|
||||
assert_eq!(Language::Rust.name(), "rust");
|
||||
assert_eq!(Language::JavaScript.name(), "js");
|
||||
assert_eq!(Language::Python.name(), "python");
|
||||
|
||||
// Каждый язык перечитывается по имени и по полному имени для
|
||||
// tree-sitter/LSP.
|
||||
for language in [
|
||||
Language::Rust,
|
||||
Language::Go,
|
||||
Language::JavaScript,
|
||||
Language::Json,
|
||||
Language::Python,
|
||||
] {
|
||||
assert_eq!(Language::from_name(language.name()), Some(language));
|
||||
assert_eq!(Language::from_name(language.syntax_name()), Some(language));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -782,15 +1052,18 @@ fn keymap_bindings_are_parsed_and_replaced() {
|
||||
.load("return function() end")
|
||||
.eval::<mlua::Function>()
|
||||
.unwrap();
|
||||
keymap.bind(plain.clone(), first);
|
||||
keymap.bind(plain, second);
|
||||
keymap.set(KeyContext::Global, plain.clone(), KeyHandler::Lua(first));
|
||||
keymap.set(KeyContext::Global, plain, KeyHandler::Lua(second));
|
||||
|
||||
let stroke = Keystroke {
|
||||
modifiers: Modifiers::default(),
|
||||
key: "a".to_owned(),
|
||||
key_char: None,
|
||||
};
|
||||
assert_eq!(keymap.callbacks_for(&stroke, true).len(), 1);
|
||||
assert_eq!(
|
||||
keymap.handlers_for(KeyContext::Global, &stroke, true).len(),
|
||||
1
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui_kit::test]
|
||||
@@ -838,7 +1111,7 @@ fn lua_key_bindings_receive_keys_while_editor_is_focused(cx: &mut TestAppContext
|
||||
fn opened_panels_render_without_panicking(cx: &mut TestAppContext) {
|
||||
cx.update(gpui_kit::init);
|
||||
|
||||
let (app, visual) = cx.add_window_view(|window, cx| MyApp::new(window, cx));
|
||||
let (app, visual) = cx.add_window_view(MyApp::new);
|
||||
|
||||
let api = AppApi::global();
|
||||
api.left_panel().open();
|
||||
@@ -859,10 +1132,10 @@ fn opened_panels_render_without_panicking(cx: &mut TestAppContext) {
|
||||
fn tree_block_renders_with_nested_nodes(cx: &mut TestAppContext) {
|
||||
cx.update(gpui_kit::init);
|
||||
|
||||
let (app, visual) = cx.add_window_view(|window, cx| MyApp::new(window, cx));
|
||||
let (app, visual) = cx.add_window_view(MyApp::new);
|
||||
|
||||
let api = AppApi::global();
|
||||
let tree = api.left_panel_handle().borrow_mut().add_tree();
|
||||
let tree = api.left_panel_handle().borrow_mut().add_tree(None);
|
||||
tree.borrow_mut()
|
||||
.append(
|
||||
"",
|
||||
@@ -898,14 +1171,54 @@ fn tree_block_renders_with_nested_nodes(cx: &mut TestAppContext) {
|
||||
assert_eq!(tree.borrow().rows().len(), 2);
|
||||
}
|
||||
|
||||
#[gpui_kit::test]
|
||||
fn bottom_panel_renders_blocks_as_tabs(cx: &mut TestAppContext) {
|
||||
cx.update(gpui_kit::init);
|
||||
|
||||
let (app, visual) = cx.add_window_view(MyApp::new);
|
||||
|
||||
let api = AppApi::global();
|
||||
let panel = api.bottom_panel_handle();
|
||||
panel
|
||||
.borrow_mut()
|
||||
.add_tree(Some("Диагностика".to_owned()))
|
||||
.borrow_mut()
|
||||
.append(
|
||||
"",
|
||||
vec![TreeNode {
|
||||
id: "a".to_owned(),
|
||||
label: "a".to_owned(),
|
||||
icon: Some("file".to_owned()),
|
||||
expandable: false,
|
||||
expanded: false,
|
||||
}],
|
||||
)
|
||||
.unwrap();
|
||||
panel.borrow_mut().add_tree(Some("Тесты".to_owned()));
|
||||
|
||||
assert_eq!(panel.borrow().active(), 1);
|
||||
assert_eq!(panel.borrow().blocks()[0].title(), "Диагностика");
|
||||
assert_eq!(panel.borrow().blocks()[1].title(), "Тесты");
|
||||
assert!(panel.borrow_mut().set_active(0));
|
||||
assert!(!panel.borrow_mut().set_active(2));
|
||||
|
||||
api.bottom_panel().open();
|
||||
visual.update(|_window, cx| {
|
||||
app.update(cx, |_, cx| cx.notify());
|
||||
});
|
||||
visual.run_until_parked();
|
||||
|
||||
assert!(api.bottom_panel_handle().borrow().is_open());
|
||||
}
|
||||
|
||||
#[gpui_kit::test]
|
||||
fn focused_tree_moves_selection_with_arrow_keys(cx: &mut TestAppContext) {
|
||||
cx.update(gpui_kit::init);
|
||||
|
||||
let (app, visual) = cx.add_window_view(|window, cx| MyApp::new(window, cx));
|
||||
let (app, visual) = cx.add_window_view(MyApp::new);
|
||||
|
||||
let api = AppApi::global();
|
||||
let tree = api.left_panel_handle().borrow_mut().add_tree();
|
||||
let tree = api.left_panel_handle().borrow_mut().add_tree(None);
|
||||
tree.borrow_mut()
|
||||
.append(
|
||||
"",
|
||||
@@ -953,6 +1266,62 @@ fn focused_tree_moves_selection_with_arrow_keys(cx: &mut TestAppContext) {
|
||||
assert_eq!(tree.borrow().selected(), Some("readme"));
|
||||
}
|
||||
|
||||
#[gpui_kit::test]
|
||||
fn lsp_diagnostics_are_underlined_in_editor(cx: &mut TestAppContext) {
|
||||
cx.update(gpui_kit::init);
|
||||
let (app, visual) = cx.add_window_view(MyApp::new);
|
||||
|
||||
let uri = visual.update(|window, cx| {
|
||||
app.update(cx, |this, cx| {
|
||||
this.editor_handle().update(cx, |state, cx| {
|
||||
state.set_value("abc\n", window, cx);
|
||||
});
|
||||
let name = this.workspace_handle().borrow().active().name.clone();
|
||||
crate::lsp::document_uri(&name).expect("у документа есть URI")
|
||||
})
|
||||
});
|
||||
|
||||
let diagnostic = |range: lsp_types::Range, severity| lsp_types::Diagnostic {
|
||||
range,
|
||||
severity: Some(severity),
|
||||
message: "сообщение".to_owned(),
|
||||
..Default::default()
|
||||
};
|
||||
let diagnostics = vec![
|
||||
diagnostic(
|
||||
lsp_types::Range::new(
|
||||
lsp_types::Position::new(0, 0),
|
||||
lsp_types::Position::new(0, 2),
|
||||
),
|
||||
lsp_types::DiagnosticSeverity::ERROR,
|
||||
),
|
||||
diagnostic(
|
||||
lsp_types::Range::new(
|
||||
lsp_types::Position::new(0, 2),
|
||||
lsp_types::Position::new(0, 3),
|
||||
),
|
||||
lsp_types::DiagnosticSeverity::WARNING,
|
||||
),
|
||||
];
|
||||
AppApi::global()
|
||||
.lsp_handle()
|
||||
.set_diagnostics_for_test(uri.as_str(), diagnostics);
|
||||
|
||||
let ranges = visual.update(|_window, cx| {
|
||||
app.update(cx, |this, cx| {
|
||||
this.refresh_diagnostics(cx);
|
||||
this.diagnostic_ranges(cx)
|
||||
})
|
||||
});
|
||||
visual.run_until_parked();
|
||||
|
||||
assert_eq!(
|
||||
ranges,
|
||||
vec![0..2, 2..3],
|
||||
"ошибка и предупреждение должны стать подчёркнутыми диапазонами"
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui_kit::test]
|
||||
fn typing_into_editor_updates_active_document(cx: &mut TestAppContext) {
|
||||
cx.update(gpui_kit::init);
|
||||
@@ -1117,8 +1486,11 @@ fn horizontal_arrows_close_completion_and_move_cursor(cx: &mut TestAppContext) {
|
||||
|
||||
let before = visual.update(|window, cx| {
|
||||
app.update(cx, |this, cx| {
|
||||
this.editor_handle()
|
||||
.update(cx, |state, cx| state.focus(window, cx));
|
||||
this.editor_handle().update(cx, |state, cx| {
|
||||
state.set_value("abc", window, cx);
|
||||
state.set_selected_range(0..0, cx);
|
||||
state.focus(window, cx);
|
||||
});
|
||||
this.open_test_completion(cx);
|
||||
this.editor_handle().read(cx).cursor()
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user