This commit is contained in:
2026-10-31 12:18:07 +03:00
parent 16e88117d5
commit e8e2d25600
9 changed files with 568 additions and 9 deletions
+138 -1
View File
@@ -8,7 +8,7 @@ use std::cell::RefCell;
use std::path::Path;
use std::rc::Rc;
use gpui_kit::{Keystroke, Modifiers, TestAppContext, px};
use gpui_kit::{Keystroke, Modifiers, TestAppContext, point, px};
use lsp_types::{Diagnostic, DiagnosticSeverity, Position, Range};
use crate::api::{AppApi, WindowCommand, drain_window_commands};
@@ -718,6 +718,55 @@ fn lua_diagnostics_handler_receives_every_server_and_file() {
let _ = std::fs::remove_dir_all(&dir);
}
#[test]
fn lua_app_open_input_queues_options() {
let workspace = Rc::new(RefCell::new(Workspace::default()));
let (api, _keymap) = install_api(workspace);
let requests = api.prompt_request_handle();
let dir = temp_script_dir("open-input");
let script = dir.join("input.lua");
std::fs::write(
&script,
r#"
app:open_input({ title = "Имя", placeholder = "main.rs", callback = function(text) end })
"#,
)
.expect("input.lua");
let engine = ScriptEngine::new(api).expect("движок Lua");
engine.run_file(&script).expect("app:open_input с опциями");
let request = requests.borrow_mut().take().expect("запрос на поле ввода");
assert_eq!(request.title.as_deref(), Some("Имя"));
assert_eq!(request.placeholder.as_deref(), Some("main.rs"));
assert!(request.callback.is_some());
// Без аргументов окно состоит из одной строки ввода, колбэка нет.
std::fs::write(&script, "app:open_input()\n").expect("input.lua");
engine.run_file(&script).expect("app:open_input()");
let request = requests.borrow_mut().take().expect("запрос без опций");
assert!(request.title.is_none());
assert!(request.placeholder.is_none());
assert!(request.callback.is_none());
// Некорректные типы опций — ошибка Lua, а не молчаливый пропуск.
std::fs::write(
&script,
r#"
assert(not pcall(function() app:open_input({ title = 1 }) end))
assert(not pcall(function() app:open_input({ placeholder = 1 }) end))
assert(not pcall(function() app:open_input({ callback = "x" }) end))
"#,
)
.expect("input.lua");
engine.run_file(&script).expect("проверка типов опций");
assert!(requests.borrow().is_none());
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()));
@@ -1789,6 +1838,94 @@ fn typing_into_editor_updates_active_document(cx: &mut TestAppContext) {
assert!(doc.is_dirty(), "правка должна помечать документ изменённым");
}
#[gpui_kit::test]
fn floating_input_blocks_keys_and_submits_on_enter(cx: &mut TestAppContext) {
cx.update(gpui_kit::init);
let mut workspace = None;
let (app, visual) = cx.add_window_view(|window, cx| {
let app = MyApp::new(window, cx);
workspace = Some(app.workspace_handle());
app
});
let workspace = workspace.expect("вид создан");
let dir = temp_script_dir("floating-input");
let keys = dir.join("keys.lua");
let open = dir.join("open.lua");
std::fs::write(
&keys,
r#"app:map_key("", "<A-r>", function() app.editor:set_active_text("blocked") end)"#,
)
.expect("keys.lua");
std::fs::write(
&open,
r#"
app:open_input({
title = "Имя",
placeholder = "main.rs",
callback = function(text) app.editor:set_active_text(text) end,
})
"#,
)
.expect("open.lua");
let engine = ScriptEngine::new(AppApi::global()).expect("движок Lua");
engine.run_file(&keys).expect("привязка");
engine.run_file(&open).expect("app:open_input");
let notify = |visual: &mut gpui_kit::VisualTestContext| {
visual.update(|_window, cx| {
app.update(cx, |_, cx| cx.notify());
});
visual.run_until_parked();
};
let prompt_open = |visual: &mut gpui_kit::VisualTestContext| {
visual.update(|_window, cx| app.read(cx).prompt_is_open())
};
notify(visual);
assert!(prompt_open(visual), "поле ввода должно открыться");
// Пока окно открыто, привязки приложения не срабатывают.
visual.simulate_keystrokes("alt-r");
visual.run_until_parked();
assert_eq!(workspace.borrow().active().content, "");
// Esc закрывает окно без колбэка.
visual.simulate_keystrokes("escape");
visual.run_until_parked();
assert!(!prompt_open(visual), "Esc должен закрыть поле ввода");
assert_eq!(workspace.borrow().active().content, "");
// Клик вне окна тоже закрывает его без колбэка.
engine.run_file(&open).expect("app:open_input повторно");
notify(visual);
assert!(prompt_open(visual));
visual.simulate_click(point(px(2.), px(2.)), Modifiers::default());
visual.run_until_parked();
assert!(
!prompt_open(visual),
"клик вне окна должен закрыть поле ввода"
);
assert_eq!(workspace.borrow().active().content, "");
// Enter подтверждает ввод и вызывает колбэк уже после закрытия окна.
engine.run_file(&open).expect("app:open_input в третий раз");
notify(visual);
assert!(prompt_open(visual));
visual.simulate_input("main.go");
visual.simulate_keystrokes("enter");
visual.run_until_parked();
assert!(!prompt_open(visual));
assert_eq!(workspace.borrow().active().content, "main.go");
drop(engine);
let _ = std::fs::remove_dir_all(&dir);
}
#[gpui_kit::test]
fn arrows_move_completion_selection_without_moving_cursor(cx: &mut TestAppContext) {
cx.update(gpui_kit::init);