use {
super::*,
crate::{testing::StubExecutor, types::ClientId},
reovim_kernel::{
api::v1::{HistoryRing, Jumplist, MarkBank, ModuleId, RegisterBank},
testing::test_mode,
},
};
fn test_mode_2() -> ModeId {
ModeId::with_discriminant(ModuleId::new("test"), "insert", 1)
}
use std::sync::Arc;
use crate::api::CommandHandle;
#[test]
fn test_mode_api() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut mode_stack = ModeStack::new(test_mode());
let mut windows = crate::WindowLayout::empty();
let mut extensions = crate::ExtensionMap::new();
let mut compositor = None;
let mut tabs = crate::TabPageSet::new();
let mut registers = RegisterBank::new();
let mut clipboard_history = HistoryRing::new();
let mut local_marks = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut runtime = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut mode_stack,
windows: &mut windows,
extensions: &mut extensions,
compositor: &mut compositor,
tabs: &mut tabs,
registers: &mut registers,
clipboard_history: &mut clipboard_history,
local_marks: &mut local_marks,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
assert_eq!(runtime.current_mode(), &test_mode());
assert_eq!(runtime.mode_depth(), 1);
assert!(runtime.is_mode_active(&test_mode()));
runtime.push_mode(test_mode_2(), TransitionContext::new());
assert_eq!(runtime.current_mode(), &test_mode_2());
assert_eq!(runtime.mode_depth(), 2);
let result = runtime.pop_mode(None);
assert!(result.is_ok());
assert_eq!(runtime.current_mode(), &test_mode());
let result = runtime.pop_mode(None);
assert!(matches!(result, Err(ModeError::CannotPopHomeMode)));
let changes = runtime.take_changes();
assert!(changes.mode_changed);
}
#[test]
fn test_per_client_mode_stack() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut client_mode_stack = ModeStack::new(test_mode());
let mut client_windows = crate::WindowLayout::empty();
let mut client_extensions = crate::ExtensionMap::new();
let mut client_compositor = None;
let mut tabs = crate::TabPageSet::new();
let mut client_registers = RegisterBank::new();
let mut client_clipboard_history = HistoryRing::new();
let mut client_local_marks = MarkBank::new();
let mut client_jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let session_home_mode = session.shared.home_mode().clone();
{
let mut runtime = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut client_mode_stack,
windows: &mut client_windows,
extensions: &mut client_extensions,
compositor: &mut client_compositor,
tabs: &mut tabs,
registers: &mut client_registers,
clipboard_history: &mut client_clipboard_history,
local_marks: &mut client_local_marks,
jumplist: &mut client_jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
assert_eq!(runtime.current_mode(), &test_mode());
runtime.push_mode(test_mode_2(), TransitionContext::new());
assert_eq!(runtime.current_mode(), &test_mode_2());
assert_eq!(runtime.mode_depth(), 2);
}
assert_eq!(session.shared.home_mode(), &session_home_mode);
assert_eq!(client_mode_stack.current(), &test_mode_2());
assert_eq!(client_mode_stack.depth(), 2);
}
#[test]
fn test_owner_tracking() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut client_stack = ModeStack::new(test_mode());
let mut client_windows = crate::WindowLayout::empty();
let mut client_extensions = crate::ExtensionMap::new();
let mut client_compositor = None;
let mut tabs = crate::TabPageSet::new();
let mut client_registers = RegisterBank::new();
let mut client_clipboard_history = HistoryRing::new();
let mut client_local_marks = MarkBank::new();
let mut client_jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
{
let runtime = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut client_stack,
windows: &mut client_windows,
extensions: &mut client_extensions,
compositor: &mut client_compositor,
tabs: &mut tabs,
registers: &mut client_registers,
clipboard_history: &mut client_clipboard_history,
local_marks: &mut client_local_marks,
jumplist: &mut client_jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
assert_eq!(runtime.owner(), None);
}
let client_id = ClientId::new(42);
{
let runtime = SessionRuntime::with_owner(
client_id,
&mut session,
crate::ClientContext {
mode_stack: &mut client_stack,
windows: &mut client_windows,
extensions: &mut client_extensions,
compositor: &mut client_compositor,
tabs: &mut tabs,
registers: &mut client_registers,
clipboard_history: &mut client_clipboard_history,
local_marks: &mut client_local_marks,
jumplist: &mut client_jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
assert_eq!(runtime.owner(), Some(client_id));
}
}
#[test]
fn test_multi_client_mode_isolation() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut client1_stack = ModeStack::new(test_mode());
let mut client1_windows = crate::WindowLayout::empty();
let mut client1_extensions = crate::ExtensionMap::new();
let mut client1_compositor = None;
let mut client1_registers = RegisterBank::new();
let mut client1_clipboard_history = HistoryRing::new();
let mut client1_local_marks = MarkBank::new();
let mut client1_jumplist = Jumplist::new();
let mut client2_stack = ModeStack::new(test_mode());
let mut client2_windows = crate::WindowLayout::empty();
let mut client2_extensions = crate::ExtensionMap::new();
let mut client2_compositor = None;
let mut tabs = crate::TabPageSet::new();
let mut client2_registers = RegisterBank::new();
let mut client2_clipboard_history = HistoryRing::new();
let mut client2_local_marks = MarkBank::new();
let mut client2_jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
{
let mut runtime1 = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut client1_stack,
windows: &mut client1_windows,
extensions: &mut client1_extensions,
compositor: &mut client1_compositor,
tabs: &mut tabs,
registers: &mut client1_registers,
clipboard_history: &mut client1_clipboard_history,
local_marks: &mut client1_local_marks,
jumplist: &mut client1_jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
runtime1.push_mode(test_mode_2(), TransitionContext::new());
}
{
let runtime2 = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut client2_stack,
windows: &mut client2_windows,
extensions: &mut client2_extensions,
compositor: &mut client2_compositor,
tabs: &mut tabs,
registers: &mut client2_registers,
clipboard_history: &mut client2_clipboard_history,
local_marks: &mut client2_local_marks,
jumplist: &mut client2_jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
assert_eq!(runtime2.current_mode(), &test_mode());
}
assert_eq!(client1_stack.current(), &test_mode_2()); assert_eq!(client2_stack.current(), &test_mode()); }
#[test]
fn test_window_api() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut mode_stack = ModeStack::new(test_mode());
let mut windows = crate::WindowLayout::empty();
let mut extensions = crate::ExtensionMap::new();
let mut compositor = None;
let mut tabs = crate::TabPageSet::new();
let mut registers = RegisterBank::new();
let mut clipboard_history = HistoryRing::new();
let mut local_marks = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut runtime = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut mode_stack,
windows: &mut windows,
extensions: &mut extensions,
compositor: &mut compositor,
tabs: &mut tabs,
registers: &mut registers,
clipboard_history: &mut clipboard_history,
local_marks: &mut local_marks,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
let window_id = runtime.create_window(None);
assert_eq!(runtime.window_count(), 1);
assert_eq!(runtime.active_window(), Some(window_id));
let result = runtime.close_window(window_id);
assert!(matches!(result, Err(WindowError::CannotCloseLastWindow)));
let window_id2 = runtime.create_window(None);
assert_eq!(runtime.window_count(), 2);
let result = runtime.focus_window(window_id2);
assert!(result.is_ok());
let result = runtime.close_window(window_id);
assert!(result.is_ok());
assert_eq!(runtime.window_count(), 1);
let changes = runtime.take_changes();
assert!(changes.window_changed);
assert!(!changes.windows_created.is_empty());
}
#[test]
#[cfg_attr(coverage_nightly, coverage(off))]
fn test_extension_api() {
use reovim_kernel::api::v1::ModeStack;
#[derive(Debug, Default)]
struct TestExtension {
value: i32,
}
impl SessionExtension for TestExtension {
fn create() -> Self {
Self { value: 42 }
}
}
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut mode_stack = ModeStack::new(test_mode());
let mut windows = crate::WindowLayout::empty();
let mut extensions = crate::ExtensionMap::new();
let mut compositor = None;
let mut tabs = crate::TabPageSet::new();
let mut registers = RegisterBank::new();
let mut clipboard_history = HistoryRing::new();
let mut local_marks = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut runtime = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut mode_stack,
windows: &mut windows,
extensions: &mut extensions,
compositor: &mut compositor,
tabs: &mut tabs,
registers: &mut registers,
clipboard_history: &mut clipboard_history,
local_marks: &mut local_marks,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
assert!(runtime.ext::<TestExtension>().is_none());
let ext = runtime.ext_mut::<TestExtension>();
assert_eq!(ext.value, 42);
ext.value = 100;
assert_eq!(runtime.ext::<TestExtension>().unwrap().value, 100);
}
#[test]
fn test_shared_ext_without_shared_extensions_returns_none() {
use reovim_kernel::api::v1::ModeStack;
#[derive(Debug)]
struct SharedTestExt;
impl SessionExtension for SharedTestExt {
fn create() -> Self {
Self
}
}
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut mode_stack = ModeStack::new(test_mode());
let mut windows = crate::WindowLayout::empty();
let mut extensions = crate::ExtensionMap::new();
let mut compositor = None;
let mut tabs = crate::TabPageSet::new();
let mut registers = RegisterBank::new();
let mut clipboard_history = HistoryRing::new();
let mut local_marks = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let runtime = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut mode_stack,
windows: &mut windows,
extensions: &mut extensions,
compositor: &mut compositor,
tabs: &mut tabs,
registers: &mut registers,
clipboard_history: &mut clipboard_history,
local_marks: &mut local_marks,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
assert!(runtime.shared_ext::<SharedTestExt>().is_none());
}
#[test]
fn test_shared_ext_mut_without_shared_extensions_returns_none() {
use reovim_kernel::api::v1::ModeStack;
#[derive(Debug)]
struct SharedTestExt2 {
_value: i32,
}
impl SessionExtension for SharedTestExt2 {
fn create() -> Self {
Self { _value: 0 }
}
}
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut mode_stack = ModeStack::new(test_mode());
let mut windows = crate::WindowLayout::empty();
let mut extensions = crate::ExtensionMap::new();
let mut compositor = None;
let mut tabs = crate::TabPageSet::new();
let mut registers = RegisterBank::new();
let mut clipboard_history = HistoryRing::new();
let mut local_marks = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut runtime = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut mode_stack,
windows: &mut windows,
extensions: &mut extensions,
compositor: &mut compositor,
tabs: &mut tabs,
registers: &mut registers,
clipboard_history: &mut clipboard_history,
local_marks: &mut local_marks,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
assert!(runtime.shared_ext_mut::<SharedTestExt2>().is_none());
}
#[test]
fn test_shared_ext_with_shared_extensions_returns_value() {
use reovim_kernel::api::v1::ModeStack;
#[derive(Debug)]
struct SharedTestExt3 {
value: i32,
}
impl SessionExtension for SharedTestExt3 {
fn create() -> Self {
Self { value: 99 }
}
}
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut mode_stack = ModeStack::new(test_mode());
let mut windows = crate::WindowLayout::empty();
let mut extensions = crate::ExtensionMap::new();
let mut shared_extensions = crate::ExtensionMap::new();
let mut compositor = None;
let mut tabs = crate::TabPageSet::new();
let mut registers = RegisterBank::new();
let mut clipboard_history = HistoryRing::new();
let mut local_marks = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
shared_extensions.get_or_insert::<SharedTestExt3>();
let runtime = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut mode_stack,
windows: &mut windows,
extensions: &mut extensions,
compositor: &mut compositor,
tabs: &mut tabs,
registers: &mut registers,
clipboard_history: &mut clipboard_history,
local_marks: &mut local_marks,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
)
.with_shared_extensions(&mut shared_extensions);
let ext = runtime.shared_ext::<SharedTestExt3>();
assert!(ext.is_some());
assert_eq!(ext.unwrap().value, 99);
}
#[test]
fn test_shared_ext_mut_creates_and_returns() {
use reovim_kernel::api::v1::ModeStack;
#[derive(Debug)]
struct SharedTestExt4 {
value: i32,
}
impl SessionExtension for SharedTestExt4 {
fn create() -> Self {
Self { value: 77 }
}
}
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut mode_stack = ModeStack::new(test_mode());
let mut windows = crate::WindowLayout::empty();
let mut extensions = crate::ExtensionMap::new();
let mut shared_extensions = crate::ExtensionMap::new();
let mut compositor = None;
let mut tabs = crate::TabPageSet::new();
let mut registers = RegisterBank::new();
let mut clipboard_history = HistoryRing::new();
let mut local_marks = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut runtime = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut mode_stack,
windows: &mut windows,
extensions: &mut extensions,
compositor: &mut compositor,
tabs: &mut tabs,
registers: &mut registers,
clipboard_history: &mut clipboard_history,
local_marks: &mut local_marks,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
)
.with_shared_extensions(&mut shared_extensions);
let ext = runtime.shared_ext_mut::<SharedTestExt4>();
assert!(ext.is_some());
let ext = ext.unwrap();
assert_eq!(ext.value, 77);
ext.value = 200;
assert_eq!(runtime.shared_ext::<SharedTestExt4>().unwrap().value, 200);
}
#[test]
fn test_shared_ext_default_trait_returns_none() {
struct MinimalApi;
#[derive(Debug)]
struct AnyExt;
impl SessionExtension for AnyExt {
fn create() -> Self {
Self
}
}
impl ExtensionApi for MinimalApi {
fn ext<T: SessionExtension>(&self) -> Option<&T> {
None
}
fn ext_mut<T: SessionExtension>(&mut self) -> &mut T {
unimplemented!()
}
}
let api = MinimalApi;
assert!(api.shared_ext::<AnyExt>().is_none());
}
#[test]
fn test_shared_ext_mut_default_trait_returns_none() {
struct MinimalApi2;
#[derive(Debug)]
struct AnyExt2;
impl SessionExtension for AnyExt2 {
fn create() -> Self {
Self
}
}
impl ExtensionApi for MinimalApi2 {
fn ext<T: SessionExtension>(&self) -> Option<&T> {
None
}
fn ext_mut<T: SessionExtension>(&mut self) -> &mut T {
unimplemented!()
}
}
let mut api = MinimalApi2;
assert!(api.shared_ext_mut::<AnyExt2>().is_none());
}
#[test]
fn test_change_tracking() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut mode_stack = ModeStack::new(test_mode());
let mut windows = crate::WindowLayout::empty();
let mut extensions = crate::ExtensionMap::new();
let mut compositor = None;
let mut tabs = crate::TabPageSet::new();
let mut registers = RegisterBank::new();
let mut clipboard_history = HistoryRing::new();
let mut local_marks = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut runtime = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut mode_stack,
windows: &mut windows,
extensions: &mut extensions,
compositor: &mut compositor,
tabs: &mut tabs,
registers: &mut registers,
clipboard_history: &mut clipboard_history,
local_marks: &mut local_marks,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
assert!(!runtime.changes.has_changes());
runtime.push_mode(test_mode_2(), TransitionContext::new());
assert!(runtime.changes.mode_changed);
let changes = runtime.take_changes();
assert!(changes.mode_changed);
assert!(!runtime.changes.has_changes());
}
#[test]
fn test_buffer_text_range_single_line() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("hello world");
let buffer_id = harness.with_runtime(|runtime| runtime.active_buffer().unwrap());
let result = harness.with_runtime(|runtime| {
runtime.buffer_text_range(buffer_id, Position::new(0, 2), Position::new(0, 8))
});
assert_eq!(result, Some("llo wo".to_string()));
}
#[test]
fn test_buffer_text_range_multi_line() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("line one\nline two\nline three");
let buffer_id = harness.with_runtime(|runtime| runtime.active_buffer().unwrap());
let result = harness.with_runtime(|runtime| {
runtime.buffer_text_range(buffer_id, Position::new(0, 5), Position::new(2, 4))
});
assert_eq!(result, Some("one\nline two\nline".to_string()));
let result = harness.with_runtime(|runtime| {
runtime.buffer_text_range(buffer_id, Position::new(0, 0), Position::new(1, 0))
});
assert_eq!(result, Some("line one\n".to_string()));
}
#[test]
fn test_buffer_line_api() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("hello\nworld\nfoo");
let buffer_id = harness.with_runtime(|runtime| runtime.active_buffer().unwrap());
harness.with_runtime(|runtime| {
assert_eq!(runtime.buffer_line(buffer_id, 0), Some("hello".to_string()));
assert_eq!(runtime.buffer_line(buffer_id, 1), Some("world".to_string()));
assert_eq!(runtime.buffer_line(buffer_id, 2), Some("foo".to_string()));
assert!(runtime.buffer_line(buffer_id, 99).is_none());
});
}
#[test]
fn test_buffer_line_count_api() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("hello\nworld\nfoo");
let buffer_id = harness.with_runtime(|runtime| runtime.active_buffer().unwrap());
let count = harness.with_runtime(|runtime| runtime.buffer_line_count(buffer_id));
assert_eq!(count, Some(3));
}
#[test]
fn test_buffer_content_api() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("hello world");
let buffer_id = harness.with_runtime(|runtime| runtime.active_buffer().unwrap());
let content = harness.with_runtime(|runtime| runtime.buffer_content(buffer_id));
assert_eq!(content, Some("hello world".to_string()));
}
#[test]
fn test_buffer_nonexistent() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("test");
let fake_id = BufferId::new();
harness.with_runtime(|runtime| {
assert!(runtime.buffer_line(fake_id, 0).is_none());
assert!(runtime.buffer_line_count(fake_id).is_none());
assert!(runtime.buffer_content(fake_id).is_none());
assert!(runtime.buffer_file_path(fake_id).is_none());
assert!(runtime.is_buffer_modified(fake_id).is_none());
assert!(
runtime
.buffer_text_range(fake_id, Position::new(0, 0), Position::new(0, 5))
.is_none()
);
});
}
#[test]
fn test_buffer_file_path_none() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("test");
let buffer_id = harness.with_runtime(|runtime| runtime.active_buffer().unwrap());
let path = harness.with_runtime(|runtime| runtime.buffer_file_path(buffer_id));
assert!(path.is_none());
}
#[test]
fn test_buffer_modified_flag() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("hello");
let buffer_id = harness.with_runtime(|runtime| runtime.active_buffer().unwrap());
let modified = harness.with_runtime(|runtime| runtime.is_buffer_modified(buffer_id));
assert_eq!(modified, Some(false));
harness.with_runtime(|runtime| {
runtime.set_buffer_modified(buffer_id, true);
});
let modified = harness.with_runtime(|runtime| runtime.is_buffer_modified(buffer_id));
assert_eq!(modified, Some(true));
harness.with_runtime(|runtime| {
runtime.set_buffer_modified(buffer_id, false);
});
let modified = harness.with_runtime(|runtime| runtime.is_buffer_modified(buffer_id));
assert_eq!(modified, Some(false));
}
#[test]
fn test_set_buffer_modified_nonexistent() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
let fake_id = BufferId::new();
harness.with_runtime(|runtime| {
runtime.set_buffer_modified(fake_id, true);
});
}
#[test]
fn test_insert_text_api() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("helloworld");
let buffer_id = harness.with_runtime(|runtime| runtime.active_buffer().unwrap());
harness.with_runtime(|runtime| {
runtime.insert_text(buffer_id, Position::new(0, 5), " ");
});
harness.assert_buffer_content("hello world");
let changes = harness.take_changes();
assert!(changes.buffer_modified);
}
#[test]
fn test_insert_text_nonexistent_buffer() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
let fake_id = BufferId::new();
harness.with_runtime(|runtime| {
runtime.insert_text(fake_id, Position::new(0, 0), "text");
});
}
#[test]
fn test_delete_range_api() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("hello world");
let buffer_id = harness.with_runtime(|runtime| runtime.active_buffer().unwrap());
harness.with_runtime(|runtime| {
runtime.delete_range(buffer_id, Position::new(0, 5), Position::new(0, 11));
});
harness.assert_buffer_content("hello");
let changes = harness.take_changes();
assert!(changes.buffer_modified);
}
#[test]
fn test_delete_range_nonexistent_buffer() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
let fake_id = BufferId::new();
harness.with_runtime(|runtime| {
runtime.delete_range(fake_id, Position::new(0, 0), Position::new(0, 5));
});
}
#[test]
fn test_create_buffer_unnamed() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
let buf_id = harness.with_runtime(|runtime| runtime.create_buffer(None, "content"));
let content = harness.with_runtime(|runtime| runtime.buffer_content(buf_id));
assert_eq!(content, Some("content".to_string()));
let path = harness.with_runtime(|runtime| runtime.buffer_file_path(buf_id));
assert!(path.is_none());
let changes = harness.take_changes();
assert!(changes.buffers_created.contains(&buf_id));
}
#[test]
fn test_create_buffer_named() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
let buf_id = harness.with_runtime(|runtime| runtime.create_buffer(Some("test.txt"), "hello"));
let path = harness.with_runtime(|runtime| runtime.buffer_file_path(buf_id));
assert_eq!(path, Some("test.txt".to_string()));
}
#[test]
fn test_rename_buffer_api() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
let buf_id = harness.with_runtime(|runtime| runtime.create_buffer(Some("old.txt"), "content"));
harness.take_changes();
harness.with_runtime(|runtime| {
runtime.rename_buffer(buf_id, "new.txt");
});
let path = harness.with_runtime(|runtime| runtime.buffer_file_path(buf_id));
assert_eq!(path, Some("new.txt".to_string()));
let changes = harness.take_changes();
assert!(!changes.buffers_renamed.is_empty());
assert_eq!(changes.buffers_renamed[0].1, "new.txt");
}
#[test]
fn test_rename_nonexistent_buffer() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
let fake_id = BufferId::new();
harness.with_runtime(|runtime| {
runtime.rename_buffer(fake_id, "new.txt");
});
}
#[test]
fn test_replace_content_updates_buffer() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("original content");
let buffer_id = harness.active_buffer().unwrap();
harness.with_runtime(|runtime| {
runtime.replace_content(buffer_id, "formatted content");
});
harness.assert_buffer_content("formatted content");
}
#[test]
fn test_replace_content_marks_modified() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("original");
let buffer_id = harness.active_buffer().unwrap();
harness
.kernel()
.buffers
.get(buffer_id)
.unwrap()
.write()
.set_modified(false);
harness.with_runtime(|runtime| {
runtime.replace_content(buffer_id, "new content");
});
let is_modified = harness
.kernel()
.buffers
.get(buffer_id)
.unwrap()
.read()
.is_modified();
assert!(is_modified);
}
#[test]
fn test_replace_content_records_changes() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("before");
let buffer_id = harness.active_buffer().unwrap();
harness.take_changes();
harness.with_runtime(|runtime| {
runtime.replace_content(buffer_id, "after");
});
let changes = harness.take_changes();
assert!(changes.buffer_modified);
}
#[test]
fn test_replace_content_nonexistent_buffer() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
let fake_id = BufferId::new();
harness.with_runtime(|runtime| {
runtime.replace_content(fake_id, "anything");
});
}
#[test]
fn test_delete_buffer_api() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
let buf1 = harness.with_runtime(|runtime| runtime.create_buffer(None, "first"));
let buf2 = harness.with_runtime(|runtime| runtime.create_buffer(None, "second"));
harness.take_changes();
let result = harness.with_runtime(|runtime| runtime.delete_buffer(buf1));
assert!(result.is_ok());
let content = harness.with_runtime(|runtime| runtime.buffer_content(buf1));
assert!(content.is_none());
let content = harness.with_runtime(|runtime| runtime.buffer_content(buf2));
assert_eq!(content, Some("second".to_string()));
let changes = harness.take_changes();
assert!(changes.buffers_deleted.contains(&buf1));
}
#[test]
fn test_delete_last_buffer_fails() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("only buffer");
let buffer_id = harness.with_runtime(|runtime| runtime.active_buffer().unwrap());
let result = harness.with_runtime(|runtime| runtime.delete_buffer(buffer_id));
assert!(matches!(result, Err(BufferError::CannotDeleteLastBuffer)));
}
#[test]
fn test_delete_nonexistent_buffer() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
harness.with_runtime(|runtime| runtime.create_buffer(None, "first"));
harness.with_runtime(|runtime| runtime.create_buffer(None, "second"));
let fake_id = BufferId::new();
let result = harness.with_runtime(|runtime| runtime.delete_buffer(fake_id));
assert!(matches!(result, Err(BufferError::NotFound(_))));
}
#[test]
fn test_window_buffer_api() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("hello");
let buffer_id = harness.with_runtime(|runtime| runtime.active_buffer().unwrap());
let window_id = harness.with_runtime(|runtime| runtime.active_window().unwrap());
let buf = harness.with_runtime(|runtime| runtime.window_buffer(window_id));
assert_eq!(buf, Some(buffer_id));
}
#[test]
fn test_window_buffer_nonexistent() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("hello");
let fake_id = WindowId::new();
let buf = harness.with_runtime(|runtime| runtime.window_buffer(fake_id));
assert!(buf.is_none());
}
#[test]
fn test_cursor_position_api() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("hello");
let pos = harness.with_runtime(|runtime| runtime.cursor_position());
assert_eq!(pos, Some(Position::new(0, 0)));
}
#[test]
fn test_cursor_position_no_window() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
let pos = harness.with_runtime(|runtime| runtime.cursor_position());
assert!(pos.is_none());
}
#[test]
fn test_focus_nonexistent_window() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("test");
let fake_id = WindowId::new();
let result = harness.with_runtime(|runtime| runtime.focus_window(fake_id));
assert!(matches!(result, Err(WindowError::NotFound(_))));
}
#[test]
fn test_close_nonexistent_window() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("test");
let _w1 = harness.with_runtime(|runtime| runtime.create_window(None));
let fake_id = WindowId::new();
let result = harness.with_runtime(|runtime| runtime.close_window(fake_id));
assert!(matches!(result, Err(WindowError::NotFound(_))));
}
#[test]
fn test_set_window_buffer_api() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("hello");
let window_id = harness.with_runtime(|runtime| runtime.active_window().unwrap());
let new_buf = harness.with_runtime(|runtime| runtime.create_buffer(None, "world"));
let result = harness.with_runtime(|runtime| runtime.set_window_buffer(window_id, new_buf));
assert!(result.is_ok());
let buf = harness.with_runtime(|runtime| runtime.window_buffer(window_id));
assert_eq!(buf, Some(new_buf));
}
#[test]
fn test_set_window_buffer_nonexistent_window() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("hello");
let buf_id = harness.with_runtime(|runtime| runtime.active_buffer().unwrap());
let fake_win = WindowId::new();
let result = harness.with_runtime(|runtime| runtime.set_window_buffer(fake_win, buf_id));
assert!(matches!(result, Err(WindowError::NotFound(_))));
}
#[test]
fn test_set_window_buffer_nonexistent_buffer() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("hello");
let window_id = harness.with_runtime(|runtime| runtime.active_window().unwrap());
let fake_buf = BufferId::new();
let result = harness.with_runtime(|runtime| runtime.set_window_buffer(window_id, fake_buf));
assert!(matches!(result, Err(WindowError::BufferNotFound(_))));
}
#[test]
fn test_set_active_selection() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("hello world");
let sel = harness.with_runtime(|runtime| runtime.active_selection().cloned());
assert!(sel.is_none());
let selection = Selection::character(Position::new(0, 0), Position::new(0, 5));
harness.with_runtime(|runtime| {
runtime.set_active_selection(Some(selection.clone()));
});
let sel = harness.with_runtime(|runtime| runtime.active_selection().cloned());
assert_eq!(sel.as_ref(), Some(&selection));
harness.with_runtime(|runtime| {
runtime.set_active_selection(None);
});
let sel = harness.with_runtime(|runtime| runtime.active_selection().cloned());
assert!(sel.is_none());
}
#[test]
fn test_active_selection_no_window() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
let sel = harness.with_runtime(|runtime| runtime.active_selection().cloned());
assert!(sel.is_none());
harness.with_runtime(|runtime| {
runtime.set_active_selection(Some(Selection::character(
Position::new(0, 0),
Position::new(0, 1),
)));
});
}
#[test]
fn test_mode_stack_api() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
let stack = harness.with_runtime(|runtime| runtime.mode_stack());
assert_eq!(stack.len(), 1);
harness.with_runtime(|runtime| {
runtime.push_mode(test_mode_2(), TransitionContext::new());
});
let stack = harness.with_runtime(|runtime| runtime.mode_stack());
assert_eq!(stack.len(), 2);
assert_eq!(stack[0], test_mode());
assert_eq!(stack[1], test_mode_2());
}
#[test]
fn test_set_mode_api() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
harness.with_runtime(|runtime| {
runtime.set_mode(test_mode_2(), TransitionContext::new());
});
let current = harness.with_runtime(|runtime| runtime.current_mode().clone());
assert_eq!(current, test_mode_2());
let depth = harness.with_runtime(|runtime| runtime.mode_depth());
assert_eq!(depth, 1); }
#[test]
fn test_is_mode_active_api() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
assert!(harness.with_runtime(|runtime| runtime.is_mode_active(&test_mode())));
assert!(!harness.with_runtime(|runtime| runtime.is_mode_active(&test_mode_2())));
harness.with_runtime(|runtime| {
runtime.push_mode(test_mode_2(), TransitionContext::new());
});
assert!(harness.with_runtime(|runtime| runtime.is_mode_active(&test_mode())));
assert!(harness.with_runtime(|runtime| runtime.is_mode_active(&test_mode_2())));
}
#[test]
fn test_home_mode_api() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
let home = harness.with_runtime(|runtime| runtime.home_mode().clone());
assert_eq!(home, test_mode());
harness.with_runtime(|runtime| {
runtime.push_mode(test_mode_2(), TransitionContext::new());
});
let home = harness.with_runtime(|runtime| runtime.home_mode().clone());
assert_eq!(home, test_mode());
}
#[test]
fn test_has_compositor_false() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut mode_stack = ModeStack::new(test_mode());
let mut windows = crate::WindowLayout::empty();
let mut extensions = crate::ExtensionMap::new();
let mut compositor = None;
let mut tabs = crate::TabPageSet::new();
let mut registers = RegisterBank::new();
let mut clipboard_history = HistoryRing::new();
let mut local_marks = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let runtime = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut mode_stack,
windows: &mut windows,
extensions: &mut extensions,
compositor: &mut compositor,
tabs: &mut tabs,
registers: &mut registers,
clipboard_history: &mut clipboard_history,
local_marks: &mut local_marks,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
assert!(!runtime.has_compositor());
}
#[test]
fn test_session_accessor() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut mode_stack = ModeStack::new(test_mode());
let mut windows = crate::WindowLayout::empty();
let mut extensions = crate::ExtensionMap::new();
let mut compositor = None;
let mut tabs = crate::TabPageSet::new();
let mut registers = RegisterBank::new();
let mut clipboard_history = HistoryRing::new();
let mut local_marks = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let runtime = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut mode_stack,
windows: &mut windows,
extensions: &mut extensions,
compositor: &mut compositor,
tabs: &mut tabs,
registers: &mut registers,
clipboard_history: &mut clipboard_history,
local_marks: &mut local_marks,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
assert_eq!(runtime.session().id.as_usize(), 1);
}
#[test]
fn test_session_mut_accessor() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut mode_stack = ModeStack::new(test_mode());
let mut windows = crate::WindowLayout::empty();
let mut extensions = crate::ExtensionMap::new();
let mut compositor = None;
let mut tabs = crate::TabPageSet::new();
let mut registers = RegisterBank::new();
let mut clipboard_history = HistoryRing::new();
let mut local_marks = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut runtime = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut mode_stack,
windows: &mut windows,
extensions: &mut extensions,
compositor: &mut compositor,
tabs: &mut tabs,
registers: &mut registers,
clipboard_history: &mut clipboard_history,
local_marks: &mut local_marks,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
let session_ref = runtime.session_mut();
assert_eq!(session_ref.id.as_usize(), 1);
}
#[test]
fn test_kernel_accessor() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut mode_stack = ModeStack::new(test_mode());
let mut windows = crate::WindowLayout::empty();
let mut extensions = crate::ExtensionMap::new();
let mut compositor = None;
let mut tabs = crate::TabPageSet::new();
let mut registers = RegisterBank::new();
let mut clipboard_history = HistoryRing::new();
let mut local_marks = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let runtime = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut mode_stack,
windows: &mut windows,
extensions: &mut extensions,
compositor: &mut compositor,
tabs: &mut tabs,
registers: &mut registers,
clipboard_history: &mut clipboard_history,
local_marks: &mut local_marks,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
let _kernel = runtime.kernel();
}
#[test]
fn test_windows_accessor() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut mode_stack = ModeStack::new(test_mode());
let mut windows = crate::WindowLayout::empty();
let mut extensions = crate::ExtensionMap::new();
let mut compositor = None;
let mut tabs = crate::TabPageSet::new();
let mut registers = RegisterBank::new();
let mut clipboard_history = HistoryRing::new();
let mut local_marks = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let runtime = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut mode_stack,
windows: &mut windows,
extensions: &mut extensions,
compositor: &mut compositor,
tabs: &mut tabs,
registers: &mut registers,
clipboard_history: &mut clipboard_history,
local_marks: &mut local_marks,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
assert!(runtime.windows().is_empty());
}
#[test]
fn test_windows_mut_accessor() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut mode_stack = ModeStack::new(test_mode());
let mut windows = crate::WindowLayout::empty();
let mut extensions = crate::ExtensionMap::new();
let mut compositor = None;
let mut tabs = crate::TabPageSet::new();
let mut registers = RegisterBank::new();
let mut clipboard_history = HistoryRing::new();
let mut local_marks = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut runtime = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut mode_stack,
windows: &mut windows,
extensions: &mut extensions,
compositor: &mut compositor,
tabs: &mut tabs,
registers: &mut registers,
clipboard_history: &mut clipboard_history,
local_marks: &mut local_marks,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
runtime.windows_mut().add(crate::Window::new());
assert_eq!(runtime.windows().len(), 1);
}
#[test]
fn test_execute_command_api() {
use {
crate::testing::TestSessionRuntime, reovim_driver_command_types::CommandContext,
reovim_kernel::api::v1::ModuleId,
};
let mut harness = TestSessionRuntime::new();
let cmd = CommandId::new(ModuleId::new("test"), "test_cmd");
let result =
harness.with_runtime(|runtime| runtime.execute_command(cmd, CommandContext::new()));
assert!(matches!(result, reovim_driver_command_types::CommandResult::Error(_)));
}
#[test]
fn test_with_buffer_read() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("hello world");
let buffer_id = harness.with_runtime(|runtime| runtime.active_buffer().unwrap());
let line_count = harness.with_runtime(|runtime| {
runtime.with_buffer_read(buffer_id, reovim_kernel::api::v1::Buffer::line_count)
});
assert_eq!(line_count, Some(1));
}
#[test]
fn test_with_buffer_read_nonexistent() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
let fake_id = BufferId::new();
let result = harness.with_runtime(|runtime| {
runtime.with_buffer_read(fake_id, reovim_kernel::api::v1::Buffer::line_count)
});
assert!(result.is_none());
}
#[test]
fn test_record_global_option_change() {
use {crate::testing::TestSessionRuntime, reovim_kernel::api::v1::OptionValue};
let mut harness = TestSessionRuntime::new();
harness.with_runtime(|runtime| {
runtime.record_global_option_change("number", OptionValue::bool(true));
});
let changes = harness.take_changes();
assert!(changes.option_changed);
assert_eq!(changes.options_changed.len(), 1);
assert_eq!(changes.options_changed[0].name, "number");
}
#[test]
fn test_record_window_option_change() {
use {crate::testing::TestSessionRuntime, reovim_kernel::api::v1::OptionValue};
let mut harness = TestSessionRuntime::with_buffer("test");
let window_id = harness.with_runtime(|runtime| runtime.active_window().unwrap());
harness.with_runtime(|runtime| {
runtime.record_window_option_change("wrap", OptionValue::bool(false), window_id);
});
let changes = harness.take_changes();
assert!(changes.option_changed);
assert_eq!(changes.options_changed.len(), 1);
assert_eq!(changes.options_changed[0].window_id, Some(window_id));
}
#[test]
fn test_change_tracker_record_cursor_move() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("test");
let buffer_id = harness.with_runtime(|runtime| runtime.active_buffer().unwrap());
harness.with_runtime(|runtime| {
ChangeTracker::record_cursor_move(runtime, buffer_id);
});
let changes = harness.take_changes();
assert!(changes.cursor_moved);
assert!(changes.affected_buffers.contains(&buffer_id));
}
#[test]
fn test_can_undo_without_provider() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("test");
let buffer_id = harness.with_runtime(|runtime| runtime.active_buffer().unwrap());
let can_undo = harness.with_runtime(|runtime| runtime.can_undo(buffer_id));
assert!(!can_undo);
let can_redo = harness.with_runtime(|runtime| runtime.can_redo(buffer_id));
assert!(!can_redo);
}
#[test]
fn test_undo_without_provider() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("test");
let buffer_id = harness.with_runtime(|runtime| runtime.active_buffer().unwrap());
let result = harness.with_runtime(|runtime| runtime.undo(buffer_id));
assert!(result.is_none());
let result = harness.with_runtime(|runtime| runtime.redo(buffer_id));
assert!(result.is_none());
}
#[test]
fn test_undo_mine_without_owner() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("test");
let buffer_id = harness.with_runtime(|runtime| runtime.active_buffer().unwrap());
let result = harness.with_runtime(|runtime| runtime.undo_mine(buffer_id));
assert!(result.is_none());
let result = harness.with_runtime(|runtime| runtime.redo_mine(buffer_id));
assert!(result.is_none());
}
#[test]
fn test_numbered_register_writes_ignored() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
harness.with_runtime(|runtime| {
runtime.set_register(Some('0'), crate::api::RegisterContent::characterwise("test"));
let content = runtime.get_register(Some('0'));
assert!(content.is_none());
});
}
#[test]
fn test_clipboard_register_without_provider() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
harness.with_runtime(|runtime| {
runtime.set_register(Some('+'), crate::api::RegisterContent::characterwise("clipboard"));
let content = runtime.get_register(Some('+'));
assert!(content.is_none()); });
}
#[test]
fn test_selection_register_without_provider() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
harness.with_runtime(|runtime| {
runtime.set_register(Some('*'), crate::api::RegisterContent::characterwise("selection"));
let content = runtime.get_register(Some('*'));
assert!(content.is_none()); });
}
#[test]
fn test_compositor_api_no_compositor() {
use {
crate::testing::TestSessionRuntime,
reovim_driver_layout::{NavigateDirection, Rect, SplitDirection},
};
let mut harness = TestSessionRuntime::new();
harness.with_runtime(|runtime| {
assert!(runtime.navigate(NavigateDirection::Left).is_err());
assert!(runtime.split(SplitDirection::Horizontal).is_err());
assert!(runtime.close_current_window().is_err());
assert!(runtime.close_others().is_err());
assert!(runtime.resize(NavigateDirection::Right, 5).is_err());
assert!(runtime.equalize().is_err());
assert!(runtime.cycle(true).is_err());
assert!(runtime.toggle_float().is_err());
assert!(runtime.raise_float().is_err());
assert!(runtime.lower_float().is_err());
assert!(runtime.hide_all_overlays().is_err());
assert!(runtime.set_active_layer_opacity(0.5).is_err());
assert!(runtime.active_layer_opacity().is_err());
assert!(runtime.adjust_active_layer_opacity(0.1).is_err());
assert!(runtime.tab_new().is_ok()); assert!(runtime.tab_close().is_ok()); assert!(runtime.tab_close().is_err()); assert!(runtime.tab_next().is_ok()); assert!(runtime.tab_prev().is_ok()); assert!(runtime.tab_goto(0).is_ok()); assert!(runtime.tab_goto(99).is_err()); assert_eq!(runtime.tab_count(), 1);
assert!(runtime.active_tab_id().is_some());
assert!(runtime.focused_window().is_none());
assert_eq!(runtime.compositor_window_count(), 0);
assert!(runtime.active_layer().is_none());
assert!(runtime.arrange(Rect::new(0, 0, 80, 24)).is_empty());
});
}
#[test]
fn test_set_screen_no_compositor() {
use {crate::testing::TestSessionRuntime, reovim_driver_layout::Rect};
let mut harness = TestSessionRuntime::new();
harness.with_runtime(|runtime| {
runtime.set_screen(Rect::new(0, 0, 120, 40));
});
}
#[test]
fn test_buffer_text_range_empty_range() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("hello world");
let buffer_id = harness.with_runtime(|runtime| runtime.active_buffer().unwrap());
let result = harness.with_runtime(|runtime| {
runtime.buffer_text_range(buffer_id, Position::new(0, 3), Position::new(0, 3))
});
assert_eq!(result, Some(String::new()));
}
#[test]
fn test_buffer_text_range_out_of_bounds_column() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("hi");
let buffer_id = harness.with_runtime(|runtime| runtime.active_buffer().unwrap());
let result = harness.with_runtime(|runtime| {
runtime.buffer_text_range(buffer_id, Position::new(0, 0), Position::new(0, 100))
});
assert_eq!(result, Some("hi".to_string()));
}
#[test]
fn test_named_register_set_and_get() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
harness.with_runtime(|runtime| {
let content = crate::api::RegisterContent::characterwise("hello");
runtime.set_register(Some('a'), content);
let got = runtime.get_register(Some('a'));
assert!(got.is_some());
assert_eq!(got.unwrap().text, "hello");
});
}
#[test]
fn test_unnamed_register_set_and_get() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
harness.with_runtime(|runtime| {
let content = crate::api::RegisterContent::characterwise("unnamed");
runtime.set_register(None, content);
let got = runtime.get_register(None);
assert!(got.is_some());
assert_eq!(got.unwrap().text, "unnamed");
});
}
#[test]
fn test_get_register_nonexistent_named() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
let got = harness.with_runtime(|runtime| runtime.get_register(Some('z')));
assert!(got.is_none());
}
#[test]
fn test_record_edit_without_provider() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("test");
let buffer_id = harness.with_runtime(|runtime| runtime.active_buffer().unwrap());
harness.with_runtime(|runtime| {
runtime.record_edit(
buffer_id,
vec![reovim_kernel::api::v1::Edit::Insert {
position: Position::new(0, 0),
text: "x".to_string(),
}],
Position::new(0, 0),
Position::new(0, 1),
);
});
}
#[test]
fn test_record_edit_mine_without_owner() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("test");
let buffer_id = harness.with_runtime(|runtime| runtime.active_buffer().unwrap());
harness.with_runtime(|runtime| {
runtime.record_edit_mine(
buffer_id,
vec![reovim_kernel::api::v1::Edit::Insert {
position: Position::new(0, 0),
text: "x".to_string(),
}],
Position::new(0, 0),
Position::new(0, 1),
);
});
}
#[test]
fn test_buffer_line_len_api() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("hello\nworld");
let buffer_id = harness.with_runtime(|runtime| runtime.active_buffer().unwrap());
harness.with_runtime(|runtime| {
assert_eq!(runtime.buffer_line_len(buffer_id, 0), Some(5));
assert_eq!(runtime.buffer_line_len(buffer_id, 1), Some(5));
assert!(runtime.buffer_line_len(buffer_id, 99).is_none());
});
}
#[test]
fn test_buffer_line_len_nonexistent_buffer() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
let fake_id = BufferId::new();
let result = harness.with_runtime(|runtime| runtime.buffer_line_len(fake_id, 0));
assert!(result.is_none());
}
#[test]
fn test_delete_range_empty_range() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("hello world");
let buffer_id = harness.with_runtime(|runtime| runtime.active_buffer().unwrap());
harness.with_runtime(|runtime| {
runtime.delete_range(buffer_id, Position::new(0, 5), Position::new(0, 5));
});
harness.assert_buffer_content("hello world");
}
#[test]
fn test_show_overlay_no_compositor() {
use {crate::testing::TestSessionRuntime, reovim_driver_layout::OverlayConstraints};
let mut harness = TestSessionRuntime::new();
let result = harness.with_runtime(|runtime| {
runtime.show_overlay(OverlayConstraints::centered().with_size(20, 10))
});
assert!(result.is_err());
}
#[test]
fn test_hide_overlay_no_compositor() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
let fake_win = WindowId::new();
let result = harness.with_runtime(|runtime| runtime.hide_overlay(fake_win));
assert!(result.is_err());
}
#[test]
fn test_resize_overlay_no_compositor() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
let fake_win = WindowId::new();
let result = harness.with_runtime(|runtime| runtime.resize_overlay(fake_win, 40, 20));
assert!(result.is_err());
}
#[test]
fn test_focus_no_compositor() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
let fake_win = WindowId::new();
let result = harness.with_runtime(|runtime| runtime.focus(fake_win));
assert!(result.is_err());
}
#[test]
fn test_to_kernel_split_direction() {
use reovim_driver_layout::SplitDirection;
let h = to_kernel_split_direction(SplitDirection::Horizontal);
assert!(matches!(h, KernelSplitDirection::Horizontal));
let v = to_kernel_split_direction(SplitDirection::Vertical);
assert!(matches!(v, KernelSplitDirection::Vertical));
}
#[test]
fn test_buffer_text_range_multi_line_out_of_bounds_start() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("ab\ncd\nef");
let buffer_id = harness.with_runtime(|runtime| runtime.active_buffer().unwrap());
let result = harness.with_runtime(|runtime| {
runtime.buffer_text_range(buffer_id, Position::new(0, 100), Position::new(2, 1))
});
assert_eq!(result, Some("\ncd\ne".to_string()));
}
#[test]
#[cfg_attr(coverage_nightly, coverage(off))]
fn test_execute_command_not_found() {
use reovim_kernel::api::v1::ModeStack;
struct NullExecutor;
impl CommandExecutor for NullExecutor {
fn get_handle(&self, _id: &CommandId) -> Option<Arc<dyn CommandHandle>> {
None
}
}
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = NullExecutor;
let mut mode_stack = ModeStack::new(test_mode());
let mut windows = crate::WindowLayout::empty();
let mut extensions = crate::ExtensionMap::new();
let mut compositor = None;
let mut tabs = crate::TabPageSet::new();
let mut registers = RegisterBank::new();
let mut clipboard_history = HistoryRing::new();
let mut local_marks = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut runtime = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut mode_stack,
windows: &mut windows,
extensions: &mut extensions,
compositor: &mut compositor,
tabs: &mut tabs,
registers: &mut registers,
clipboard_history: &mut clipboard_history,
local_marks: &mut local_marks,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
let cmd = CommandId::new(ModuleId::new("test"), "nonexistent");
let result = runtime.execute_command(cmd, CommandContext::new());
assert!(matches!(result, CommandResult::Error(_)));
}
#[test]
fn test_execute_command_recursion_guard() {
use {
crate::testing::TestSessionRuntime, reovim_driver_command_types::CommandContext,
reovim_kernel::api::v1::ModuleId,
};
let mut harness = TestSessionRuntime::new();
let cmd = CommandId::new(ModuleId::new("test"), "test_cmd");
harness.with_runtime(|runtime| {
runtime.command_depth = 16;
let result = runtime.execute_command(cmd, CommandContext::new());
assert!(result.is_error());
match result {
CommandResult::Error(msg) => {
assert!(msg.contains("recursion limit"));
}
CommandResult::Success => panic!("Expected recursion limit error"),
}
});
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[test]
fn test_set_window_buffer_clears_selection() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("hello");
let window_id = harness.with_runtime(|runtime| runtime.active_window().unwrap());
if let Some(w) = harness.windows.get_mut(window_id) {
w.selection = Some(crate::Selection::new(
Position::new(0, 0),
Position::new(0, 3),
crate::SelectionMode::Character,
));
}
let new_buf = harness.with_runtime(|runtime| runtime.create_buffer(None, "world"));
let result = harness.with_runtime(|runtime| runtime.set_window_buffer(window_id, new_buf));
assert!(result.is_ok());
assert!(harness.windows.get(window_id).unwrap().selection.is_none());
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[test]
fn test_insert_text_with_cursor_position() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("hello");
let buffer_id = harness.with_runtime(|runtime| runtime.active_buffer().unwrap());
if let Some(w) = harness.windows.active_mut() {
w.cursor.line = 0;
w.cursor.column = 3;
}
harness.with_runtime(|runtime| {
runtime.insert_text(buffer_id, Position::new(0, 3), " ");
});
harness.assert_buffer_content("hel lo");
}
#[test]
fn test_insert_text_emits_buffer_modified() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("hello");
let buffer_id = harness.with_runtime(|runtime| runtime.active_buffer().unwrap());
harness.with_runtime(|runtime| {
runtime.insert_text(buffer_id, Position::new(0, 5), " world");
});
harness.assert_buffer_content("hello world");
let changes = harness.take_changes();
assert!(changes.buffer_modified);
assert!(changes.affected_buffers.contains(&buffer_id));
}
#[test]
fn test_delete_range_emits_buffer_modified() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("hello world");
let buffer_id = harness.with_runtime(|runtime| runtime.active_buffer().unwrap());
harness.with_runtime(|runtime| {
runtime.delete_range(buffer_id, Position::new(0, 5), Position::new(0, 11));
});
harness.assert_buffer_content("hello");
let changes = harness.take_changes();
assert!(changes.buffer_modified);
assert!(changes.affected_buffers.contains(&buffer_id));
}
#[test]
fn test_pop_mode_with_result() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
harness.with_runtime(|runtime| {
runtime.push_mode(test_mode_2(), TransitionContext::new());
});
let result = harness.with_runtime(|runtime| runtime.pop_mode(Some(PopResult::Cancelled)));
assert!(result.is_ok());
}
#[test]
#[cfg_attr(coverage_nightly, coverage(off))]
fn test_set_mode_records_change() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
harness.with_runtime(|runtime| {
runtime.set_mode(test_mode_2(), TransitionContext::new());
});
let changes = harness.take_changes();
assert!(changes.mode_changed);
}
struct InMemoryBufferManager {
buffers: reovim_arch::sync::RwLock<
std::collections::HashMap<
BufferId,
std::sync::Arc<reovim_arch::sync::RwLock<reovim_kernel::api::v1::Buffer>>,
>,
>,
}
impl InMemoryBufferManager {
fn new() -> Self {
Self {
buffers: reovim_arch::sync::RwLock::new(std::collections::HashMap::new()),
}
}
}
#[cfg_attr(coverage_nightly, coverage(off))]
impl reovim_kernel::api::v1::BufferManager for InMemoryBufferManager {
fn get(
&self,
id: BufferId,
) -> Option<std::sync::Arc<reovim_arch::sync::RwLock<reovim_kernel::api::v1::Buffer>>> {
self.buffers.read().get(&id).cloned()
}
fn create(&self) -> BufferId {
let id = BufferId::new();
let buffer = std::sync::Arc::new(reovim_arch::sync::RwLock::new(
reovim_kernel::api::v1::Buffer::new(),
));
self.buffers.write().insert(id, buffer);
id
}
fn register(&self, buffer: reovim_kernel::api::v1::Buffer) -> BufferId {
let id = BufferId::new();
let buffer = std::sync::Arc::new(reovim_arch::sync::RwLock::new(buffer));
self.buffers.write().insert(id, buffer);
id
}
fn unregister(
&self,
id: BufferId,
) -> Result<reovim_kernel::api::v1::Buffer, reovim_kernel::api::v1::BufferError> {
self.buffers.write().remove(&id).map_or(
Err(reovim_kernel::api::v1::BufferError::NotFound(id)),
|arc_buf| {
std::sync::Arc::try_unwrap(arc_buf)
.map_or_else(|arc| Ok(arc.read().clone()), |rwlock| Ok(rwlock.into_inner()))
},
)
}
fn list(&self) -> Vec<BufferId> {
self.buffers.read().keys().copied().collect()
}
fn count(&self) -> usize {
self.buffers.read().len()
}
}
fn make_kernel_with_services(
services: std::sync::Arc<reovim_kernel::api::v1::ServiceRegistry>,
) -> KernelContext {
use reovim_kernel::api::v1::{
EventBus, MarkBank, MotionEngine, OptionRegistry, TextObjectEngine,
};
KernelContext::new(
std::sync::Arc::new(EventBus::new()),
std::sync::Arc::new(InMemoryBufferManager::new()),
std::sync::Arc::new(MotionEngine),
std::sync::Arc::new(TextObjectEngine),
std::sync::Arc::new(reovim_arch::sync::RwLock::new(MarkBank::new())),
std::sync::Arc::new(OptionRegistry::new()),
services,
)
}
#[test]
fn test_insert_text_no_active_window_uses_zero_position() {
use reovim_kernel::api::v1::ModeStack;
let services = std::sync::Arc::new(reovim_kernel::api::v1::ServiceRegistry::new());
let kernel = make_kernel_with_services(services);
let mut session = Session::new(ClientId::new(1), test_mode());
let executor = StubExecutor;
let buf = reovim_kernel::api::v1::Buffer::from_string("hello");
let buf_id = kernel.buffers.register(buf);
let mut mode_stack = ModeStack::new(test_mode());
let mut windows = crate::WindowLayout::empty(); let mut extensions = crate::ExtensionMap::new();
let mut compositor = None;
let mut tabs = crate::TabPageSet::new();
let mut registers = RegisterBank::new();
let mut clipboard_history = HistoryRing::new();
let mut local_marks = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = Some(buf_id); let mut terminal_size = (80u16, 24u16);
let mut runtime = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut mode_stack,
windows: &mut windows,
extensions: &mut extensions,
compositor: &mut compositor,
tabs: &mut tabs,
registers: &mut registers,
clipboard_history: &mut clipboard_history,
local_marks: &mut local_marks,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
runtime.insert_text(buf_id, Position::new(0, 5), " world");
let content = runtime.buffer_content(buf_id);
assert_eq!(content, Some("hello world".to_string()));
}
#[test]
fn test_delete_range_no_active_window_uses_zero_position() {
use reovim_kernel::api::v1::ModeStack;
let services = std::sync::Arc::new(reovim_kernel::api::v1::ServiceRegistry::new());
let kernel = make_kernel_with_services(services);
let mut session = Session::new(ClientId::new(1), test_mode());
let executor = StubExecutor;
let buf = reovim_kernel::api::v1::Buffer::from_string("hello world");
let buf_id = kernel.buffers.register(buf);
let mut mode_stack = ModeStack::new(test_mode());
let mut windows = crate::WindowLayout::empty(); let mut extensions = crate::ExtensionMap::new();
let mut compositor = None;
let mut tabs = crate::TabPageSet::new();
let mut registers = RegisterBank::new();
let mut clipboard_history = HistoryRing::new();
let mut local_marks = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = Some(buf_id); let mut terminal_size = (80u16, 24u16);
let mut runtime = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut mode_stack,
windows: &mut windows,
extensions: &mut extensions,
compositor: &mut compositor,
tabs: &mut tabs,
registers: &mut registers,
clipboard_history: &mut clipboard_history,
local_marks: &mut local_marks,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
runtime.delete_range(buf_id, Position::new(0, 5), Position::new(0, 11));
let content = runtime.buffer_content(buf_id);
assert_eq!(content, Some("hello".to_string()));
}
struct MockClipboard {
clipboard: std::sync::Mutex<Option<String>>,
selection: std::sync::Mutex<Option<String>>,
}
impl MockClipboard {
fn new() -> Self {
Self {
clipboard: std::sync::Mutex::new(None),
selection: std::sync::Mutex::new(None),
}
}
fn with_clipboard(text: &str) -> Self {
Self {
clipboard: std::sync::Mutex::new(Some(text.to_string())),
selection: std::sync::Mutex::new(None),
}
}
fn with_selection(text: &str) -> Self {
Self {
clipboard: std::sync::Mutex::new(None),
selection: std::sync::Mutex::new(Some(text.to_string())),
}
}
}
#[cfg_attr(coverage_nightly, coverage(off))]
impl reovim_driver_clipboard::ClipboardProvider for MockClipboard {
fn clipboard_available(&self) -> bool {
true
}
fn copy_to_clipboard(&self, text: &str) -> Result<(), reovim_driver_clipboard::ClipboardError> {
*self.clipboard.lock().unwrap() = Some(text.to_string());
Ok(())
}
fn paste_from_clipboard(
&self,
) -> Result<Option<String>, reovim_driver_clipboard::ClipboardError> {
Ok(self.clipboard.lock().unwrap().clone())
}
fn selection_available(&self) -> bool {
true
}
fn copy_to_selection(&self, text: &str) -> Result<(), reovim_driver_clipboard::ClipboardError> {
*self.selection.lock().unwrap() = Some(text.to_string());
Ok(())
}
fn paste_from_selection(
&self,
) -> Result<Option<String>, reovim_driver_clipboard::ClipboardError> {
Ok(self.selection.lock().unwrap().clone())
}
}
fn kernel_with_clipboard(provider: MockClipboard) -> KernelContext {
let services = std::sync::Arc::new(reovim_kernel::api::v1::ServiceRegistry::new());
let clipboard_registry = ClipboardProviderRegistry::new();
clipboard_registry.register(ClipboardKey::Default, std::sync::Arc::new(provider));
services.register(std::sync::Arc::new(clipboard_registry));
make_kernel_with_services(services)
}
#[test]
fn test_get_register_raw_clipboard_plus_returns_none() {
use reovim_kernel::api::v1::ModeStack;
let kernel = kernel_with_clipboard(MockClipboard::with_clipboard("from-clipboard"));
let mut session = Session::new(ClientId::new(1), test_mode());
let executor = StubExecutor;
let mut mode_stack = ModeStack::new(test_mode());
let mut windows = crate::WindowLayout::empty();
let mut extensions = crate::ExtensionMap::new();
let mut compositor = None;
let mut tabs = crate::TabPageSet::new();
let mut registers = RegisterBank::new();
let mut clipboard_history = HistoryRing::new();
let mut local_marks = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let runtime = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut mode_stack,
windows: &mut windows,
extensions: &mut extensions,
compositor: &mut compositor,
tabs: &mut tabs,
registers: &mut registers,
clipboard_history: &mut clipboard_history,
local_marks: &mut local_marks,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
assert!(runtime.get_register(Some('+')).is_none());
let content = runtime.get_register_with_clipboard(Some('+'));
assert!(content.is_some());
assert_eq!(content.unwrap().text, "from-clipboard");
}
#[test]
fn test_get_register_raw_selection_star_returns_none() {
use reovim_kernel::api::v1::ModeStack;
let kernel = kernel_with_clipboard(MockClipboard::with_selection("from-selection"));
let mut session = Session::new(ClientId::new(1), test_mode());
let executor = StubExecutor;
let mut mode_stack = ModeStack::new(test_mode());
let mut windows = crate::WindowLayout::empty();
let mut extensions = crate::ExtensionMap::new();
let mut compositor = None;
let mut tabs = crate::TabPageSet::new();
let mut registers = RegisterBank::new();
let mut clipboard_history = HistoryRing::new();
let mut local_marks = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let runtime = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut mode_stack,
windows: &mut windows,
extensions: &mut extensions,
compositor: &mut compositor,
tabs: &mut tabs,
registers: &mut registers,
clipboard_history: &mut clipboard_history,
local_marks: &mut local_marks,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
assert!(runtime.get_register(Some('*')).is_none());
let content = runtime.get_register_with_clipboard(Some('*'));
assert!(content.is_some());
assert_eq!(content.unwrap().text, "from-selection");
}
#[test]
fn test_get_register_numbered_with_provider() {
use reovim_kernel::api::v1::ModeStack;
let kernel = kernel_with_clipboard(MockClipboard::new());
let mut session = Session::new(ClientId::new(1), test_mode());
let executor = StubExecutor;
let mut mode_stack = ModeStack::new(test_mode());
let mut windows = crate::WindowLayout::empty();
let mut extensions = crate::ExtensionMap::new();
let mut compositor = None;
let mut tabs = crate::TabPageSet::new();
let mut registers = RegisterBank::new();
let mut clipboard_history = HistoryRing::new();
clipboard_history.push(RegisterContent::characterwise("yank-1"));
clipboard_history.push(RegisterContent::characterwise("yank-0"));
let mut local_marks = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let runtime = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut mode_stack,
windows: &mut windows,
extensions: &mut extensions,
compositor: &mut compositor,
tabs: &mut tabs,
registers: &mut registers,
clipboard_history: &mut clipboard_history,
local_marks: &mut local_marks,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
let c0 = runtime.get_register(Some('0'));
assert!(c0.is_some());
assert_eq!(c0.unwrap().text, "yank-0");
let c1 = runtime.get_register(Some('1'));
assert!(c1.is_some());
assert_eq!(c1.unwrap().text, "yank-1");
}
#[test]
fn test_set_register_clipboard_plus_not_stored_in_register_bank() {
use reovim_kernel::api::v1::ModeStack;
let kernel = kernel_with_clipboard(MockClipboard::new());
let mut session = Session::new(ClientId::new(1), test_mode());
let executor = StubExecutor;
let mut mode_stack = ModeStack::new(test_mode());
let mut windows = crate::WindowLayout::empty();
let mut extensions = crate::ExtensionMap::new();
let mut compositor = None;
let mut tabs = crate::TabPageSet::new();
let mut registers = RegisterBank::new();
let mut clipboard_history = HistoryRing::new();
let mut local_marks = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut runtime = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut mode_stack,
windows: &mut windows,
extensions: &mut extensions,
compositor: &mut compositor,
tabs: &mut tabs,
registers: &mut registers,
clipboard_history: &mut clipboard_history,
local_marks: &mut local_marks,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
runtime.set_register(Some('+'), RegisterContent::characterwise("to-clipboard"));
assert!(runtime.get_register(Some('+')).is_none());
}
#[test]
fn test_store_register_with_sync_clipboard_plus() {
use reovim_kernel::api::v1::ModeStack;
let kernel = kernel_with_clipboard(MockClipboard::new());
let mut session = Session::new(ClientId::new(1), test_mode());
let executor = StubExecutor;
let mut mode_stack = ModeStack::new(test_mode());
let mut windows = crate::WindowLayout::empty();
let mut extensions = crate::ExtensionMap::new();
let mut compositor = None;
let mut tabs = crate::TabPageSet::new();
let mut registers = RegisterBank::new();
let mut clipboard_history = HistoryRing::new();
let mut local_marks = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut runtime = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut mode_stack,
windows: &mut windows,
extensions: &mut extensions,
compositor: &mut compositor,
tabs: &mut tabs,
registers: &mut registers,
clipboard_history: &mut clipboard_history,
local_marks: &mut local_marks,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
runtime.store_register_with_sync(Some('+'), RegisterContent::characterwise("to-clipboard"));
let content = runtime.get_register_with_clipboard(Some('+'));
assert!(content.is_some());
assert_eq!(content.unwrap().text, "to-clipboard");
}
#[test]
fn test_set_register_selection_star_not_stored_in_register_bank() {
use reovim_kernel::api::v1::ModeStack;
let kernel = kernel_with_clipboard(MockClipboard::new());
let mut session = Session::new(ClientId::new(1), test_mode());
let executor = StubExecutor;
let mut mode_stack = ModeStack::new(test_mode());
let mut windows = crate::WindowLayout::empty();
let mut extensions = crate::ExtensionMap::new();
let mut compositor = None;
let mut tabs = crate::TabPageSet::new();
let mut registers = RegisterBank::new();
let mut clipboard_history = HistoryRing::new();
let mut local_marks = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut runtime = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut mode_stack,
windows: &mut windows,
extensions: &mut extensions,
compositor: &mut compositor,
tabs: &mut tabs,
registers: &mut registers,
clipboard_history: &mut clipboard_history,
local_marks: &mut local_marks,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
runtime.set_register(Some('*'), RegisterContent::characterwise("to-selection"));
assert!(runtime.get_register(Some('*')).is_none());
}
#[test]
fn test_store_register_with_sync_selection_star() {
use reovim_kernel::api::v1::ModeStack;
let kernel = kernel_with_clipboard(MockClipboard::new());
let mut session = Session::new(ClientId::new(1), test_mode());
let executor = StubExecutor;
let mut mode_stack = ModeStack::new(test_mode());
let mut windows = crate::WindowLayout::empty();
let mut extensions = crate::ExtensionMap::new();
let mut compositor = None;
let mut tabs = crate::TabPageSet::new();
let mut registers = RegisterBank::new();
let mut clipboard_history = HistoryRing::new();
let mut local_marks = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut runtime = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut mode_stack,
windows: &mut windows,
extensions: &mut extensions,
compositor: &mut compositor,
tabs: &mut tabs,
registers: &mut registers,
clipboard_history: &mut clipboard_history,
local_marks: &mut local_marks,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
runtime.store_register_with_sync(Some('*'), RegisterContent::characterwise("to-selection"));
let content = runtime.get_register_with_clipboard(Some('*'));
assert!(content.is_some());
assert_eq!(content.unwrap().text, "to-selection");
}
struct MockUndoProvider {
edits: std::sync::Mutex<Vec<reovim_driver_undo::UndoRecord>>,
}
impl MockUndoProvider {
fn new() -> Self {
Self {
edits: std::sync::Mutex::new(Vec::new()),
}
}
}
#[cfg_attr(coverage_nightly, coverage(off))]
impl reovim_driver_undo::UndoProvider for MockUndoProvider {
fn undo(&self, _buffer_id: BufferId) -> Option<UndoResult> {
Some(UndoResult {
edits: vec![Edit::Insert {
position: Position::new(0, 0),
text: "X".to_string(),
}],
cursor: Position::new(0, 1),
})
}
fn redo(&self, _buffer_id: BufferId) -> Option<UndoResult> {
Some(UndoResult {
edits: vec![Edit::Delete {
position: Position::new(0, 0),
text: "X".to_string(),
}],
cursor: Position::new(0, 0),
})
}
fn redo_branch(&self, _buffer_id: BufferId, _branch_idx: usize) -> Option<UndoResult> {
None
}
fn record(
&self,
buffer_id: BufferId,
edits: Vec<Edit>,
cursor_before: Position,
cursor_after: Position,
) {
self.edits
.lock()
.unwrap()
.push(reovim_driver_undo::UndoRecord {
buffer_id,
edits,
cursor_before,
cursor_after,
});
}
fn has_history(&self, _buffer_id: BufferId) -> bool {
true
}
fn remove(&self, _buffer_id: BufferId) {}
fn buffer_count(&self) -> usize {
1
}
fn get_tree(&self, _buffer_id: BufferId) -> Option<reovim_kernel::api::v1::UndoTree> {
let mut tree = reovim_kernel::api::v1::UndoTree::new();
tree.push(
vec![Edit::Insert {
position: Position::new(0, 0),
text: "a".to_string(),
}],
Position::new(0, 0),
Position::new(0, 1),
);
Some(tree)
}
fn begin_batch(&self, _buffer_id: BufferId, _cursor_before: Position) {}
fn end_batch(&self, _buffer_id: BufferId, _cursor_after: Position) {}
fn is_batching(&self, _buffer_id: BufferId) -> bool {
false
}
fn persist(
&self,
_buffer_id: BufferId,
_buffer_path: &str,
_vfs: &dyn reovim_driver_vfs::VfsDriver,
) -> Result<(), reovim_driver_undo::UndoPersistError> {
Ok(())
}
fn load(
&self,
_buffer_id: BufferId,
_buffer_path: &str,
_vfs: &dyn reovim_driver_vfs::VfsDriver,
) -> Result<bool, reovim_driver_undo::UndoPersistError> {
Ok(false)
}
fn undo_for_client(&self, _buffer_id: BufferId, _client_id: usize) -> Option<UndoResult> {
Some(UndoResult {
edits: vec![Edit::Insert {
position: Position::new(0, 0),
text: "Y".to_string(),
}],
cursor: Position::new(0, 1),
})
}
fn redo_for_client(&self, _buffer_id: BufferId, _client_id: usize) -> Option<UndoResult> {
Some(UndoResult {
edits: vec![Edit::Delete {
position: Position::new(0, 0),
text: "Y".to_string(),
}],
cursor: Position::new(0, 0),
})
}
fn record_for_client(
&self,
buffer_id: BufferId,
_client_id: usize,
edits: Vec<Edit>,
cursor_before: Position,
cursor_after: Position,
) {
self.record(buffer_id, edits, cursor_before, cursor_after);
}
}
fn kernel_with_undo(provider: MockUndoProvider) -> KernelContext {
let services = std::sync::Arc::new(reovim_kernel::api::v1::ServiceRegistry::new());
let undo_registry = UndoProviderRegistry::new();
undo_registry.register(UndoKey::Buffer, std::sync::Arc::new(provider));
services.register(std::sync::Arc::new(undo_registry));
make_kernel_with_services(services)
}
#[test]
fn test_undo_with_provider() {
use reovim_kernel::api::v1::ModeStack;
let kernel = kernel_with_undo(MockUndoProvider::new());
let mut session = Session::new(ClientId::new(1), test_mode());
let executor = StubExecutor;
let buf = reovim_kernel::api::v1::Buffer::from_string("hello");
let buf_id = kernel.buffers.register(buf);
let mut mode_stack = ModeStack::new(test_mode());
let mut window = crate::Window::new();
window.buffer_id = Some(buf_id);
let mut windows = crate::WindowLayout::empty();
windows.add(window);
let mut extensions = crate::ExtensionMap::new();
let mut compositor = None;
let mut tabs = crate::TabPageSet::new();
let mut registers = RegisterBank::new();
let mut clipboard_history = HistoryRing::new();
let mut local_marks = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut runtime = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut mode_stack,
windows: &mut windows,
extensions: &mut extensions,
compositor: &mut compositor,
tabs: &mut tabs,
registers: &mut registers,
clipboard_history: &mut clipboard_history,
local_marks: &mut local_marks,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
let result = runtime.undo(buf_id);
assert!(result.is_some());
assert_eq!(result.unwrap().cursor, Position::new(0, 1));
assert!(runtime.changes.buffer_modified);
assert!(runtime.changes.cursor_moved);
}
#[test]
fn test_redo_with_provider() {
use reovim_kernel::api::v1::ModeStack;
let kernel = kernel_with_undo(MockUndoProvider::new());
let mut session = Session::new(ClientId::new(1), test_mode());
let executor = StubExecutor;
let buf = reovim_kernel::api::v1::Buffer::from_string("Xhello");
let buf_id = kernel.buffers.register(buf);
let mut mode_stack = ModeStack::new(test_mode());
let mut window = crate::Window::new();
window.buffer_id = Some(buf_id);
let mut windows = crate::WindowLayout::empty();
windows.add(window);
let mut extensions = crate::ExtensionMap::new();
let mut compositor = None;
let mut tabs = crate::TabPageSet::new();
let mut registers = RegisterBank::new();
let mut clipboard_history = HistoryRing::new();
let mut local_marks = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut runtime = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut mode_stack,
windows: &mut windows,
extensions: &mut extensions,
compositor: &mut compositor,
tabs: &mut tabs,
registers: &mut registers,
clipboard_history: &mut clipboard_history,
local_marks: &mut local_marks,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
let result = runtime.redo(buf_id);
assert!(result.is_some());
assert_eq!(result.unwrap().cursor, Position::new(0, 0));
assert!(runtime.changes.buffer_modified);
assert!(runtime.changes.cursor_moved);
}
#[test]
fn test_can_undo_with_provider() {
use reovim_kernel::api::v1::ModeStack;
let kernel = kernel_with_undo(MockUndoProvider::new());
let mut session = Session::new(ClientId::new(1), test_mode());
let executor = StubExecutor;
let mut mode_stack = ModeStack::new(test_mode());
let mut windows = crate::WindowLayout::empty();
let mut extensions = crate::ExtensionMap::new();
let mut compositor = None;
let mut tabs = crate::TabPageSet::new();
let mut registers = RegisterBank::new();
let mut clipboard_history = HistoryRing::new();
let mut local_marks = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let runtime = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut mode_stack,
windows: &mut windows,
extensions: &mut extensions,
compositor: &mut compositor,
tabs: &mut tabs,
registers: &mut registers,
clipboard_history: &mut clipboard_history,
local_marks: &mut local_marks,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
let buf_id = BufferId::from_raw(1);
assert!(runtime.can_undo(buf_id));
}
#[test]
fn test_undo_mine_with_owner_and_provider() {
use reovim_kernel::api::v1::ModeStack;
let kernel = kernel_with_undo(MockUndoProvider::new());
let mut session = Session::new(ClientId::new(1), test_mode());
let executor = StubExecutor;
let client_id = ClientId::new(42);
let buf = reovim_kernel::api::v1::Buffer::from_string("hello");
let buf_id = kernel.buffers.register(buf);
let mut mode_stack = ModeStack::new(test_mode());
let mut window = crate::Window::new();
window.buffer_id = Some(buf_id);
let mut windows = crate::WindowLayout::empty();
windows.add(window);
let mut extensions = crate::ExtensionMap::new();
let mut compositor = None;
let mut tabs = crate::TabPageSet::new();
let mut registers = RegisterBank::new();
let mut clipboard_history = HistoryRing::new();
let mut local_marks = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut runtime = SessionRuntime::with_owner(
client_id,
&mut session,
crate::ClientContext {
mode_stack: &mut mode_stack,
windows: &mut windows,
extensions: &mut extensions,
compositor: &mut compositor,
tabs: &mut tabs,
registers: &mut registers,
clipboard_history: &mut clipboard_history,
local_marks: &mut local_marks,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
let result = runtime.undo_mine(buf_id);
assert!(result.is_some());
assert_eq!(result.unwrap().cursor, Position::new(0, 1));
assert!(runtime.changes.buffer_modified);
assert!(runtime.changes.cursor_moved);
}
#[test]
fn test_redo_mine_with_owner_and_provider() {
use reovim_kernel::api::v1::ModeStack;
let kernel = kernel_with_undo(MockUndoProvider::new());
let mut session = Session::new(ClientId::new(1), test_mode());
let executor = StubExecutor;
let client_id = ClientId::new(42);
let buf = reovim_kernel::api::v1::Buffer::from_string("Yhello");
let buf_id = kernel.buffers.register(buf);
let mut mode_stack = ModeStack::new(test_mode());
let mut window = crate::Window::new();
window.buffer_id = Some(buf_id);
let mut windows = crate::WindowLayout::empty();
windows.add(window);
let mut extensions = crate::ExtensionMap::new();
let mut compositor = None;
let mut tabs = crate::TabPageSet::new();
let mut registers = RegisterBank::new();
let mut clipboard_history = HistoryRing::new();
let mut local_marks = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut runtime = SessionRuntime::with_owner(
client_id,
&mut session,
crate::ClientContext {
mode_stack: &mut mode_stack,
windows: &mut windows,
extensions: &mut extensions,
compositor: &mut compositor,
tabs: &mut tabs,
registers: &mut registers,
clipboard_history: &mut clipboard_history,
local_marks: &mut local_marks,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
let result = runtime.redo_mine(buf_id);
assert!(result.is_some());
assert_eq!(result.unwrap().cursor, Position::new(0, 0));
assert!(runtime.changes.buffer_modified);
assert!(runtime.changes.cursor_moved);
}
#[test]
fn test_record_edit_mine_with_owner_and_provider() {
use reovim_kernel::api::v1::ModeStack;
let kernel = kernel_with_undo(MockUndoProvider::new());
let mut session = Session::new(ClientId::new(1), test_mode());
let executor = StubExecutor;
let client_id = ClientId::new(42);
let buf_id = BufferId::from_raw(1);
let mut mode_stack = ModeStack::new(test_mode());
let mut windows = crate::WindowLayout::empty();
let mut extensions = crate::ExtensionMap::new();
let mut compositor = None;
let mut tabs = crate::TabPageSet::new();
let mut registers = RegisterBank::new();
let mut clipboard_history = HistoryRing::new();
let mut local_marks = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut runtime = SessionRuntime::with_owner(
client_id,
&mut session,
crate::ClientContext {
mode_stack: &mut mode_stack,
windows: &mut windows,
extensions: &mut extensions,
compositor: &mut compositor,
tabs: &mut tabs,
registers: &mut registers,
clipboard_history: &mut clipboard_history,
local_marks: &mut local_marks,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
runtime.record_edit_mine(
buf_id,
vec![Edit::Insert {
position: Position::new(0, 0),
text: "z".to_string(),
}],
Position::new(0, 0),
Position::new(0, 1),
);
}
struct AlternateUndoProvider;
#[cfg_attr(coverage_nightly, coverage(off))]
impl reovim_driver_undo::UndoProvider for AlternateUndoProvider {
fn undo(&self, _buffer_id: BufferId) -> Option<UndoResult> {
Some(UndoResult {
edits: vec![Edit::Delete {
position: Position::new(0, 0),
text: "X".to_string(),
}],
cursor: Position::new(0, 0),
})
}
fn redo(&self, _buffer_id: BufferId) -> Option<UndoResult> {
Some(UndoResult {
edits: vec![Edit::Insert {
position: Position::new(0, 0),
text: "Y".to_string(),
}],
cursor: Position::new(0, 1),
})
}
fn redo_branch(&self, _buffer_id: BufferId, _branch_idx: usize) -> Option<UndoResult> {
None
}
fn record(
&self,
_buffer_id: BufferId,
_edits: Vec<Edit>,
_cursor_before: Position,
_cursor_after: Position,
) {
}
fn has_history(&self, _buffer_id: BufferId) -> bool {
true
}
fn remove(&self, _buffer_id: BufferId) {}
fn buffer_count(&self) -> usize {
1
}
fn get_tree(&self, _buffer_id: BufferId) -> Option<reovim_kernel::api::v1::UndoTree> {
None
}
fn begin_batch(&self, _buffer_id: BufferId, _cursor_before: Position) {}
fn end_batch(&self, _buffer_id: BufferId, _cursor_after: Position) {}
fn is_batching(&self, _buffer_id: BufferId) -> bool {
false
}
fn persist(
&self,
_buffer_id: BufferId,
_buffer_path: &str,
_vfs: &dyn reovim_driver_vfs::VfsDriver,
) -> Result<(), reovim_driver_undo::UndoPersistError> {
Ok(())
}
fn load(
&self,
_buffer_id: BufferId,
_buffer_path: &str,
_vfs: &dyn reovim_driver_vfs::VfsDriver,
) -> Result<bool, reovim_driver_undo::UndoPersistError> {
Ok(false)
}
fn undo_for_client(&self, _buffer_id: BufferId, _client_id: usize) -> Option<UndoResult> {
Some(UndoResult {
edits: vec![Edit::Delete {
position: Position::new(0, 0),
text: "Z".to_string(),
}],
cursor: Position::new(0, 0),
})
}
fn redo_for_client(&self, _buffer_id: BufferId, _client_id: usize) -> Option<UndoResult> {
Some(UndoResult {
edits: vec![Edit::Insert {
position: Position::new(0, 0),
text: "W".to_string(),
}],
cursor: Position::new(0, 1),
})
}
fn record_for_client(
&self,
_buffer_id: BufferId,
_client_id: usize,
_edits: Vec<Edit>,
_cursor_before: Position,
_cursor_after: Position,
) {
}
}
fn kernel_with_alternate_undo() -> KernelContext {
let services = std::sync::Arc::new(reovim_kernel::api::v1::ServiceRegistry::new());
let undo_registry = UndoProviderRegistry::new();
undo_registry.register(UndoKey::Buffer, std::sync::Arc::new(AlternateUndoProvider));
services.register(std::sync::Arc::new(undo_registry));
make_kernel_with_services(services)
}
#[test]
fn test_undo_with_delete_edits() {
use reovim_kernel::api::v1::ModeStack;
let kernel = kernel_with_alternate_undo();
let mut session = Session::new(ClientId::new(1), test_mode());
let executor = StubExecutor;
let buf = reovim_kernel::api::v1::Buffer::from_string("Xhello");
let buf_id = kernel.buffers.register(buf);
let mut mode_stack = ModeStack::new(test_mode());
let mut window = crate::Window::new();
window.buffer_id = Some(buf_id);
let mut windows = crate::WindowLayout::empty();
windows.add(window);
let mut extensions = crate::ExtensionMap::new();
let mut compositor = None;
let mut tabs = crate::TabPageSet::new();
let mut registers = RegisterBank::new();
let mut clipboard_history = HistoryRing::new();
let mut local_marks = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut runtime = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut mode_stack,
windows: &mut windows,
extensions: &mut extensions,
compositor: &mut compositor,
tabs: &mut tabs,
registers: &mut registers,
clipboard_history: &mut clipboard_history,
local_marks: &mut local_marks,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
let result = runtime.undo(buf_id);
assert!(result.is_some());
let content = runtime.buffer_content(buf_id);
assert_eq!(content, Some("hello".to_string()));
assert!(runtime.changes.buffer_modified);
}
#[test]
fn test_redo_with_insert_edits() {
use reovim_kernel::api::v1::ModeStack;
let kernel = kernel_with_alternate_undo();
let mut session = Session::new(ClientId::new(1), test_mode());
let executor = StubExecutor;
let buf = reovim_kernel::api::v1::Buffer::from_string("hello");
let buf_id = kernel.buffers.register(buf);
let mut mode_stack = ModeStack::new(test_mode());
let mut window = crate::Window::new();
window.buffer_id = Some(buf_id);
let mut windows = crate::WindowLayout::empty();
windows.add(window);
let mut extensions = crate::ExtensionMap::new();
let mut compositor = None;
let mut tabs = crate::TabPageSet::new();
let mut registers = RegisterBank::new();
let mut clipboard_history = HistoryRing::new();
let mut local_marks = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut runtime = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut mode_stack,
windows: &mut windows,
extensions: &mut extensions,
compositor: &mut compositor,
tabs: &mut tabs,
registers: &mut registers,
clipboard_history: &mut clipboard_history,
local_marks: &mut local_marks,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
let result = runtime.redo(buf_id);
assert!(result.is_some());
let content = runtime.buffer_content(buf_id);
assert_eq!(content, Some("Yhello".to_string()));
assert!(runtime.changes.buffer_modified);
}
#[test]
fn test_undo_mine_with_delete_edits() {
use reovim_kernel::api::v1::ModeStack;
let kernel = kernel_with_alternate_undo();
let mut session = Session::new(ClientId::new(1), test_mode());
let executor = StubExecutor;
let client_id = ClientId::new(42);
let buf = reovim_kernel::api::v1::Buffer::from_string("Zhello");
let buf_id = kernel.buffers.register(buf);
let mut mode_stack = ModeStack::new(test_mode());
let mut window = crate::Window::new();
window.buffer_id = Some(buf_id);
let mut windows = crate::WindowLayout::empty();
windows.add(window);
let mut extensions = crate::ExtensionMap::new();
let mut compositor = None;
let mut tabs = crate::TabPageSet::new();
let mut registers = RegisterBank::new();
let mut clipboard_history = HistoryRing::new();
let mut local_marks = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut runtime = SessionRuntime::with_owner(
client_id,
&mut session,
crate::ClientContext {
mode_stack: &mut mode_stack,
windows: &mut windows,
extensions: &mut extensions,
compositor: &mut compositor,
tabs: &mut tabs,
registers: &mut registers,
clipboard_history: &mut clipboard_history,
local_marks: &mut local_marks,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
let result = runtime.undo_mine(buf_id);
assert!(result.is_some());
let content = runtime.buffer_content(buf_id);
assert_eq!(content, Some("hello".to_string()));
assert!(runtime.changes.buffer_modified);
}
#[test]
fn test_redo_mine_with_insert_edits() {
use reovim_kernel::api::v1::ModeStack;
let kernel = kernel_with_alternate_undo();
let mut session = Session::new(ClientId::new(1), test_mode());
let executor = StubExecutor;
let client_id = ClientId::new(42);
let buf = reovim_kernel::api::v1::Buffer::from_string("hello");
let buf_id = kernel.buffers.register(buf);
let mut mode_stack = ModeStack::new(test_mode());
let mut window = crate::Window::new();
window.buffer_id = Some(buf_id);
let mut windows = crate::WindowLayout::empty();
windows.add(window);
let mut extensions = crate::ExtensionMap::new();
let mut compositor = None;
let mut tabs = crate::TabPageSet::new();
let mut registers = RegisterBank::new();
let mut clipboard_history = HistoryRing::new();
let mut local_marks = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut runtime = SessionRuntime::with_owner(
client_id,
&mut session,
crate::ClientContext {
mode_stack: &mut mode_stack,
windows: &mut windows,
extensions: &mut extensions,
compositor: &mut compositor,
tabs: &mut tabs,
registers: &mut registers,
clipboard_history: &mut clipboard_history,
local_marks: &mut local_marks,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
let result = runtime.redo_mine(buf_id);
assert!(result.is_some());
let content = runtime.buffer_content(buf_id);
assert_eq!(content, Some("Whello".to_string()));
assert!(runtime.changes.buffer_modified);
}
#[test]
fn test_apply_undo_edits_buffer_not_found() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut ms = ModeStack::new(test_mode());
let mut w = crate::WindowLayout::empty();
let mut e = crate::ExtensionMap::new();
let mut c = None;
let mut tabs = crate::TabPageSet::new();
let mut r = RegisterBank::new();
let mut ch = HistoryRing::new();
let mut lm = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let rt = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut ms,
windows: &mut w,
extensions: &mut e,
compositor: &mut c,
tabs: &mut tabs,
registers: &mut r,
clipboard_history: &mut ch,
local_marks: &mut lm,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
let buf = BufferId::new();
let edits = vec![Edit::Insert {
position: Position::new(0, 0),
text: "X".to_string(),
}];
rt.apply_undo_edits(buf, &edits);
}
struct MockLayerCompositor {
id: reovim_driver_layout::LayerId,
windows: Vec<WindowId>,
focused: Option<WindowId>,
next_id: usize,
}
impl MockLayerCompositor {
fn new() -> Self {
let first = WindowId::from_raw(1);
let second = WindowId::from_raw(2);
Self {
id: reovim_driver_layout::LayerId::new(0),
windows: vec![first, second],
focused: Some(first),
next_id: 3,
}
}
}
#[cfg_attr(coverage_nightly, coverage(off))]
impl reovim_driver_layout::WindowLayerCompositor for MockLayerCompositor {
fn id(&self) -> reovim_driver_layout::LayerId {
self.id
}
fn arrange(&self, _bounds: Rect) -> Vec<reovim_driver_layout::WindowPlacement> {
Vec::new()
}
fn add_tiled(&mut self) -> WindowId {
let id = WindowId::from_raw(self.next_id);
self.next_id += 1;
self.windows.push(id);
if self.focused.is_none() {
self.focused = Some(id);
}
id
}
fn split_tiled(
&mut self,
_from: WindowId,
_direction: reovim_driver_layout::SplitDirection,
) -> Option<WindowId> {
let id = WindowId::from_raw(self.next_id);
self.next_id += 1;
self.windows.push(id);
self.focused = Some(id);
Some(id)
}
fn navigate_tiled(&self, from: WindowId, _direction: NavigateDirection) -> Option<WindowId> {
self.windows.iter().find(|&&w| w != from).copied()
}
fn resize_tiled(&mut self, _window: WindowId, _direction: NavigateDirection, _delta: i16) {}
fn close_tiled(&mut self, window: WindowId) -> Option<WindowId> {
self.windows.retain(|&w| w != window);
let next = self.windows.first().copied();
if self.focused == Some(window) {
self.focused = next;
}
next
}
fn equalize_tiled(&mut self) {}
fn cycle_tiled(&self, from: WindowId, _forward: bool) -> Option<WindowId> {
self.windows.iter().find(|&&w| w != from).copied()
}
fn create_float(&mut self, _bounds: Rect) -> WindowId {
let id = WindowId::from_raw(self.next_id);
self.next_id += 1;
id
}
fn move_float(&mut self, _window: WindowId, _x: u16, _y: u16) {}
fn resize_float(&mut self, _window: WindowId, _width: u16, _height: u16) {}
fn raise_float(&mut self, _window: WindowId) {}
fn lower_float(&mut self, _window: WindowId) {}
fn close_float(&mut self, _window: WindowId) {}
fn toggle_float(&mut self, _window: WindowId) {}
fn show_overlay(&mut self, _constraints: reovim_driver_layout::OverlayConstraints) -> WindowId {
let id = WindowId::from_raw(self.next_id);
self.next_id += 1;
id
}
fn hide_overlay(&mut self, _window: WindowId) {}
fn resize_overlay(&mut self, _window: WindowId, _width: u16, _height: u16) {}
fn hide_all_overlays(&mut self) {}
fn set_focus(&mut self, window: WindowId) {
self.focused = Some(window);
}
fn focused(&self) -> Option<WindowId> {
self.focused
}
fn windows_in_zone(&self, zone: reovim_driver_layout::Zone) -> Vec<WindowId> {
if zone == reovim_driver_layout::Zone::Tiled {
self.windows.clone()
} else {
Vec::new()
}
}
fn zone_of(&self, _window: WindowId) -> Option<reovim_driver_layout::Zone> {
Some(reovim_driver_layout::Zone::Tiled)
}
}
struct MockRootCompositor {
layer: MockLayerCompositor,
focused: Option<WindowId>,
}
impl MockRootCompositor {
fn new() -> Self {
let layer = MockLayerCompositor::new();
let focused = layer.focused;
Self { layer, focused }
}
}
#[cfg_attr(coverage_nightly, coverage(off))]
impl reovim_driver_layout::RootCompositor for MockRootCompositor {
fn composite(&self, screen: Rect) -> reovim_driver_layout::CompositeResult {
reovim_driver_layout::CompositeResult::empty(screen)
}
fn create_layer(
&mut self,
_config: reovim_driver_layout::LayerConfig,
) -> reovim_driver_layout::LayerId {
reovim_driver_layout::LayerId::new(0)
}
fn remove_layer(&mut self, _layer: reovim_driver_layout::LayerId) {}
fn layer_by_label(&self, _label: &str) -> Option<reovim_driver_layout::LayerId> {
None
}
fn layers(&self) -> Vec<&reovim_driver_layout::Layer> {
Vec::new()
}
fn set_layer_visible(&mut self, _layer: reovim_driver_layout::LayerId, _visible: bool) {}
fn set_layer_opacity(&mut self, _layer: reovim_driver_layout::LayerId, _opacity: f32) {}
fn reorder_layer(&mut self, _layer: reovim_driver_layout::LayerId, _new_z: u16) {}
fn set_active_layer(&mut self, _layer: reovim_driver_layout::LayerId) {}
fn active_layer(&self) -> Option<reovim_driver_layout::LayerId> {
Some(reovim_driver_layout::LayerId::new(0))
}
fn set_focus(&mut self, window: WindowId) {
self.focused = Some(window);
reovim_driver_layout::WindowLayerCompositor::set_focus(&mut self.layer, window);
}
fn focused(&self) -> Option<WindowId> {
self.focused
}
fn focus_at(&mut self, _x: u16, _y: u16) -> Option<WindowId> {
self.focused
}
fn layer_compositor(
&self,
_layer: reovim_driver_layout::LayerId,
) -> Option<&dyn reovim_driver_layout::WindowLayerCompositor> {
Some(&self.layer)
}
fn layer_compositor_mut(
&mut self,
_layer: reovim_driver_layout::LayerId,
) -> Option<&mut dyn reovim_driver_layout::WindowLayerCompositor> {
Some(&mut self.layer)
}
fn window_count(&self) -> usize {
self.layer.windows.len()
}
fn set_screen(&mut self, _screen: Rect) {}
fn layer_of(&self, _window: WindowId) -> Option<reovim_driver_layout::LayerId> {
Some(reovim_driver_layout::LayerId::new(0))
}
fn boxed_clone(&self) -> Box<dyn reovim_driver_layout::RootCompositor> {
Box::new(Self {
layer: MockLayerCompositor {
id: self.layer.id,
windows: self.layer.windows.clone(),
focused: self.layer.focused,
next_id: self.layer.next_id,
},
focused: self.focused,
})
}
}
fn make_compositor_runtime<'a>(
session: &'a mut Session,
client: crate::ClientContext<'a>,
kernel: &'a KernelContext,
executor: &'a StubExecutor,
) -> SessionRuntime<'a> {
*client.compositor = Some(Box::new(MockRootCompositor::new()));
SessionRuntime::new(session, client, kernel, executor)
}
#[test]
fn test_compositor_navigate() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut ms = ModeStack::new(test_mode());
let mut w = crate::WindowLayout::empty();
let mut e = crate::ExtensionMap::new();
let mut c = None;
let mut tabs = crate::TabPageSet::new();
let mut r = RegisterBank::new();
let mut ch = HistoryRing::new();
let mut lm = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let rt = make_compositor_runtime(
&mut session,
crate::ClientContext {
mode_stack: &mut ms,
windows: &mut w,
extensions: &mut e,
compositor: &mut c,
tabs: &mut tabs,
registers: &mut r,
clipboard_history: &mut ch,
local_marks: &mut lm,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
let result = rt.navigate(NavigateDirection::Right);
assert!(result.is_ok());
assert_eq!(result.unwrap(), WindowId::from_raw(2));
}
#[test]
fn test_compositor_split() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut ms = ModeStack::new(test_mode());
let mut w = crate::WindowLayout::empty();
let mut e = crate::ExtensionMap::new();
let mut c = None;
let mut tabs = crate::TabPageSet::new();
let mut r = RegisterBank::new();
let mut ch = HistoryRing::new();
let mut lm = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut rt = make_compositor_runtime(
&mut session,
crate::ClientContext {
mode_stack: &mut ms,
windows: &mut w,
extensions: &mut e,
compositor: &mut c,
tabs: &mut tabs,
registers: &mut r,
clipboard_history: &mut ch,
local_marks: &mut lm,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
let result = rt.split(reovim_driver_layout::SplitDirection::Horizontal);
assert!(result.is_ok());
assert!(rt.changes.windows_created.contains(&result.unwrap()));
}
#[test]
fn test_compositor_close_current_window() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut ms = ModeStack::new(test_mode());
let mut w = crate::WindowLayout::empty();
let mut e = crate::ExtensionMap::new();
let mut c = None;
let mut tabs = crate::TabPageSet::new();
let mut r = RegisterBank::new();
let mut ch = HistoryRing::new();
let mut lm = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut rt = make_compositor_runtime(
&mut session,
crate::ClientContext {
mode_stack: &mut ms,
windows: &mut w,
extensions: &mut e,
compositor: &mut c,
tabs: &mut tabs,
registers: &mut r,
clipboard_history: &mut ch,
local_marks: &mut lm,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
let result = rt.close_current_window();
assert!(result.is_ok());
assert_eq!(result.unwrap(), WindowId::from_raw(2));
}
#[test]
fn test_compositor_close_others() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut ms = ModeStack::new(test_mode());
let mut w = crate::WindowLayout::empty();
let mut e = crate::ExtensionMap::new();
let mut c = None;
let mut tabs = crate::TabPageSet::new();
let mut r = RegisterBank::new();
let mut ch = HistoryRing::new();
let mut lm = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut rt = make_compositor_runtime(
&mut session,
crate::ClientContext {
mode_stack: &mut ms,
windows: &mut w,
extensions: &mut e,
compositor: &mut c,
tabs: &mut tabs,
registers: &mut r,
clipboard_history: &mut ch,
local_marks: &mut lm,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
let result = rt.close_others();
assert!(result.is_ok());
assert!(rt.changes.windows_closed.contains(&WindowId::from_raw(2)));
}
#[test]
fn test_compositor_resize() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut ms = ModeStack::new(test_mode());
let mut w = crate::WindowLayout::empty();
let mut e = crate::ExtensionMap::new();
let mut c = None;
let mut tabs = crate::TabPageSet::new();
let mut r = RegisterBank::new();
let mut ch = HistoryRing::new();
let mut lm = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut rt = make_compositor_runtime(
&mut session,
crate::ClientContext {
mode_stack: &mut ms,
windows: &mut w,
extensions: &mut e,
compositor: &mut c,
tabs: &mut tabs,
registers: &mut r,
clipboard_history: &mut ch,
local_marks: &mut lm,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
let result = rt.resize(NavigateDirection::Right, 5);
assert!(result.is_ok());
assert!(rt.changes.window_changed);
}
#[test]
fn test_compositor_equalize() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut ms = ModeStack::new(test_mode());
let mut w = crate::WindowLayout::empty();
let mut e = crate::ExtensionMap::new();
let mut c = None;
let mut tabs = crate::TabPageSet::new();
let mut r = RegisterBank::new();
let mut ch = HistoryRing::new();
let mut lm = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut rt = make_compositor_runtime(
&mut session,
crate::ClientContext {
mode_stack: &mut ms,
windows: &mut w,
extensions: &mut e,
compositor: &mut c,
tabs: &mut tabs,
registers: &mut r,
clipboard_history: &mut ch,
local_marks: &mut lm,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
let result = rt.equalize();
assert!(result.is_ok());
assert!(rt.changes.window_changed);
}
#[test]
fn test_compositor_cycle() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut ms = ModeStack::new(test_mode());
let mut w = crate::WindowLayout::empty();
let mut e = crate::ExtensionMap::new();
let mut c = None;
let mut tabs = crate::TabPageSet::new();
let mut r = RegisterBank::new();
let mut ch = HistoryRing::new();
let mut lm = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let rt = make_compositor_runtime(
&mut session,
crate::ClientContext {
mode_stack: &mut ms,
windows: &mut w,
extensions: &mut e,
compositor: &mut c,
tabs: &mut tabs,
registers: &mut r,
clipboard_history: &mut ch,
local_marks: &mut lm,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
let result = rt.cycle(true);
assert!(result.is_ok());
assert_eq!(result.unwrap(), WindowId::from_raw(2));
}
#[test]
fn test_compositor_focus() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut ms = ModeStack::new(test_mode());
let mut w = crate::WindowLayout::empty();
let mut e = crate::ExtensionMap::new();
let mut c = None;
let mut tabs = crate::TabPageSet::new();
let mut r = RegisterBank::new();
let mut ch = HistoryRing::new();
let mut lm = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut rt = make_compositor_runtime(
&mut session,
crate::ClientContext {
mode_stack: &mut ms,
windows: &mut w,
extensions: &mut e,
compositor: &mut c,
tabs: &mut tabs,
registers: &mut r,
clipboard_history: &mut ch,
local_marks: &mut lm,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
let result = rt.focus(WindowId::from_raw(2));
assert!(result.is_ok());
assert!(rt.changes.focus_changed);
}
#[test]
fn test_compositor_focus_same_window_no_event() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut ms = ModeStack::new(test_mode());
let mut w = crate::WindowLayout::empty();
let mut e = crate::ExtensionMap::new();
let mut c = None;
let mut tabs = crate::TabPageSet::new();
let mut r = RegisterBank::new();
let mut ch = HistoryRing::new();
let mut lm = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut rt = make_compositor_runtime(
&mut session,
crate::ClientContext {
mode_stack: &mut ms,
windows: &mut w,
extensions: &mut e,
compositor: &mut c,
tabs: &mut tabs,
registers: &mut r,
clipboard_history: &mut ch,
local_marks: &mut lm,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
let result = rt.focus(WindowId::from_raw(1));
assert!(result.is_ok());
assert!(rt.changes.focus_changed);
}
#[test]
fn test_compositor_focused_window() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut ms = ModeStack::new(test_mode());
let mut w = crate::WindowLayout::empty();
let mut e = crate::ExtensionMap::new();
let mut c = None;
let mut tabs = crate::TabPageSet::new();
let mut r = RegisterBank::new();
let mut ch = HistoryRing::new();
let mut lm = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let rt = make_compositor_runtime(
&mut session,
crate::ClientContext {
mode_stack: &mut ms,
windows: &mut w,
extensions: &mut e,
compositor: &mut c,
tabs: &mut tabs,
registers: &mut r,
clipboard_history: &mut ch,
local_marks: &mut lm,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
assert_eq!(rt.focused_window(), Some(WindowId::from_raw(1)));
}
#[test]
fn test_compositor_window_count() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut ms = ModeStack::new(test_mode());
let mut w = crate::WindowLayout::empty();
let mut e = crate::ExtensionMap::new();
let mut c = None;
let mut tabs = crate::TabPageSet::new();
let mut r = RegisterBank::new();
let mut ch = HistoryRing::new();
let mut lm = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let rt = make_compositor_runtime(
&mut session,
crate::ClientContext {
mode_stack: &mut ms,
windows: &mut w,
extensions: &mut e,
compositor: &mut c,
tabs: &mut tabs,
registers: &mut r,
clipboard_history: &mut ch,
local_marks: &mut lm,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
assert_eq!(rt.compositor_window_count(), 2);
}
#[test]
fn test_compositor_active_layer() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut ms = ModeStack::new(test_mode());
let mut w = crate::WindowLayout::empty();
let mut e = crate::ExtensionMap::new();
let mut c = None;
let mut tabs = crate::TabPageSet::new();
let mut r = RegisterBank::new();
let mut ch = HistoryRing::new();
let mut lm = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let rt = make_compositor_runtime(
&mut session,
crate::ClientContext {
mode_stack: &mut ms,
windows: &mut w,
extensions: &mut e,
compositor: &mut c,
tabs: &mut tabs,
registers: &mut r,
clipboard_history: &mut ch,
local_marks: &mut lm,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
assert!(rt.active_layer().is_some());
}
#[test]
fn test_compositor_toggle_float() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut ms = ModeStack::new(test_mode());
let mut w = crate::WindowLayout::empty();
let mut e = crate::ExtensionMap::new();
let mut c = None;
let mut tabs = crate::TabPageSet::new();
let mut r = RegisterBank::new();
let mut ch = HistoryRing::new();
let mut lm = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut rt = make_compositor_runtime(
&mut session,
crate::ClientContext {
mode_stack: &mut ms,
windows: &mut w,
extensions: &mut e,
compositor: &mut c,
tabs: &mut tabs,
registers: &mut r,
clipboard_history: &mut ch,
local_marks: &mut lm,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
assert!(rt.toggle_float().is_ok());
assert!(rt.changes.window_changed);
}
#[test]
fn test_compositor_raise_float() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut ms = ModeStack::new(test_mode());
let mut w = crate::WindowLayout::empty();
let mut e = crate::ExtensionMap::new();
let mut c = None;
let mut tabs = crate::TabPageSet::new();
let mut r = RegisterBank::new();
let mut ch = HistoryRing::new();
let mut lm = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut rt = make_compositor_runtime(
&mut session,
crate::ClientContext {
mode_stack: &mut ms,
windows: &mut w,
extensions: &mut e,
compositor: &mut c,
tabs: &mut tabs,
registers: &mut r,
clipboard_history: &mut ch,
local_marks: &mut lm,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
assert!(rt.raise_float().is_ok());
}
#[test]
fn test_compositor_lower_float() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut ms = ModeStack::new(test_mode());
let mut w = crate::WindowLayout::empty();
let mut e = crate::ExtensionMap::new();
let mut c = None;
let mut tabs = crate::TabPageSet::new();
let mut r = RegisterBank::new();
let mut ch = HistoryRing::new();
let mut lm = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut rt = make_compositor_runtime(
&mut session,
crate::ClientContext {
mode_stack: &mut ms,
windows: &mut w,
extensions: &mut e,
compositor: &mut c,
tabs: &mut tabs,
registers: &mut r,
clipboard_history: &mut ch,
local_marks: &mut lm,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
assert!(rt.lower_float().is_ok());
}
#[test]
fn test_compositor_show_overlay() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut ms = ModeStack::new(test_mode());
let mut w = crate::WindowLayout::empty();
let mut e = crate::ExtensionMap::new();
let mut c = None;
let mut tabs = crate::TabPageSet::new();
let mut r = RegisterBank::new();
let mut ch = HistoryRing::new();
let mut lm = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut rt = make_compositor_runtime(
&mut session,
crate::ClientContext {
mode_stack: &mut ms,
windows: &mut w,
extensions: &mut e,
compositor: &mut c,
tabs: &mut tabs,
registers: &mut r,
clipboard_history: &mut ch,
local_marks: &mut lm,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
let result =
rt.show_overlay(reovim_driver_layout::OverlayConstraints::centered().with_size(20, 10));
assert!(result.is_ok());
}
#[test]
fn test_compositor_hide_overlay() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut ms = ModeStack::new(test_mode());
let mut w = crate::WindowLayout::empty();
let mut e = crate::ExtensionMap::new();
let mut c = None;
let mut tabs = crate::TabPageSet::new();
let mut r = RegisterBank::new();
let mut ch = HistoryRing::new();
let mut lm = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut rt = make_compositor_runtime(
&mut session,
crate::ClientContext {
mode_stack: &mut ms,
windows: &mut w,
extensions: &mut e,
compositor: &mut c,
tabs: &mut tabs,
registers: &mut r,
clipboard_history: &mut ch,
local_marks: &mut lm,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
assert!(rt.hide_overlay(WindowId::from_raw(99)).is_ok());
}
#[test]
fn test_compositor_resize_overlay() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut ms = ModeStack::new(test_mode());
let mut w = crate::WindowLayout::empty();
let mut e = crate::ExtensionMap::new();
let mut c = None;
let mut tabs = crate::TabPageSet::new();
let mut r = RegisterBank::new();
let mut ch = HistoryRing::new();
let mut lm = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut rt = make_compositor_runtime(
&mut session,
crate::ClientContext {
mode_stack: &mut ms,
windows: &mut w,
extensions: &mut e,
compositor: &mut c,
tabs: &mut tabs,
registers: &mut r,
clipboard_history: &mut ch,
local_marks: &mut lm,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
assert!(rt.resize_overlay(WindowId::from_raw(99), 40, 20).is_ok());
}
#[test]
fn test_compositor_hide_all_overlays() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut ms = ModeStack::new(test_mode());
let mut w = crate::WindowLayout::empty();
let mut e = crate::ExtensionMap::new();
let mut c = None;
let mut tabs = crate::TabPageSet::new();
let mut r = RegisterBank::new();
let mut ch = HistoryRing::new();
let mut lm = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut rt = make_compositor_runtime(
&mut session,
crate::ClientContext {
mode_stack: &mut ms,
windows: &mut w,
extensions: &mut e,
compositor: &mut c,
tabs: &mut tabs,
registers: &mut r,
clipboard_history: &mut ch,
local_marks: &mut lm,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
assert!(rt.hide_all_overlays().is_ok());
}
#[test]
fn test_compositor_set_active_layer_opacity() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut ms = ModeStack::new(test_mode());
let mut w = crate::WindowLayout::empty();
let mut e = crate::ExtensionMap::new();
let mut c = None;
let mut tabs = crate::TabPageSet::new();
let mut r = RegisterBank::new();
let mut ch = HistoryRing::new();
let mut lm = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut rt = make_compositor_runtime(
&mut session,
crate::ClientContext {
mode_stack: &mut ms,
windows: &mut w,
extensions: &mut e,
compositor: &mut c,
tabs: &mut tabs,
registers: &mut r,
clipboard_history: &mut ch,
local_marks: &mut lm,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
assert!(rt.set_active_layer_opacity(0.5).is_ok());
}
#[test]
fn test_compositor_set_active_layer_opacity_clamps() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut ms = ModeStack::new(test_mode());
let mut w = crate::WindowLayout::empty();
let mut e = crate::ExtensionMap::new();
let mut c = None;
let mut tabs = crate::TabPageSet::new();
let mut r = RegisterBank::new();
let mut ch = HistoryRing::new();
let mut lm = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut rt = make_compositor_runtime(
&mut session,
crate::ClientContext {
mode_stack: &mut ms,
windows: &mut w,
extensions: &mut e,
compositor: &mut c,
tabs: &mut tabs,
registers: &mut r,
clipboard_history: &mut ch,
local_marks: &mut lm,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
assert!(rt.set_active_layer_opacity(2.0).is_ok());
assert!(rt.set_active_layer_opacity(-1.0).is_ok());
}
#[test]
fn test_compositor_active_layer_opacity() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut ms = ModeStack::new(test_mode());
let mut w = crate::WindowLayout::empty();
let mut e = crate::ExtensionMap::new();
let mut c = None;
let mut tabs = crate::TabPageSet::new();
let mut r = RegisterBank::new();
let mut ch = HistoryRing::new();
let mut lm = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let rt = make_compositor_runtime(
&mut session,
crate::ClientContext {
mode_stack: &mut ms,
windows: &mut w,
extensions: &mut e,
compositor: &mut c,
tabs: &mut tabs,
registers: &mut r,
clipboard_history: &mut ch,
local_marks: &mut lm,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
let opacity = rt.active_layer_opacity().unwrap();
assert!((opacity - 1.0).abs() < f32::EPSILON);
}
#[test]
fn test_compositor_adjust_active_layer_opacity() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut ms = ModeStack::new(test_mode());
let mut w = crate::WindowLayout::empty();
let mut e = crate::ExtensionMap::new();
let mut c = None;
let mut tabs = crate::TabPageSet::new();
let mut r = RegisterBank::new();
let mut ch = HistoryRing::new();
let mut lm = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut rt = make_compositor_runtime(
&mut session,
crate::ClientContext {
mode_stack: &mut ms,
windows: &mut w,
extensions: &mut e,
compositor: &mut c,
tabs: &mut tabs,
registers: &mut r,
clipboard_history: &mut ch,
local_marks: &mut lm,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
let new_opacity = rt.adjust_active_layer_opacity(-0.3).unwrap();
assert!((new_opacity - 0.7).abs() < f32::EPSILON);
}
#[test]
fn test_set_screen_with_compositor() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut ms = ModeStack::new(test_mode());
let mut w = crate::WindowLayout::empty();
let mut e = crate::ExtensionMap::new();
let mut c = None;
let mut tabs = crate::TabPageSet::new();
let mut r = RegisterBank::new();
let mut ch = HistoryRing::new();
let mut lm = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut rt = make_compositor_runtime(
&mut session,
crate::ClientContext {
mode_stack: &mut ms,
windows: &mut w,
extensions: &mut e,
compositor: &mut c,
tabs: &mut tabs,
registers: &mut r,
clipboard_history: &mut ch,
local_marks: &mut lm,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
rt.set_screen(Rect::new(0, 0, 120, 40));
}
#[test]
fn test_emit_layout_event_with_compositor() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut ms = ModeStack::new(test_mode());
let mut w = crate::WindowLayout::empty();
let mut e = crate::ExtensionMap::new();
let mut c = None;
let mut tabs = crate::TabPageSet::new();
let mut r = RegisterBank::new();
let mut ch = HistoryRing::new();
let mut lm = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let rt = make_compositor_runtime(
&mut session,
crate::ClientContext {
mode_stack: &mut ms,
windows: &mut w,
extensions: &mut e,
compositor: &mut c,
tabs: &mut tabs,
registers: &mut r,
clipboard_history: &mut ch,
local_marks: &mut lm,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
rt.emit_layout_event(reovim_kernel::api::v1::events::kernel::LayoutChangeKind::Equalize);
}
#[test]
fn test_arrange_with_compositor() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut ms = ModeStack::new(test_mode());
let mut w = crate::WindowLayout::empty();
let mut e = crate::ExtensionMap::new();
let mut c = None;
let mut tabs = crate::TabPageSet::new();
let mut r = RegisterBank::new();
let mut ch = HistoryRing::new();
let mut lm = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let rt = make_compositor_runtime(
&mut session,
crate::ClientContext {
mode_stack: &mut ms,
windows: &mut w,
extensions: &mut e,
compositor: &mut c,
tabs: &mut tabs,
registers: &mut r,
clipboard_history: &mut ch,
local_marks: &mut lm,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
let placements = rt.arrange(Rect::new(0, 0, 80, 24));
assert!(placements.is_empty());
}
struct SingleWindowLayerCompositor {
id: reovim_driver_layout::LayerId,
window: WindowId,
}
#[cfg_attr(coverage_nightly, coverage(off))]
impl reovim_driver_layout::WindowLayerCompositor for SingleWindowLayerCompositor {
fn id(&self) -> reovim_driver_layout::LayerId {
self.id
}
fn arrange(&self, _bounds: Rect) -> Vec<WindowPlacement> {
Vec::new()
}
fn add_tiled(&mut self) -> WindowId {
self.window
}
fn split_tiled(
&mut self,
_from: WindowId,
_direction: reovim_driver_layout::SplitDirection,
) -> Option<WindowId> {
None
}
fn navigate_tiled(&self, _from: WindowId, _direction: NavigateDirection) -> Option<WindowId> {
None
}
fn resize_tiled(&mut self, _window: WindowId, _direction: NavigateDirection, _delta: i16) {}
fn close_tiled(&mut self, _window: WindowId) -> Option<WindowId> {
None
}
fn equalize_tiled(&mut self) {}
fn cycle_tiled(&self, _from: WindowId, _forward: bool) -> Option<WindowId> {
None
}
fn create_float(&mut self, _bounds: Rect) -> WindowId {
self.window
}
fn move_float(&mut self, _window: WindowId, _x: u16, _y: u16) {}
fn resize_float(&mut self, _window: WindowId, _width: u16, _height: u16) {}
fn raise_float(&mut self, _window: WindowId) {}
fn lower_float(&mut self, _window: WindowId) {}
fn close_float(&mut self, _window: WindowId) {}
fn toggle_float(&mut self, _window: WindowId) {}
fn show_overlay(&mut self, _constraints: OverlayConstraints) -> WindowId {
self.window
}
fn hide_overlay(&mut self, _window: WindowId) {}
fn resize_overlay(&mut self, _window: WindowId, _width: u16, _height: u16) {}
fn hide_all_overlays(&mut self) {}
fn set_focus(&mut self, _window: WindowId) {}
fn focused(&self) -> Option<WindowId> {
Some(self.window)
}
fn windows_in_zone(&self, zone: reovim_driver_layout::Zone) -> Vec<WindowId> {
if zone == reovim_driver_layout::Zone::Tiled {
vec![self.window] } else {
Vec::new()
}
}
fn zone_of(&self, _window: WindowId) -> Option<reovim_driver_layout::Zone> {
Some(reovim_driver_layout::Zone::Tiled)
}
}
struct SingleWindowRootCompositor {
layer: SingleWindowLayerCompositor,
}
impl SingleWindowRootCompositor {
fn new() -> Self {
Self {
layer: SingleWindowLayerCompositor {
id: reovim_driver_layout::LayerId::new(0),
window: WindowId::from_raw(1),
},
}
}
}
#[cfg_attr(coverage_nightly, coverage(off))]
impl reovim_driver_layout::RootCompositor for SingleWindowRootCompositor {
fn composite(&self, screen: Rect) -> reovim_driver_layout::CompositeResult {
reovim_driver_layout::CompositeResult::empty(screen)
}
fn create_layer(
&mut self,
_config: reovim_driver_layout::LayerConfig,
) -> reovim_driver_layout::LayerId {
reovim_driver_layout::LayerId::new(0)
}
fn remove_layer(&mut self, _layer: reovim_driver_layout::LayerId) {}
fn layer_by_label(&self, _label: &str) -> Option<reovim_driver_layout::LayerId> {
None
}
fn layers(&self) -> Vec<&reovim_driver_layout::Layer> {
Vec::new()
}
fn set_layer_visible(&mut self, _layer: reovim_driver_layout::LayerId, _visible: bool) {}
fn set_layer_opacity(&mut self, _layer: reovim_driver_layout::LayerId, _opacity: f32) {}
fn reorder_layer(&mut self, _layer: reovim_driver_layout::LayerId, _new_z: u16) {}
fn set_active_layer(&mut self, _layer: reovim_driver_layout::LayerId) {}
fn active_layer(&self) -> Option<reovim_driver_layout::LayerId> {
Some(reovim_driver_layout::LayerId::new(0))
}
fn set_focus(&mut self, _window: WindowId) {}
fn focused(&self) -> Option<WindowId> {
Some(self.layer.window)
}
fn focus_at(&mut self, _x: u16, _y: u16) -> Option<WindowId> {
Some(self.layer.window)
}
fn layer_compositor(
&self,
_layer: reovim_driver_layout::LayerId,
) -> Option<&dyn reovim_driver_layout::WindowLayerCompositor> {
Some(&self.layer)
}
fn layer_compositor_mut(
&mut self,
_layer: reovim_driver_layout::LayerId,
) -> Option<&mut dyn reovim_driver_layout::WindowLayerCompositor> {
Some(&mut self.layer)
}
fn window_count(&self) -> usize {
1
}
fn set_screen(&mut self, _screen: Rect) {}
fn layer_of(&self, _window: WindowId) -> Option<reovim_driver_layout::LayerId> {
Some(reovim_driver_layout::LayerId::new(0))
}
fn boxed_clone(&self) -> Box<dyn reovim_driver_layout::RootCompositor> {
Box::new(Self::new())
}
}
#[test]
fn test_compositor_close_current_window_single_window() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut ms = ModeStack::new(test_mode());
let mut w = crate::WindowLayout::empty();
let mut e = crate::ExtensionMap::new();
let mut c: Option<Box<dyn reovim_driver_layout::RootCompositor>> =
Some(Box::new(SingleWindowRootCompositor::new()));
let mut tabs = crate::TabPageSet::new();
let mut r = RegisterBank::new();
let mut ch = HistoryRing::new();
let mut lm = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut rt = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut ms,
windows: &mut w,
extensions: &mut e,
compositor: &mut c,
tabs: &mut tabs,
registers: &mut r,
clipboard_history: &mut ch,
local_marks: &mut lm,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
let result = rt.close_current_window();
assert!(result.is_err());
assert!(matches!(result.unwrap_err(), CompositorError::CannotCloseLastWindow));
}
#[test]
fn test_record_cursor_move_extends_selection() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut ms = ModeStack::new(test_mode());
let mut w = crate::WindowLayout::empty();
let mut e = crate::ExtensionMap::new();
let mut c = None;
let mut tabs = crate::TabPageSet::new();
let mut r = RegisterBank::new();
let mut ch = HistoryRing::new();
let mut lm = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut window = crate::Window::new();
window.cursor = Position::new(0, 5).into();
window.selection =
Some(crate::api::Selection::character(Position::new(0, 0), Position::new(0, 1)));
w.add(window);
let buf = BufferId::new();
let mut rt = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut ms,
windows: &mut w,
extensions: &mut e,
compositor: &mut c,
tabs: &mut tabs,
registers: &mut r,
clipboard_history: &mut ch,
local_marks: &mut lm,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
rt.record_cursor_move(buf);
let changes = rt.take_changes();
assert!(changes.cursor_moved);
assert!(changes.selection_changed);
let sel = rt.windows().active().unwrap().selection.as_ref().unwrap();
assert_eq!(sel.end, Position::new(0, 6));
}
#[test]
fn test_record_cursor_move_no_selection() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut ms = ModeStack::new(test_mode());
let mut w = crate::WindowLayout::empty();
let mut e = crate::ExtensionMap::new();
let mut c = None;
let mut tabs = crate::TabPageSet::new();
let mut r = RegisterBank::new();
let mut ch = HistoryRing::new();
let mut lm = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut window = crate::Window::new();
window.cursor = Position::new(0, 3).into();
w.add(window);
let buf = BufferId::new();
let mut rt = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut ms,
windows: &mut w,
extensions: &mut e,
compositor: &mut c,
tabs: &mut tabs,
registers: &mut r,
clipboard_history: &mut ch,
local_marks: &mut lm,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
rt.record_cursor_move(buf);
let changes = rt.take_changes();
assert!(changes.cursor_moved);
assert!(!changes.selection_changed);
}
#[test]
fn test_record_cursor_move_no_active_window() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut ms = ModeStack::new(test_mode());
let mut w = crate::WindowLayout::empty(); let mut e = crate::ExtensionMap::new();
let mut c = None;
let mut tabs = crate::TabPageSet::new();
let mut r = RegisterBank::new();
let mut ch = HistoryRing::new();
let mut lm = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let buf = BufferId::new();
let mut rt = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut ms,
windows: &mut w,
extensions: &mut e,
compositor: &mut c,
tabs: &mut tabs,
registers: &mut r,
clipboard_history: &mut ch,
local_marks: &mut lm,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
rt.record_cursor_move(buf);
let changes = rt.take_changes();
assert!(changes.cursor_moved);
assert!(!changes.selection_changed);
}
#[test]
fn test_record_selection_change_directly() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut ms = ModeStack::new(test_mode());
let mut w = crate::WindowLayout::empty();
let mut e = crate::ExtensionMap::new();
let mut c = None;
let mut tabs = crate::TabPageSet::new();
let mut r = RegisterBank::new();
let mut ch = HistoryRing::new();
let mut lm = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let buf = BufferId::new();
let mut rt = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut ms,
windows: &mut w,
extensions: &mut e,
compositor: &mut c,
tabs: &mut tabs,
registers: &mut r,
clipboard_history: &mut ch,
local_marks: &mut lm,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
rt.record_selection_change(buf);
let changes = rt.take_changes();
assert!(changes.selection_changed);
assert!(changes.affected_buffers.contains(&buf));
}
#[test]
fn test_compositor_focus_same_window_no_layout_event() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut ms = ModeStack::new(test_mode());
let mut w = crate::WindowLayout::empty();
let mut e = crate::ExtensionMap::new();
let mut c = None;
let mut tabs = crate::TabPageSet::new();
let mut r = RegisterBank::new();
let mut ch = HistoryRing::new();
let mut lm = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut rt = make_compositor_runtime(
&mut session,
crate::ClientContext {
mode_stack: &mut ms,
windows: &mut w,
extensions: &mut e,
compositor: &mut c,
tabs: &mut tabs,
registers: &mut r,
clipboard_history: &mut ch,
local_marks: &mut lm,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
let already_focused = WindowId::from_raw(1);
let result = rt.focus(already_focused);
assert!(result.is_ok());
let changes = rt.take_changes();
assert!(changes.focus_changed);
}
#[test]
fn test_delete_range_empty_result_no_undo_record() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("hello world");
let buffer_id = harness.with_runtime(|runtime| runtime.active_buffer().unwrap());
harness.with_runtime(|runtime| {
runtime.delete_range(buffer_id, Position::new(0, 3), Position::new(0, 3));
});
harness.assert_buffer_content("hello world");
let changes = harness.take_changes();
assert!(changes.buffer_modified);
}
#[test]
fn test_set_screen_without_compositor() {
use reovim_kernel::api::v1::ModeStack;
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut ms = ModeStack::new(test_mode());
let mut w = crate::WindowLayout::empty();
let mut e = crate::ExtensionMap::new();
let mut c: Option<Box<dyn reovim_driver_layout::RootCompositor>> = None;
let mut tabs = crate::TabPageSet::new();
let mut r = RegisterBank::new();
let mut ch = HistoryRing::new();
let mut lm = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut rt = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut ms,
windows: &mut w,
extensions: &mut e,
compositor: &mut c,
tabs: &mut tabs,
registers: &mut r,
clipboard_history: &mut ch,
local_marks: &mut lm,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
let screen = Rect::new(0, 0, 80, 24);
rt.set_screen(screen);
assert_eq!(rt.screen, screen);
}
#[test]
fn test_registers_accessor() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
harness.with_runtime(|runtime| {
let bank = runtime.registers();
assert!(bank.get().is_empty());
});
}
#[test]
fn test_registers_mut_accessor() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
harness.with_runtime(|runtime| {
let bank = runtime.registers_mut();
bank.set_by_name(Some('a'), crate::api::RegisterContent::characterwise("test"));
assert_eq!(bank.get_named('a').map(|r| r.text.as_str()), Some("test"));
});
}
#[test]
fn test_clipboard_history_accessor() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
harness.with_runtime(|runtime| {
let history = runtime.clipboard_history();
assert!(history.is_empty());
});
}
#[test]
fn test_clipboard_history_mut_accessor() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
harness.with_runtime(|runtime| {
let history = runtime.clipboard_history_mut();
history.push(crate::api::RegisterContent::characterwise("entry"));
assert_eq!(history.len(), 1);
});
}
#[test]
fn test_local_marks_accessor() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
harness.with_runtime(|runtime| {
let marks = runtime.local_marks();
assert!(marks.get_local('a').is_none());
});
}
#[test]
fn test_local_marks_mut_accessor() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
harness.with_runtime(|runtime| {
let marks = runtime.local_marks_mut();
marks.set_local('a', reovim_kernel::api::v1::Position::new(0, 5));
assert!(marks.get_local('a').is_some());
});
}
#[test]
fn test_clipboard_api_no_provider_copy_to_clipboard() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
harness.with_runtime(|runtime| {
assert!(!runtime.copy_to_clipboard("test"));
});
}
#[test]
fn test_clipboard_api_no_provider_paste_from_clipboard() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
harness.with_runtime(|runtime| {
assert!(runtime.paste_from_clipboard().is_none());
});
}
#[test]
fn test_clipboard_api_no_provider_copy_to_selection() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
harness.with_runtime(|runtime| {
assert!(!runtime.copy_to_selection("test"));
});
}
#[test]
fn test_clipboard_api_no_provider_paste_from_selection() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
harness.with_runtime(|runtime| {
assert!(runtime.paste_from_selection().is_none());
});
}
#[test]
fn test_buffer_api_active_buffer_trait_qualified() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
harness.with_runtime(|runtime| {
assert!(BufferApi::active_buffer(runtime).is_none());
});
let mut harness = TestSessionRuntime::with_buffer("hello");
harness.with_runtime(|runtime| {
let buf_id = BufferApi::active_buffer(runtime);
assert!(buf_id.is_some());
BufferApi::set_active_buffer(runtime, None);
assert!(BufferApi::active_buffer(runtime).is_none());
BufferApi::set_active_buffer(runtime, buf_id);
assert_eq!(BufferApi::active_buffer(runtime), buf_id);
});
}
#[test]
fn test_signal_queue_initially_empty() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("");
harness.with_runtime(|runtime| {
let signals = runtime.take_signals();
assert!(signals.is_empty());
});
}
#[test]
fn test_signal_push_and_take() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("");
harness.with_runtime(|runtime| {
runtime.signal(RuntimeSignal::Quit);
let signals = runtime.take_signals();
assert_eq!(signals.len(), 1);
assert_eq!(signals[0], RuntimeSignal::Quit);
});
}
#[test]
fn test_signal_take_drains_queue() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("");
harness.with_runtime(|runtime| {
runtime.signal(RuntimeSignal::Quit);
let first = runtime.take_signals();
assert_eq!(first.len(), 1);
let second = runtime.take_signals();
assert!(second.is_empty());
});
}
#[test]
fn test_signal_multiple_fifo_order() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("");
harness.with_runtime(|runtime| {
runtime.signal(RuntimeSignal::Quit);
runtime.signal(RuntimeSignal::Quit);
runtime.signal(RuntimeSignal::Quit);
let signals = runtime.take_signals();
assert_eq!(signals.len(), 3);
for s in &signals {
assert_eq!(*s, RuntimeSignal::Quit);
}
});
}
#[test]
fn test_signal_queue_independent_of_state_changes() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("hello");
harness.with_runtime(|runtime| {
runtime.signal(RuntimeSignal::Quit);
let changes = runtime.take_changes();
let signals = runtime.take_signals();
assert_eq!(signals.len(), 1);
drop(changes);
});
}
#[test]
fn test_record_cursor_move_emits_cursor_moved_event() {
use {
reovim_kernel::api::v1::{EventResult, ModeStack, events::kernel::CursorMoved},
std::sync::{
Arc,
atomic::{AtomicBool, AtomicU64, Ordering},
},
};
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut ms = ModeStack::new(test_mode());
let mut w = crate::WindowLayout::empty();
let mut e = crate::ExtensionMap::new();
let mut c = None;
let mut tabs = crate::TabPageSet::new();
let mut r = RegisterBank::new();
let mut ch = HistoryRing::new();
let mut lm = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut window = crate::Window::new();
window.cursor = Position::new(3, 7).into();
w.add(window);
let received = Arc::new(AtomicBool::new(false));
let received_buf = Arc::new(AtomicU64::new(0));
let received_to_line = Arc::new(AtomicU64::new(0));
let received_to_col = Arc::new(AtomicU64::new(0));
let received_from_line = Arc::new(AtomicU64::new(0));
let received_from_col = Arc::new(AtomicU64::new(0));
let r1 = Arc::clone(&received);
let rb = Arc::clone(&received_buf);
let rtl = Arc::clone(&received_to_line);
let rtc = Arc::clone(&received_to_col);
let rfl = Arc::clone(&received_from_line);
let rfc = Arc::clone(&received_from_col);
let _sub = kernel
.event_bus
.subscribe::<CursorMoved, _>(50, move |event| {
r1.store(true, Ordering::SeqCst);
rb.store(event.buffer_id, Ordering::SeqCst);
rtl.store(u64::from(event.to.0), Ordering::SeqCst);
rtc.store(u64::from(event.to.1), Ordering::SeqCst);
rfl.store(u64::from(event.from.0), Ordering::SeqCst);
rfc.store(u64::from(event.from.1), Ordering::SeqCst);
EventResult::Handled
});
let buf = BufferId::new();
let mut rt = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut ms,
windows: &mut w,
extensions: &mut e,
compositor: &mut c,
tabs: &mut tabs,
registers: &mut r,
clipboard_history: &mut ch,
local_marks: &mut lm,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
rt.record_cursor_move(buf);
assert!(received.load(Ordering::SeqCst));
assert_eq!(received_buf.load(Ordering::SeqCst), buf.as_usize() as u64);
assert_eq!(received_from_line.load(Ordering::SeqCst), 3);
assert_eq!(received_from_col.load(Ordering::SeqCst), 7);
assert_eq!(received_to_line.load(Ordering::SeqCst), 3);
assert_eq!(received_to_col.load(Ordering::SeqCst), 7);
}
#[test]
fn test_record_cursor_move_no_window_no_event() {
use {
reovim_kernel::api::v1::{EventResult, ModeStack, events::kernel::CursorMoved},
std::sync::{
Arc,
atomic::{AtomicBool, Ordering},
},
};
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut ms = ModeStack::new(test_mode());
let mut w = crate::WindowLayout::empty(); let mut e = crate::ExtensionMap::new();
let mut c = None;
let mut tabs = crate::TabPageSet::new();
let mut r = RegisterBank::new();
let mut ch = HistoryRing::new();
let mut lm = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let received = Arc::new(AtomicBool::new(false));
let r1 = Arc::clone(&received);
let _sub = kernel.event_bus.subscribe::<CursorMoved, _>(50, move |_| {
r1.store(true, Ordering::SeqCst);
EventResult::Handled
});
let buf = BufferId::new();
let mut rt = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut ms,
windows: &mut w,
extensions: &mut e,
compositor: &mut c,
tabs: &mut tabs,
registers: &mut r,
clipboard_history: &mut ch,
local_marks: &mut lm,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
rt.record_cursor_move(buf);
assert!(!received.load(Ordering::SeqCst));
}
#[test]
fn test_record_cursor_move_multiple_updates_snapshot() {
use {
reovim_kernel::api::v1::{EventResult, ModeStack, events::kernel::CursorMoved},
std::sync::{Arc, Mutex},
};
let mut session = Session::new(ClientId::new(1), test_mode());
let kernel = KernelContext::default();
let executor = StubExecutor;
let mut ms = ModeStack::new(test_mode());
let mut w = crate::WindowLayout::empty();
let mut e = crate::ExtensionMap::new();
let mut c = None;
let mut tabs = crate::TabPageSet::new();
let mut r = RegisterBank::new();
let mut ch = HistoryRing::new();
let mut lm = MarkBank::new();
let mut jumplist = Jumplist::new();
let mut active_buffer = None;
let mut terminal_size = (80u16, 24u16);
let mut window = crate::Window::new();
window.cursor = Position::new(0, 0).into();
w.add(window);
#[allow(clippy::type_complexity)]
let events: Arc<Mutex<Vec<(u32, u32, u32, u32)>>> = Arc::new(Mutex::new(Vec::new()));
let events_clone = Arc::clone(&events);
let _sub = kernel
.event_bus
.subscribe::<CursorMoved, _>(50, move |event| {
events_clone
.lock()
.unwrap()
.push((event.from.0, event.from.1, event.to.0, event.to.1));
EventResult::Handled
});
let buf = BufferId::new();
let mut rt = SessionRuntime::new(
&mut session,
crate::ClientContext {
mode_stack: &mut ms,
windows: &mut w,
extensions: &mut e,
compositor: &mut c,
tabs: &mut tabs,
registers: &mut r,
clipboard_history: &mut ch,
local_marks: &mut lm,
jumplist: &mut jumplist,
active_buffer: &mut active_buffer,
terminal_size: &mut terminal_size,
},
&kernel,
&executor,
);
rt.record_cursor_move(buf);
rt.windows_mut().active_mut().unwrap().cursor = Position::new(5, 10).into();
rt.record_cursor_move(buf);
let captured = events.lock().unwrap();
assert_eq!(captured.len(), 2);
assert_eq!(captured[0], (0, 0, 0, 0));
assert_eq!(captured[1], (0, 0, 5, 10));
drop(captured);
}
#[test]
fn test_tab_new() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
harness.with_runtime(|runtime| {
assert_eq!(runtime.tab_count(), 1);
let id = runtime.tab_new().expect("tab_new should succeed");
assert_eq!(runtime.tab_count(), 2);
assert_eq!(runtime.active_tab_id(), Some(id));
});
assert!(harness.changes().window_changed);
}
#[test]
fn test_tab_close() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
harness.with_runtime(|runtime| {
runtime.tab_new().expect("tab_new should succeed");
assert_eq!(runtime.tab_count(), 2);
runtime.tab_close().expect("tab_close should succeed");
assert_eq!(runtime.tab_count(), 1);
});
assert!(harness.changes().window_changed);
}
#[test]
fn test_tab_close_last_tab_fails() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
harness.with_runtime(|runtime| {
assert_eq!(runtime.tab_count(), 1);
let result = runtime.tab_close();
assert!(result.is_err());
});
}
#[test]
fn test_tab_next() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
harness.with_runtime(|runtime| {
let tab1_id = runtime.active_tab_id().unwrap();
let tab2_id = runtime.tab_new().expect("tab_new should succeed");
assert_eq!(runtime.active_tab_id(), Some(tab2_id));
let next_id = runtime.tab_next().expect("tab_next should succeed");
assert_eq!(next_id, tab1_id);
});
assert!(harness.changes().window_changed);
}
#[test]
fn test_tab_prev() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
harness.with_runtime(|runtime| {
let tab1_id = runtime.active_tab_id().unwrap();
runtime.tab_new().expect("tab_new should succeed");
let prev_id = runtime.tab_prev().expect("tab_prev should succeed");
assert_eq!(prev_id, tab1_id);
});
assert!(harness.changes().window_changed);
}
#[test]
fn test_tab_goto_valid() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
harness.with_runtime(|runtime| {
let tab1_id = runtime.active_tab_id().unwrap();
runtime.tab_new().expect("tab_new should succeed");
let result = runtime.tab_goto(0);
assert!(result.is_ok());
assert_eq!(runtime.active_tab_id(), Some(tab1_id));
});
assert!(harness.changes().window_changed);
}
#[test]
fn test_tab_goto_invalid_index() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
harness.with_runtime(|runtime| {
let result = runtime.tab_goto(5);
assert!(result.is_err());
});
}
#[test]
fn test_tab_count_and_active_tab_id() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
harness.with_runtime(|runtime| {
assert_eq!(runtime.tab_count(), 1);
assert!(runtime.active_tab_id().is_some());
});
}
#[test]
fn test_jumplist_accessor() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::new();
harness.with_runtime(|runtime| {
let jl = runtime.jumplist();
assert!(jl.is_empty());
});
}
#[test]
fn test_jumplist_mut_accessor() {
use {crate::testing::TestSessionRuntime, reovim_kernel::api::v1::JumpEntry};
let mut harness = TestSessionRuntime::new();
harness.with_runtime(|runtime| {
let jl = runtime.jumplist_mut();
jl.push(JumpEntry::new(BufferId::new(), Position::new(5, 10)));
assert!(!jl.is_empty());
});
}
#[test]
fn test_kernel_and_registers_accessor() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("hello");
harness.with_runtime(|runtime| {
let (kernel, regs, history) = runtime.kernel_and_registers();
assert!(kernel.buffers.count() > 0);
regs.set_by_name(Some('a'), crate::api::RegisterContent::characterwise("test"));
assert_eq!(regs.get_named('a').map(|r| r.text.as_str()), Some("test"));
assert!(history.is_empty());
});
}
#[test]
fn test_record_buffer_modified_inherent() {
use crate::testing::TestSessionRuntime;
let mut harness = TestSessionRuntime::with_buffer("hello");
let changes = harness.with_runtime(|runtime| {
let buf = runtime.active_buffer().unwrap();
runtime.record_buffer_modified(buf);
runtime.take_changes()
});
assert!(!changes.modified_buffers.is_empty());
}