1use std::cell::RefCell;
18use std::iter;
19use std::ops::Range;
20use std::path::Path;
21use std::time::{Duration, Instant};
22
23use serde_json::{self, Value};
24
25use xi_rope::{Cursor, Interval, LinesMetric, Rope, RopeDelta};
26use xi_rpc::{Error as RpcError, RemoteError};
27use xi_trace::trace_block;
28
29use crate::plugins::rpc::{
30 ClientPluginInfo, Hover, PluginBufferInfo, PluginNotification, PluginRequest, PluginUpdate,
31};
32use crate::rpc::{EditNotification, EditRequest, LineRange, Position as ClientPosition};
33
34use crate::client::Client;
35use crate::config::{BufferItems, Table};
36use crate::edit_types::{EventDomain, SpecialEvent};
37use crate::editor::Editor;
38use crate::file::FileInfo;
39use crate::plugins::Plugin;
40use crate::recorder::Recorder;
41use crate::selection::InsertDrift;
42use crate::styles::ThemeStyleMap;
43use crate::syntax::LanguageId;
44use crate::tabs::{
45 BufferId, PluginId, ViewId, FIND_VIEW_IDLE_MASK, RENDER_VIEW_IDLE_MASK, REWRAP_VIEW_IDLE_MASK,
46};
47use crate::view::View;
48use crate::width_cache::WidthCache;
49use crate::WeakXiCore;
50
51pub const MAX_SIZE_LIMIT: usize = 1024 * 1024;
53
54const RENDER_DELAY: Duration = Duration::from_millis(2);
59
60pub struct EventContext<'a> {
65 pub(crate) view_id: ViewId,
66 pub(crate) buffer_id: BufferId,
67 pub(crate) editor: &'a RefCell<Editor>,
68 pub(crate) info: Option<&'a FileInfo>,
69 pub(crate) config: &'a BufferItems,
70 pub(crate) recorder: &'a RefCell<Recorder>,
71 pub(crate) language: LanguageId,
72 pub(crate) view: &'a RefCell<View>,
73 pub(crate) siblings: Vec<&'a RefCell<View>>,
74 pub(crate) plugins: Vec<&'a Plugin>,
75 pub(crate) client: &'a Client,
76 pub(crate) style_map: &'a RefCell<ThemeStyleMap>,
77 pub(crate) width_cache: &'a RefCell<WidthCache>,
78 pub(crate) kill_ring: &'a RefCell<Rope>,
79 pub(crate) weak_core: &'a WeakXiCore,
80}
81
82impl<'a> EventContext<'a> {
83 pub(crate) fn with_editor<R, F>(&mut self, f: F) -> R
86 where
87 F: FnOnce(&mut Editor, &mut View, &mut Rope, &BufferItems) -> R,
88 {
89 let mut editor = self.editor.borrow_mut();
90 let mut view = self.view.borrow_mut();
91 let mut kill_ring = self.kill_ring.borrow_mut();
92 f(&mut editor, &mut view, &mut kill_ring, &self.config)
93 }
94
95 fn with_view<R, F>(&mut self, f: F) -> R
99 where
100 F: FnOnce(&mut View, &Rope) -> R,
101 {
102 let editor = self.editor.borrow();
103 let mut view = self.view.borrow_mut();
104 f(&mut view, editor.get_buffer())
105 }
106
107 fn with_each_plugin<F: FnMut(&&Plugin)>(&self, f: F) {
108 self.plugins.iter().for_each(f)
109 }
110
111 pub(crate) fn do_edit(&mut self, cmd: EditNotification) {
112 let event: EventDomain = cmd.into();
113
114 {
115 let mut recorder = self.recorder.borrow_mut();
117 match (recorder.is_recording(), &event) {
118 (_, EventDomain::Special(SpecialEvent::ToggleRecording(recording_name))) => {
119 recorder.toggle_recording(recording_name.clone());
120 }
121 (true, EventDomain::Special(_)) => {
123 warn!("Special events cannot be recorded-- ignoring event {:?}", event)
124 }
125 (true, event) => recorder.record(event.clone()),
126 _ => {}
127 }
128 }
129
130 self.dispatch_event(event);
131 self.after_edit("core");
132 self.render_if_needed();
133 }
134
135 fn dispatch_event(&mut self, event: EventDomain) {
136 use self::EventDomain as E;
137 match event {
138 E::View(cmd) => {
139 self.with_view(|view, text| view.do_edit(text, cmd));
140 self.editor.borrow_mut().update_edit_type();
141 if self.with_view(|v, t| v.needs_wrap_in_visible_region(t)) {
142 self.rewrap();
143 }
144 if self.with_view(|v, _| v.find_in_progress()) {
145 self.do_incremental_find();
146 }
147 }
148 E::Buffer(cmd) => {
149 self.with_editor(|ed, view, k_ring, conf| ed.do_edit(view, k_ring, conf, cmd))
150 }
151 E::Special(cmd) => self.do_special(cmd),
152 }
153 }
154
155 fn do_special(&mut self, cmd: SpecialEvent) {
156 match cmd {
157 SpecialEvent::Resize(size) => {
158 self.with_view(|view, _| view.set_size(size));
159 if self.config.word_wrap {
160 self.update_wrap_settings(false);
161 }
162 }
163 SpecialEvent::DebugRewrap | SpecialEvent::DebugWrapWidth => {
164 warn!("debug wrapping methods are removed, use the config system")
165 }
166 SpecialEvent::DebugPrintSpans => self.with_editor(|ed, view, _, _| {
167 let sel = view.sel_regions().last().unwrap();
168 let iv = Interval::new(sel.min(), sel.max());
169 ed.get_layers().debug_print_spans(iv);
170 }),
171 SpecialEvent::RequestLines(LineRange { first, last }) => {
172 self.do_request_lines(first as usize, last as usize)
173 }
174 SpecialEvent::RequestHover { request_id, position } => {
175 self.do_request_hover(request_id, position)
176 }
177 SpecialEvent::DebugToggleComment => self.do_debug_toggle_comment(),
178 SpecialEvent::Reindent => self.do_reindent(),
179 SpecialEvent::ToggleRecording(_) => {}
180 SpecialEvent::PlayRecording(recording_name) => {
181 let recorder = self.recorder.borrow();
182
183 let starting_revision = self.editor.borrow_mut().get_head_rev_token();
184
185 self.editor.borrow_mut().update_edit_type();
187 self.editor.borrow_mut().calculate_undo_group();
188
189 self.editor.borrow_mut().set_force_undo_group(true);
191 recorder.play(&recording_name, |event| {
192 self.dispatch_event(event.clone());
193
194 let mut editor = self.editor.borrow_mut();
195 let (delta, last_text, drift) = match editor.commit_delta() {
196 Some(edit_info) => edit_info,
197 None => return,
198 };
199 self.update_views(&editor, &delta, &last_text, drift);
200 });
201 self.editor.borrow_mut().set_force_undo_group(false);
202
203 self.editor.borrow_mut().update_edit_type();
205
206 let delta = self.editor.borrow_mut().delta_rev_head(starting_revision).unwrap();
207 self.update_plugins(&mut self.editor.borrow_mut(), delta, "core");
208 }
209 SpecialEvent::ClearRecording(recording_name) => {
210 let mut recorder = self.recorder.borrow_mut();
211 recorder.clear(&recording_name);
212 }
213 }
214 }
215
216 pub(crate) fn do_edit_sync(&mut self, cmd: EditRequest) -> Result<Value, RemoteError> {
217 use self::EditRequest::*;
218 let result = match cmd {
219 Cut => Ok(self.with_editor(|ed, view, _, _| ed.do_cut(view))),
220 Copy => Ok(self.with_editor(|ed, view, _, _| ed.do_copy(view))),
221 };
222 self.after_edit("core");
223 self.render_if_needed();
224 result
225 }
226
227 pub(crate) fn do_plugin_cmd(&mut self, plugin: PluginId, cmd: PluginNotification) {
228 use self::PluginNotification::*;
229 match cmd {
230 AddScopes { scopes } => {
231 let mut ed = self.editor.borrow_mut();
232 let style_map = self.style_map.borrow();
233 ed.get_layers_mut().add_scopes(plugin, scopes, &style_map);
234 }
235 UpdateSpans { start, len, spans, rev } => self.with_editor(|ed, view, _, _| {
236 ed.update_spans(view, plugin, start, len, spans, rev)
237 }),
238 Edit { edit } => self.with_editor(|ed, _, _, _| ed.apply_plugin_edit(edit)),
239 Alert { msg } => self.client.alert(&msg),
240 AddStatusItem { key, value, alignment } => {
241 let plugin_name = &self.plugins.iter().find(|p| p.id == plugin).unwrap().name;
242 self.client.add_status_item(self.view_id, plugin_name, &key, &value, &alignment);
243 }
244 UpdateStatusItem { key, value } => {
245 self.client.update_status_item(self.view_id, &key, &value)
246 }
247 UpdateAnnotations { start, len, spans, annotation_type, rev } => {
248 self.with_editor(|ed, view, _, _| {
249 ed.update_annotations(view, plugin, start, len, spans, annotation_type, rev)
250 })
251 }
252 RemoveStatusItem { key } => self.client.remove_status_item(self.view_id, &key),
253 ShowHover { request_id, result } => self.do_show_hover(request_id, result),
254 };
255 self.after_edit(&plugin.to_string());
256 self.render_if_needed();
257 }
258
259 pub(crate) fn do_plugin_cmd_sync(&mut self, _plugin: PluginId, cmd: PluginRequest) -> Value {
260 use self::PluginRequest::*;
261 match cmd {
262 LineCount => json!(self.editor.borrow().plugin_n_lines()),
263 GetData { start, unit, max_size, rev } => {
264 json!(self.editor.borrow().plugin_get_data(start, unit, max_size, rev))
265 }
266 GetSelections => json!("not implemented"),
267 }
268 }
269
270 fn after_edit(&mut self, author: &str) {
273 let _t = trace_block("EventContext::after_edit", &["core"]);
274
275 let edit_info = self.editor.borrow_mut().commit_delta();
276 let (delta, last_text, drift) = match edit_info {
277 Some(edit_info) => edit_info,
278 None => return,
279 };
280
281 self.update_views(&self.editor.borrow(), &delta, &last_text, drift);
282 self.update_plugins(&mut self.editor.borrow_mut(), delta, author);
283
284 if !self.plugins.is_empty() {
286 let mut view = self.view.borrow_mut();
287 if !view.has_pending_render() {
288 let timeout = Instant::now() + RENDER_DELAY;
289 let view_id: usize = self.view_id.into();
290 let token = RENDER_VIEW_IDLE_MASK | view_id;
291 self.client.schedule_timer(timeout, token);
292 view.set_has_pending_render(true);
293 }
294 }
295 }
296
297 fn update_views(&self, ed: &Editor, delta: &RopeDelta, last_text: &Rope, drift: InsertDrift) {
298 let mut width_cache = self.width_cache.borrow_mut();
299 let iter_views = iter::once(&self.view).chain(self.siblings.iter());
300 iter_views.for_each(|view| {
301 view.borrow_mut().after_edit(
302 ed.get_buffer(),
303 last_text,
304 delta,
305 self.client,
306 &mut width_cache,
307 drift,
308 )
309 });
310 }
311
312 fn update_plugins(&self, ed: &mut Editor, delta: RopeDelta, author: &str) {
313 let new_len = delta.new_document_len();
314 let nb_lines = ed.get_buffer().measure::<LinesMetric>() + 1;
315 let approx_size = delta.inserts_len() + (delta.els.len() * 10);
317 let delta = if approx_size > MAX_SIZE_LIMIT { None } else { Some(delta) };
318
319 let undo_group = ed.get_active_undo_group();
320 let v: Value = serde_json::to_value(&ed.get_edit_type()).unwrap();
323 let edit_type_str = v.as_str().unwrap().to_string();
324
325 let update = PluginUpdate::new(
326 self.view_id,
327 ed.get_head_rev_token(),
328 delta,
329 new_len,
330 nb_lines,
331 Some(undo_group),
332 edit_type_str,
333 author.into(),
334 );
335
336 ed.increment_revs_in_flight();
339
340 self.plugins.iter().for_each(|plugin| {
341 ed.increment_revs_in_flight();
342 let weak_core = self.weak_core.clone();
343 let id = plugin.id;
344 let view_id = self.view_id;
345 plugin.update(&update, move |resp| {
346 weak_core.handle_plugin_update(id, view_id, resp);
347 });
348 });
349 ed.dec_revs_in_flight();
350 ed.update_edit_type();
351 }
352
353 pub(crate) fn render_if_needed(&mut self) {
355 let needed = !self.view.borrow().has_pending_render();
356 if needed {
357 self.render()
358 }
359 }
360
361 pub(crate) fn _finish_delayed_render(&mut self) {
362 self.render();
363 self.view.borrow_mut().set_has_pending_render(false);
364 }
365
366 fn render(&mut self) {
368 let _t = trace_block("EventContext::render", &["core"]);
369 let ed = self.editor.borrow();
370 self.view.borrow_mut().render_if_dirty(
372 ed.get_buffer(),
373 self.client,
374 self.style_map,
375 ed.get_layers().get_merged(),
376 ed.is_pristine(),
377 )
378 }
379}
380
381impl<'a> EventContext<'a> {
387 pub(crate) fn finish_init(&mut self, config: &Table) {
388 if !self.plugins.is_empty() {
389 let info = self.plugin_info();
390 self.plugins.iter().for_each(|plugin| plugin.new_buffer(&info));
391 }
392
393 let available_plugins = self
394 .plugins
395 .iter()
396 .map(|plugin| ClientPluginInfo { name: plugin.name.clone(), running: true })
397 .collect::<Vec<_>>();
398 self.client.available_plugins(self.view_id, &available_plugins);
399
400 self.client.config_changed(self.view_id, config);
401 self.client.language_changed(self.view_id, &self.language);
402 self.update_wrap_settings(true);
403 self.with_view(|view, text| view.set_dirty(text));
404 self.render()
405 }
406
407 pub(crate) fn after_save(&mut self, path: &Path) {
408 self.plugins.iter().for_each(|plugin| plugin.did_save(self.view_id, path));
410
411 self.editor.borrow_mut().set_pristine();
412 self.with_view(|view, text| view.set_dirty(text));
413 self.render()
414 }
415
416 pub(crate) fn close_view(&self) -> bool {
418 self.plugins.iter().for_each(|plug| plug.close_view(self.view_id));
421 self.siblings.is_empty()
422 }
423
424 pub(crate) fn config_changed(&mut self, changes: &Table) {
425 if changes.contains_key("wrap_width") || changes.contains_key("word_wrap") {
426 if changes.contains_key("word_wrap") {
433 debug!("clearing {} items from width cache", self.width_cache.borrow().len());
434 self.width_cache.replace(WidthCache::new());
435 }
436 self.update_wrap_settings(true);
437 }
438
439 self.client.config_changed(self.view_id, &changes);
440 self.plugins.iter().for_each(|plug| plug.config_changed(self.view_id, &changes));
441 self.render()
442 }
443
444 pub(crate) fn language_changed(&mut self, new_language_id: &LanguageId) {
445 self.language = new_language_id.clone();
446 self.client.language_changed(self.view_id, new_language_id);
447 self.plugins.iter().for_each(|plug| plug.language_changed(self.view_id, new_language_id));
448 }
449
450 pub(crate) fn reload(&mut self, text: Rope) {
451 self.with_editor(|ed, _, _, _| ed.reload(text));
452 self.after_edit("core");
453 self.render();
454 }
455
456 pub(crate) fn plugin_info(&mut self) -> PluginBufferInfo {
457 let ed = self.editor.borrow();
458 let nb_lines = ed.get_buffer().measure::<LinesMetric>() + 1;
459 let views: Vec<ViewId> = iter::once(&self.view)
460 .chain(self.siblings.iter())
461 .map(|v| v.borrow().get_view_id())
462 .collect();
463
464 let changes = serde_json::to_value(self.config).unwrap();
465 let path = self.info.map(|info| info.path.to_owned());
466 PluginBufferInfo::new(
467 self.buffer_id,
468 &views,
469 ed.get_head_rev_token(),
470 ed.get_buffer().len(),
471 nb_lines,
472 path,
473 self.language.clone(),
474 changes.as_object().unwrap().to_owned(),
475 )
476 }
477
478 pub(crate) fn plugin_started(&mut self, plugin: &Plugin) {
479 self.client.plugin_started(self.view_id, &plugin.name)
480 }
481
482 pub(crate) fn plugin_stopped(&mut self, plugin: &Plugin) {
483 self.client.plugin_stopped(self.view_id, &plugin.name, 0);
484 let needs_render = self.with_editor(|ed, view, _, _| {
485 if ed.get_layers_mut().remove_layer(plugin.id).is_some() {
486 view.set_dirty(ed.get_buffer());
487 true
488 } else {
489 false
490 }
491 });
492 if needs_render {
493 self.render();
494 }
495 }
496
497 pub(crate) fn do_plugin_update(&mut self, update: Result<Value, RpcError>) {
498 match update.map(serde_json::from_value::<u64>) {
499 Ok(Ok(_)) => (),
500 Ok(Err(err)) => error!("plugin response json err: {:?}", err),
501 Err(err) => error!("plugin shutdown, do something {:?}", err),
502 }
503 self.editor.borrow_mut().dec_revs_in_flight();
504 }
505
506 pub(crate) fn text_for_save(&mut self) -> Rope {
508 let editor = self.editor.borrow();
509 let mut rope = editor.get_buffer().clone();
510 let rope_len = rope.len();
511
512 if rope_len < 1 || !self.config.save_with_newline {
513 return rope;
514 }
515
516 let cursor = Cursor::new(&rope, rope.len());
517 let has_newline_at_eof = match cursor.get_leaf() {
518 Some((last_chunk, _)) => last_chunk.ends_with(&self.config.line_ending),
519 None => unreachable!(),
521 };
522
523 if !has_newline_at_eof {
524 let line_ending = &self.config.line_ending;
525 rope.edit(rope_len.., line_ending);
526 rope
527 } else {
528 rope
529 }
530 }
531
532 fn update_wrap_settings(&mut self, rewrap_immediately: bool) {
537 let wrap_width = self.config.wrap_width;
538 let word_wrap = self.config.word_wrap;
539 self.with_view(|view, text| view.update_wrap_settings(text, wrap_width, word_wrap));
540 if rewrap_immediately {
541 self.rewrap();
542 self.with_view(|view, text| view.set_dirty(text));
543 }
544 if self.view.borrow().needs_more_wrap() {
545 self.schedule_rewrap();
546 }
547 }
548
549 fn rewrap(&mut self) {
553 let mut view = self.view.borrow_mut();
554 let ed = self.editor.borrow();
555 let mut width_cache = self.width_cache.borrow_mut();
556 view.rewrap(ed.get_buffer(), &mut width_cache, self.client, ed.get_layers().get_merged());
557 }
558
559 pub(crate) fn do_incremental_find(&mut self) {
561 let _t = trace_block("EventContext::do_incremental_find", &["find"]);
562
563 self.find();
564 if self.view.borrow().find_in_progress() {
565 let ed = self.editor.borrow();
566 self.client.find_status(
567 self.view_id,
568 &json!(self.view.borrow().find_status(ed.get_buffer(), true)),
569 );
570 self.schedule_find();
571 }
572 self.render_if_needed();
573 }
574
575 fn schedule_find(&self) {
576 let view_id: usize = self.view_id.into();
577 let token = FIND_VIEW_IDLE_MASK | view_id;
578 self.client.schedule_idle(token);
579 }
580
581 fn find(&mut self) {
583 let mut view = self.view.borrow_mut();
584 let ed = self.editor.borrow();
585 view.do_find(ed.get_buffer());
586 }
587
588 pub(crate) fn do_rewrap_batch(&mut self) {
590 self.rewrap();
591 if self.view.borrow().needs_more_wrap() {
592 self.schedule_rewrap();
593 }
594 self.render_if_needed();
595 }
596
597 fn schedule_rewrap(&self) {
598 let view_id: usize = self.view_id.into();
599 let token = REWRAP_VIEW_IDLE_MASK | view_id;
600 self.client.schedule_idle(token);
601 }
602
603 fn do_request_lines(&mut self, first: usize, last: usize) {
604 let mut view = self.view.borrow_mut();
605 let ed = self.editor.borrow();
606 view.request_lines(
607 ed.get_buffer(),
608 self.client,
609 self.style_map,
610 ed.get_layers().get_merged(),
611 first,
612 last,
613 ed.is_pristine(),
614 )
615 }
616
617 fn selected_line_ranges(&mut self) -> Vec<(usize, usize)> {
618 let ed = self.editor.borrow();
619 let mut prev_range: Option<Range<usize>> = None;
620 let mut line_ranges = Vec::new();
621 for region in self.view.borrow().sel_regions().iter() {
624 let start = ed.get_buffer().line_of_offset(region.min());
625 let end = ed.get_buffer().line_of_offset(region.max()) + 1;
626 let line_range = start..end;
627 let prev = prev_range.take();
628 match (prev, line_range) {
629 (None, range) => prev_range = Some(range),
630 (Some(ref prev), ref range) if range.start <= prev.end => {
631 let combined =
632 Range { start: prev.start.min(range.start), end: prev.end.max(range.end) };
633 prev_range = Some(combined);
634 }
635 (Some(prev), range) => {
636 line_ranges.push((prev.start, prev.end));
637 prev_range = Some(range);
638 }
639 }
640 }
641
642 if let Some(prev) = prev_range {
643 line_ranges.push((prev.start, prev.end));
644 }
645
646 line_ranges
647 }
648
649 fn do_reindent(&mut self) {
650 let line_ranges = self.selected_line_ranges();
651 if let Some(plug) = self.plugins.iter().find(|p| p.name == "xi-syntect-plugin") {
653 plug.dispatch_command(self.view_id, "reindent", &json!(line_ranges));
654 }
655 }
656
657 fn do_debug_toggle_comment(&mut self) {
658 let line_ranges = self.selected_line_ranges();
659
660 if let Some(plug) = self.plugins.iter().find(|p| p.name == "xi-syntect-plugin") {
662 plug.dispatch_command(self.view_id, "toggle_comment", &json!(line_ranges));
663 }
664 }
665
666 fn do_request_hover(&mut self, request_id: usize, position: Option<ClientPosition>) {
667 if let Some(position) = self.get_resolved_position(position) {
668 self.with_each_plugin(|p| p.get_hover(self.view_id, request_id, position))
669 }
670 }
671
672 fn do_show_hover(&mut self, request_id: usize, hover: Result<Hover, RemoteError>) {
673 match hover {
674 Ok(hover) => {
675 self.client.show_hover(self.view_id, request_id, hover.content)
677 }
678 Err(err) => warn!("Hover Response from Client Error {:?}", err),
679 }
680 }
681
682 fn get_resolved_position(&mut self, position: Option<ClientPosition>) -> Option<usize> {
686 position
687 .map(|p| self.with_view(|view, text| view.line_col_to_offset(text, p.line, p.column)))
688 .or_else(|| self.view.borrow().get_caret_offset())
689 }
690}
691
692#[cfg(test)]
693#[rustfmt::skip]
694mod tests {
695 use super::*;
696 use crate::config::ConfigManager;
697 use crate::core::dummy_weak_core;
698 use crate::tabs::BufferId;
699 use xi_rpc::test_utils::DummyPeer;
700
701 struct ContextHarness {
702 view: RefCell<View>,
703 editor: RefCell<Editor>,
704 client: Client,
705 core_ref: WeakXiCore,
706 kill_ring: RefCell<Rope>,
707 style_map: RefCell<ThemeStyleMap>,
708 width_cache: RefCell<WidthCache>,
709 config_manager: ConfigManager,
710 recorder: RefCell<Recorder>,
711 }
712
713 impl ContextHarness {
714 fn new<S: AsRef<str>>(s: S) -> Self {
715 let view_id = ViewId(1);
718 let buffer_id = BufferId(2);
719 let mut config_manager = ConfigManager::new(None, None);
720 let config = config_manager.add_buffer(buffer_id, None);
721 let view = RefCell::new(View::new(view_id, buffer_id));
722 let editor = RefCell::new(Editor::with_text(s));
723 let client = Client::new(Box::new(DummyPeer));
724 let core_ref = dummy_weak_core();
725 let kill_ring = RefCell::new(Rope::from(""));
726 let style_map = RefCell::new(ThemeStyleMap::new(None));
727 let width_cache = RefCell::new(WidthCache::new());
728 let recorder = RefCell::new(Recorder::new());
729 let harness = ContextHarness { view, editor, client, core_ref, kill_ring,
730 style_map, width_cache, config_manager, recorder };
731 harness.make_context().finish_init(&config);
732 harness
733
734 }
735
736 fn debug_render(&self) -> String {
739 let b = self.editor.borrow();
740 let mut text: String = b.get_buffer().into();
741 let v = self.view.borrow();
742 for sel in v.sel_regions().iter().rev() {
743 if sel.end == sel.start {
744 text.insert(sel.end, '|');
745 } else if sel.end > sel.start {
746 text.insert_str(sel.end, "|]");
747 text.insert(sel.start, '[');
748 } else {
749 text.insert(sel.start, ']');
750 text.insert_str(sel.end, "[|");
751 }
752 }
753 text
754 }
755
756 fn make_context<'a>(&'a self) -> EventContext<'a> {
757 let view_id = ViewId(1);
758 let buffer_id = self.view.borrow().get_buffer_id();
759 let config = self.config_manager.get_buffer_config(buffer_id);
760 let language = self.config_manager.get_buffer_language(buffer_id);
761 EventContext {
762 view_id,
763 buffer_id,
764 view: &self.view,
765 editor: &self.editor,
766 config: &config.items,
767 language,
768 info: None,
769 siblings: Vec::new(),
770 plugins: Vec::new(),
771 recorder: &self.recorder,
772 client: &self.client,
773 kill_ring: &self.kill_ring,
774 style_map: &self.style_map,
775 width_cache: &self.width_cache,
776 weak_core: &self.core_ref,
777 }
778 }
779 }
780
781 #[test]
782 fn smoke_test() {
783 let harness = ContextHarness::new("");
784 let mut ctx = harness.make_context();
785 ctx.do_edit(EditNotification::Insert { chars: "hello".into() });
786 ctx.do_edit(EditNotification::Insert { chars: " ".into() });
787 ctx.do_edit(EditNotification::Insert { chars: "world".into() });
788 ctx.do_edit(EditNotification::Insert { chars: "!".into() });
789 assert_eq!(harness.debug_render(),"hello world!|");
790 ctx.do_edit(EditNotification::MoveWordLeft);
791 ctx.do_edit(EditNotification::InsertNewline);
792 assert_eq!(harness.debug_render(),"hello \n|world!");
793 ctx.do_edit(EditNotification::MoveWordRightAndModifySelection);
794 assert_eq!(harness.debug_render(), "hello \n[world|]!");
795 ctx.do_edit(EditNotification::Insert { chars: "friends".into() });
796 assert_eq!(harness.debug_render(), "hello \nfriends|!");
797 }
798
799 #[test]
800 fn test_gestures() {
801 use crate::rpc::GestureType::*;
802 let initial_text = "\
803 this is a string\n\
804 that has three\n\
805 lines.";
806 let harness = ContextHarness::new(initial_text);
807 let mut ctx = harness.make_context();
808
809 ctx.do_edit(EditNotification::MoveDown);
810 ctx.do_edit(EditNotification::MoveDown);
811 ctx.do_edit(EditNotification::MoveToEndOfParagraph);
812 assert_eq!(harness.debug_render(),"\
813 this is a string\n\
814 that has three\n\
815 lines.|" );
816
817 ctx.do_edit(EditNotification::Gesture { line: 0, col: 0, ty: PointSelect });
818 ctx.do_edit(EditNotification::MoveToEndOfParagraphAndModifySelection);
819 assert_eq!(harness.debug_render(),"\
820 [this is a string|]\n\
821 that has three\n\
822 lines." );
823
824 ctx.do_edit(EditNotification::MoveToEndOfParagraph);
825 ctx.do_edit(EditNotification::MoveToBeginningOfParagraphAndModifySelection);
826 assert_eq!(harness.debug_render(),"\
827 [|this is a string]\n\
828 that has three\n\
829 lines." );
830
831 ctx.do_edit(EditNotification::Gesture { line: 0, col: 0, ty: PointSelect });
832 assert_eq!(harness.debug_render(),"\
833 |this is a string\n\
834 that has three\n\
835 lines." );
836
837 ctx.do_edit(EditNotification::Gesture { line: 0, col: 5, ty: PointSelect });
838 assert_eq!(harness.debug_render(),"\
839 this |is a string\n\
840 that has three\n\
841 lines." );
842
843 ctx.do_edit(EditNotification::Gesture { line: 1, col: 5, ty: ToggleSel });
844 assert_eq!(harness.debug_render(),"\
845 this |is a string\n\
846 that |has three\n\
847 lines." );
848
849 ctx.do_edit(EditNotification::MoveToRightEndOfLineAndModifySelection);
850 assert_eq!(harness.debug_render(),"\
851 this [is a string|]\n\
852 that [has three|]\n\
853 lines." );
854
855 ctx.do_edit(EditNotification::Gesture { line: 2, col: 2, ty: MultiWordSelect });
856 assert_eq!(harness.debug_render(),"\
857 this [is a string|]\n\
858 that [has three|]\n\
859 [lines|]." );
860
861 ctx.do_edit(EditNotification::Gesture { line: 2, col: 2, ty: ToggleSel });
862 assert_eq!(harness.debug_render(),"\
863 this [is a string|]\n\
864 that [has three|]\n\
865 lines." );
866
867 ctx.do_edit(EditNotification::Gesture { line: 2, col: 2, ty: ToggleSel });
868 assert_eq!(harness.debug_render(),"\
869 this [is a string|]\n\
870 that [has three|]\n\
871 li|nes." );
872
873 ctx.do_edit(EditNotification::MoveToLeftEndOfLine);
874 assert_eq!(harness.debug_render(),"\
875 |this is a string\n\
876 |that has three\n\
877 |lines." );
878
879 ctx.do_edit(EditNotification::MoveWordRight);
880 assert_eq!(harness.debug_render(),"\
881 this| is a string\n\
882 that| has three\n\
883 lines|." );
884
885 ctx.do_edit(EditNotification::MoveToLeftEndOfLineAndModifySelection);
886 assert_eq!(harness.debug_render(),"\
887 [|this] is a string\n\
888 [|that] has three\n\
889 [|lines]." );
890
891 ctx.do_edit(EditNotification::CollapseSelections);
892 ctx.do_edit(EditNotification::MoveToRightEndOfLine);
893 assert_eq!(harness.debug_render(),"\
894 this is a string|\n\
895 that has three\n\
896 lines." );
897
898 ctx.do_edit(EditNotification::Gesture { line: 2, col: 2, ty: MultiLineSelect });
899 assert_eq!(harness.debug_render(),"\
900 this is a string|\n\
901 that has three\n\
902 [lines.|]" );
903
904 ctx.do_edit(EditNotification::SelectAll);
905 assert_eq!(harness.debug_render(),"\
906 [this is a string\n\
907 that has three\n\
908 lines.|]" );
909
910 ctx.do_edit(EditNotification::CollapseSelections);
911 ctx.do_edit(EditNotification::AddSelectionAbove);
912 assert_eq!(harness.debug_render(),"\
913 this is a string\n\
914 that h|as three\n\
915 lines.|" );
916
917 ctx.do_edit(EditNotification::MoveRight);
918 assert_eq!(harness.debug_render(),"\
919 this is a string\n\
920 that ha|s three\n\
921 lines.|" );
922
923 ctx.do_edit(EditNotification::MoveLeft);
924 assert_eq!(harness.debug_render(),"\
925 this is a string\n\
926 that h|as three\n\
927 lines|." );
928 }
929
930 #[test]
931 fn delete_combining_enclosing_keycaps_tests() {
932 use crate::rpc::GestureType::*;
933
934 let initial_text = "1\u{E0101}\u{20E3}";
935 let harness = ContextHarness::new(initial_text);
936 let mut ctx = harness.make_context();
937 ctx.do_edit(EditNotification::Gesture { line: 0, col: 8, ty: PointSelect });
938
939 assert_eq!(harness.debug_render(), "1\u{E0101}\u{20E3}|");
940
941 ctx.do_edit(EditNotification::DeleteBackward);
942 assert_eq!(harness.debug_render(), "|");
943
944 ctx.do_edit(EditNotification::Insert { chars: "1\u{20E3}\u{20E3}".into() });
946 assert_eq!(harness.debug_render(), "1\u{20E3}\u{20E3}|");
947 ctx.do_edit(EditNotification::DeleteBackward);
948 assert_eq!(harness.debug_render(), "1\u{20E3}|");
949 ctx.do_edit(EditNotification::DeleteBackward);
950 assert_eq!(harness.debug_render(), "|");
951
952 ctx.do_edit(EditNotification::Insert { chars: "\u{20E3}".into() });
954 assert_eq!(harness.debug_render(), "\u{20E3}|");
955 ctx.do_edit(EditNotification::DeleteBackward);
956 assert_eq!(harness.debug_render(), "|");
957
958 ctx.do_edit(EditNotification::Insert { chars: "\u{20E3}\u{20E3}".into() });
960 assert_eq!(harness.debug_render(), "\u{20E3}\u{20E3}|");
961 ctx.do_edit(EditNotification::DeleteBackward);
962 assert_eq!(harness.debug_render(), "\u{20E3}|");
963 ctx.do_edit(EditNotification::DeleteBackward);
964 assert_eq!(harness.debug_render(), "|");
965 }
966
967 #[test]
968 fn delete_variation_selector_tests() {
969 use crate::rpc::GestureType::*;
970
971 let initial_text = "\u{FE0F}";
972 let harness = ContextHarness::new(initial_text);
973 let mut ctx = harness.make_context();
974 ctx.do_edit(EditNotification::Gesture { line: 0, col: 3, ty: PointSelect });
975
976 assert_eq!(harness.debug_render(), "\u{FE0F}|");
977
978 ctx.do_edit(EditNotification::DeleteBackward);
980 assert_eq!(harness.debug_render(), "|");
981
982 ctx.do_edit(EditNotification::Insert { chars: "\u{E0100}".into() });
983 assert_eq!(harness.debug_render(), "\u{E0100}|");
984 ctx.do_edit(EditNotification::DeleteBackward);
985 assert_eq!(harness.debug_render(), "|");
986
987 ctx.do_edit(EditNotification::Insert { chars: "\u{FE0F}\u{FE0F}".into() });
989 assert_eq!(harness.debug_render(), "\u{FE0F}\u{FE0F}|");
990 ctx.do_edit(EditNotification::DeleteBackward);
991 assert_eq!(harness.debug_render(), "\u{FE0F}|");
992 ctx.do_edit(EditNotification::DeleteBackward);
993 assert_eq!(harness.debug_render(), "|");
994
995 ctx.do_edit(EditNotification::Insert { chars: "\u{FE0F}\u{E0100}".into() });
996 assert_eq!(harness.debug_render(), "\u{FE0F}\u{E0100}|");
997 ctx.do_edit(EditNotification::DeleteBackward);
998 assert_eq!(harness.debug_render(), "\u{FE0F}|");
999 ctx.do_edit(EditNotification::DeleteBackward);
1000 assert_eq!(harness.debug_render(), "|");
1001
1002 ctx.do_edit(EditNotification::Insert { chars: "\u{E0100}\u{FE0F}".into() });
1003 assert_eq!(harness.debug_render(), "\u{E0100}\u{FE0F}|");
1004 ctx.do_edit(EditNotification::DeleteBackward);
1005 assert_eq!(harness.debug_render(), "\u{E0100}|");
1006 ctx.do_edit(EditNotification::DeleteBackward);
1007 assert_eq!(harness.debug_render(), "|");
1008
1009 ctx.do_edit(EditNotification::Insert { chars: "\u{E0100}\u{E0100}".into() });
1010 assert_eq!(harness.debug_render(), "\u{E0100}\u{E0100}|");
1011 ctx.do_edit(EditNotification::DeleteBackward);
1012 assert_eq!(harness.debug_render(), "\u{E0100}|");
1013 ctx.do_edit(EditNotification::DeleteBackward);
1014 assert_eq!(harness.debug_render(), "|");
1015
1016 ctx.do_edit(EditNotification::Insert { chars: "#\u{FE0F}\u{FE0F}".into() });
1018 assert_eq!(harness.debug_render(), "#\u{FE0F}\u{FE0F}|");
1019 ctx.do_edit(EditNotification::DeleteBackward);
1020 assert_eq!(harness.debug_render(), "#\u{FE0F}|");
1021 ctx.do_edit(EditNotification::DeleteBackward);
1022 assert_eq!(harness.debug_render(), "|");
1023
1024 ctx.do_edit(EditNotification::Insert { chars: "#\u{FE0F}\u{E0100}".into() });
1025 assert_eq!(harness.debug_render(), "#\u{FE0F}\u{E0100}|");
1026 ctx.do_edit(EditNotification::DeleteBackward);
1027 assert_eq!(harness.debug_render(), "#\u{FE0F}|");
1028 ctx.do_edit(EditNotification::DeleteBackward);
1029 assert_eq!(harness.debug_render(), "|");
1030
1031 ctx.do_edit(EditNotification::Insert { chars: "#\u{E0100}\u{FE0F}".into() });
1032 assert_eq!(harness.debug_render(), "#\u{E0100}\u{FE0F}|");
1033 ctx.do_edit(EditNotification::DeleteBackward);
1034 assert_eq!(harness.debug_render(), "#\u{E0100}|");
1035 ctx.do_edit(EditNotification::DeleteBackward);
1036 assert_eq!(harness.debug_render(), "|");
1037
1038 ctx.do_edit(EditNotification::Insert { chars: "#\u{E0100}\u{E0100}".into() });
1039 assert_eq!(harness.debug_render(), "#\u{E0100}\u{E0100}|");
1040 ctx.do_edit(EditNotification::DeleteBackward);
1041 assert_eq!(harness.debug_render(), "#\u{E0100}|");
1042 ctx.do_edit(EditNotification::DeleteBackward);
1043 assert_eq!(harness.debug_render(), "|");
1044 }
1045
1046 #[test]
1047 fn delete_emoji_zwj_sequence_tests() {
1048 use crate::rpc::GestureType::*;
1049 let initial_text = "\u{1F441}\u{200D}\u{1F5E8}";
1050 let harness = ContextHarness::new(initial_text);
1051 let mut ctx = harness.make_context();
1052 ctx.do_edit(EditNotification::Gesture { line: 0, col: 11, ty: PointSelect });
1053 assert_eq!(harness.debug_render(), "\u{1F441}\u{200D}\u{1F5E8}|");
1054
1055 ctx.do_edit(EditNotification::DeleteBackward);
1057 assert_eq!(harness.debug_render(), "|");
1058
1059 ctx.do_edit(EditNotification::Insert { chars: "\u{1F441}\u{200D}\u{1F5E8}\u{FE0E}".into() });
1060 assert_eq!(harness.debug_render(), "\u{1F441}\u{200D}\u{1F5E8}\u{FE0E}|");
1061 ctx.do_edit(EditNotification::DeleteBackward);
1062 assert_eq!(harness.debug_render(), "|");
1063
1064 ctx.do_edit(EditNotification::Insert { chars: "\u{1F469}\u{200D}\u{1F373}".into() });
1065 assert_eq!(harness.debug_render(), "\u{1F469}\u{200D}\u{1F373}|");
1066 ctx.do_edit(EditNotification::DeleteBackward);
1067 assert_eq!(harness.debug_render(), "|");
1068
1069 ctx.do_edit(EditNotification::Insert { chars: "\u{1F487}\u{200D}\u{2640}".into() });
1070 assert_eq!(harness.debug_render(), "\u{1F487}\u{200D}\u{2640}|");
1071 ctx.do_edit(EditNotification::DeleteBackward);
1072 assert_eq!(harness.debug_render(), "|");
1073
1074 ctx.do_edit(EditNotification::Insert { chars: "\u{1F487}\u{200D}\u{2640}\u{FE0F}".into() });
1075 assert_eq!(harness.debug_render(), "\u{1F487}\u{200D}\u{2640}\u{FE0F}|");
1076 ctx.do_edit(EditNotification::DeleteBackward);
1077 assert_eq!(harness.debug_render(), "|");
1078
1079 ctx.do_edit(EditNotification::Insert { chars: "\u{1F468}\u{200D}\u{2764}\u{FE0F}\u{200D}\u{1F48B}\u{200D}\u{1F468}".into() });
1080 assert_eq!(harness.debug_render(), "\u{1F468}\u{200D}\u{2764}\u{FE0F}\u{200D}\u{1F48B}\u{200D}\u{1F468}|");
1081 ctx.do_edit(EditNotification::DeleteBackward);
1082 assert_eq!(harness.debug_render(), "|");
1083
1084 ctx.do_edit(EditNotification::Insert { chars: "\u{1F469}\u{1F3FB}\u{200D}\u{1F4BC}".into() });
1086 assert_eq!(harness.debug_render(), "\u{1F469}\u{1F3FB}\u{200D}\u{1F4BC}|");
1087 ctx.do_edit(EditNotification::DeleteBackward);
1088 assert_eq!(harness.debug_render(), "|");
1089
1090 ctx.do_edit(EditNotification::Insert { chars: "\u{1F441}\u{200D}".into() });
1092 assert_eq!(harness.debug_render(), "\u{1F441}\u{200D}|");
1093 ctx.do_edit(EditNotification::DeleteBackward);
1094 assert_eq!(harness.debug_render(), "\u{1F441}|");
1095 ctx.do_edit(EditNotification::DeleteBackward);
1096 assert_eq!(harness.debug_render(), "|");
1097
1098 ctx.do_edit(EditNotification::Insert { chars: "\u{200D}\u{1F5E8}".into() });
1100 assert_eq!(harness.debug_render(), "\u{200D}\u{1F5E8}|");
1101 ctx.do_edit(EditNotification::DeleteBackward);
1102 assert_eq!(harness.debug_render(), "\u{200D}|");
1103 ctx.do_edit(EditNotification::DeleteBackward);
1104 assert_eq!(harness.debug_render(), "|");
1105
1106 ctx.do_edit(EditNotification::Insert { chars: "\u{FE0E}\u{200D}\u{1F5E8}".into() });
1107 assert_eq!(harness.debug_render(), "\u{FE0E}\u{200D}\u{1F5E8}|");
1108 ctx.do_edit(EditNotification::DeleteBackward);
1109 assert_eq!(harness.debug_render(), "\u{FE0E}\u{200D}|");
1110 ctx.do_edit(EditNotification::DeleteBackward);
1111 assert_eq!(harness.debug_render(), "\u{FE0E}|");
1112 ctx.do_edit(EditNotification::DeleteBackward);
1113 assert_eq!(harness.debug_render(), "|");
1114
1115 ctx.do_edit(EditNotification::Insert { chars: "\u{1F441}\u{200D}\u{200D}\u{1F5E8}".into() });
1117 assert_eq!(harness.debug_render(), "\u{1F441}\u{200D}\u{200D}\u{1F5E8}|");
1118 ctx.do_edit(EditNotification::DeleteBackward);
1119 assert_eq!(harness.debug_render(), "\u{1F441}\u{200D}\u{200D}|");
1120 ctx.do_edit(EditNotification::DeleteBackward);
1121 assert_eq!(harness.debug_render(), "\u{1F441}\u{200D}|");
1122 ctx.do_edit(EditNotification::DeleteBackward);
1123 assert_eq!(harness.debug_render(), "\u{1F441}|");
1124 ctx.do_edit(EditNotification::DeleteBackward);
1125 assert_eq!(harness.debug_render(), "|");
1126
1127 ctx.do_edit(EditNotification::Insert { chars: "\u{200D}".into() });
1129 assert_eq!(harness.debug_render(), "\u{200D}|");
1130 ctx.do_edit(EditNotification::DeleteBackward);
1131 assert_eq!(harness.debug_render(), "|");
1132
1133 ctx.do_edit(EditNotification::Insert { chars: "\u{200D}\u{200D}".into() });
1135 assert_eq!(harness.debug_render(), "\u{200D}\u{200D}|");
1136 ctx.do_edit(EditNotification::DeleteBackward);
1137 assert_eq!(harness.debug_render(), "\u{200D}|");
1138 ctx.do_edit(EditNotification::DeleteBackward);
1139 assert_eq!(harness.debug_render(), "|");
1140 }
1141
1142 #[test]
1143 fn delete_flags_tests() {
1144 use crate::rpc::GestureType::*;
1145 let initial_text = "\u{1F1FA}";
1146 let harness = ContextHarness::new(initial_text);
1147 let mut ctx = harness.make_context();
1148 ctx.do_edit(EditNotification::Gesture { line: 0, col: 4, ty: PointSelect });
1149
1150 assert_eq!(harness.debug_render(), "\u{1F1FA}|");
1152 ctx.do_edit(EditNotification::DeleteBackward);
1153 assert_eq!(harness.debug_render(), "|");
1154
1155 ctx.do_edit(EditNotification::Insert { chars: "\u{1F1FA}\u{1F1F8}\u{1F1FA}".into() });
1157 assert_eq!(harness.debug_render(), "\u{1F1FA}\u{1F1F8}\u{1F1FA}|");
1158 ctx.do_edit(EditNotification::DeleteBackward);
1159 assert_eq!(harness.debug_render(), "\u{1F1FA}\u{1F1F8}|");
1160 ctx.do_edit(EditNotification::DeleteBackward);
1161 assert_eq!(harness.debug_render(), "|");
1162
1163 ctx.do_edit(EditNotification::Insert { chars: "a\u{1F3F4}\u{E0067}b".into() });
1165 assert_eq!(harness.debug_render(), "a\u{1F3F4}\u{E0067}b|");
1166 ctx.do_edit(EditNotification::DeleteBackward);
1167 assert_eq!(harness.debug_render(), "a\u{1F3F4}\u{E0067}|");
1168 ctx.do_edit(EditNotification::DeleteBackward);
1169 assert_eq!(harness.debug_render(), "a\u{1F3F4}|");
1170 ctx.do_edit(EditNotification::DeleteBackward);
1171 assert_eq!(harness.debug_render(), "a|");
1172
1173 ctx.do_edit(EditNotification::Insert { chars: "\u{E0067}\u{E007F}b".into() });
1175 assert_eq!(harness.debug_render(), "a\u{E0067}\u{E007F}b|");
1176 ctx.do_edit(EditNotification::DeleteBackward);
1177 assert_eq!(harness.debug_render(), "a\u{E0067}\u{E007F}|");
1178 ctx.do_edit(EditNotification::DeleteBackward);
1179 assert_eq!(harness.debug_render(), "a\u{E0067}|");
1180 ctx.do_edit(EditNotification::DeleteBackward);
1181 assert_eq!(harness.debug_render(), "a|");
1182
1183 ctx.do_edit(EditNotification::Insert { chars: "\u{E0067}\u{E0067}b".into() });
1185 assert_eq!(harness.debug_render(), "a\u{E0067}\u{E0067}b|");
1186 ctx.do_edit(EditNotification::DeleteBackward);
1187 assert_eq!(harness.debug_render(), "a\u{E0067}\u{E0067}|");
1188 ctx.do_edit(EditNotification::DeleteBackward);
1189 assert_eq!(harness.debug_render(), "a\u{E0067}|");
1190 ctx.do_edit(EditNotification::DeleteBackward);
1191 assert_eq!(harness.debug_render(), "a|");
1192
1193 ctx.do_edit(EditNotification::Insert { chars: "\u{E007F}\u{E007F}b".into() });
1195 assert_eq!(harness.debug_render(), "a\u{E007F}\u{E007F}b|");
1196 ctx.do_edit(EditNotification::DeleteBackward);
1197 assert_eq!(harness.debug_render(), "a\u{E007F}\u{E007F}|");
1198 ctx.do_edit(EditNotification::DeleteBackward);
1199 assert_eq!(harness.debug_render(), "a\u{E007F}|");
1200 ctx.do_edit(EditNotification::DeleteBackward);
1201 assert_eq!(harness.debug_render(), "a|");
1202
1203 ctx.do_edit(EditNotification::Insert { chars: "\u{1F3F4}\u{E007F}\u{1F3F4}\u{E007F}b".into() });
1205 assert_eq!(harness.debug_render(), "a\u{1F3F4}\u{E007F}\u{1F3F4}\u{E007F}b|");
1206 ctx.do_edit(EditNotification::DeleteBackward);
1207 assert_eq!(harness.debug_render(), "a\u{1F3F4}\u{E007F}\u{1F3F4}\u{E007F}|");
1208 ctx.do_edit(EditNotification::DeleteBackward);
1209 assert_eq!(harness.debug_render(), "a\u{1F3F4}\u{E007F}|");
1210 ctx.do_edit(EditNotification::DeleteBackward);
1211 assert_eq!(harness.debug_render(), "a|");
1212 }
1213
1214 #[test]
1215 fn delete_emoji_modifier_tests() {
1216 use crate::rpc::GestureType::*;
1217 let initial_text = "\u{1F466}\u{1F3FB}";
1218 let harness = ContextHarness::new(initial_text);
1219 let mut ctx = harness.make_context();
1220 ctx.do_edit(EditNotification::Gesture { line: 0, col: 8, ty: PointSelect });
1221
1222 assert_eq!(harness.debug_render(), "\u{1F466}\u{1F3FB}|");
1224 ctx.do_edit(EditNotification::DeleteBackward);
1225 assert_eq!(harness.debug_render(), "|");
1226
1227 ctx.do_edit(EditNotification::Insert { chars: "\u{1F3FB}".into() });
1229 assert_eq!(harness.debug_render(), "\u{1F3FB}|");
1230 ctx.do_edit(EditNotification::DeleteBackward);
1231 assert_eq!(harness.debug_render(), "|");
1232
1233 ctx.do_edit(EditNotification::Insert { chars: "\u{1F3FB}\u{1F3FB}".into() });
1235 assert_eq!(harness.debug_render(), "\u{1F3FB}\u{1F3FB}|");
1236 ctx.do_edit(EditNotification::DeleteBackward);
1237 assert_eq!(harness.debug_render(), "\u{1F3FB}|");
1238 ctx.do_edit(EditNotification::DeleteBackward);
1239 assert_eq!(harness.debug_render(), "|");
1240
1241 ctx.do_edit(EditNotification::Insert { chars: "\u{1F466}\u{1F3FB}\u{1F3FB}".into() });
1243 ctx.do_edit(EditNotification::DeleteBackward);
1244 assert_eq!(harness.debug_render(), "\u{1F466}\u{1F3FB}|");
1245 ctx.do_edit(EditNotification::DeleteBackward);
1246 assert_eq!(harness.debug_render(), "|");
1247 }
1248
1249 #[test]
1250 fn delete_mixed_edge_cases_tests() {
1251 use crate::rpc::GestureType::*;
1252 let initial_text = "";
1253 let harness = ContextHarness::new(initial_text);
1254 let mut ctx = harness.make_context();
1255 ctx.do_edit(EditNotification::Gesture { line: 0, col: 7, ty: PointSelect });
1256
1257 ctx.do_edit(EditNotification::Insert { chars: "1\u{20E3}\u{FE0F}".into() });
1259 ctx.do_edit(EditNotification::DeleteBackward);
1260 assert_eq!(harness.debug_render(), "1|");
1261 ctx.do_edit(EditNotification::DeleteBackward);
1262 assert_eq!(harness.debug_render(), "|");
1263
1264 ctx.do_edit(EditNotification::Insert { chars: "\u{2665}\u{FE0F}\u{20E3}".into() });
1266 ctx.do_edit(EditNotification::DeleteBackward);
1267 assert_eq!(harness.debug_render(), "\u{2665}\u{FE0F}|");
1268 ctx.do_edit(EditNotification::DeleteBackward);
1269 assert_eq!(harness.debug_render(), "|");
1270
1271 ctx.do_edit(EditNotification::Insert { chars: "1\u{20E3}\u{200D}".into() });
1273 ctx.do_edit(EditNotification::DeleteBackward);
1274 assert_eq!(harness.debug_render(), "1\u{20E3}|");
1275 ctx.do_edit(EditNotification::DeleteBackward);
1276 assert_eq!(harness.debug_render(), "|");
1277
1278 ctx.do_edit(EditNotification::Insert { chars: "1\u{20E3}\u{200D}\u{1F5E8}".into() });
1280 ctx.do_edit(EditNotification::DeleteBackward);
1281 assert_eq!(harness.debug_render(), "1\u{20E3}\u{200D}|");
1282 ctx.do_edit(EditNotification::DeleteBackward);
1283 assert_eq!(harness.debug_render(), "1\u{20E3}|");
1284 ctx.do_edit(EditNotification::DeleteBackward);
1285 assert_eq!(harness.debug_render(), "|");
1286
1287 ctx.do_edit(EditNotification::Insert { chars: "\u{200D}\u{20E3}".into() });
1289 ctx.do_edit(EditNotification::DeleteBackward);
1290 assert_eq!(harness.debug_render(), "\u{200D}|");
1291 ctx.do_edit(EditNotification::DeleteBackward);
1292 assert_eq!(harness.debug_render(), "|");
1293
1294 ctx.do_edit(EditNotification::Insert { chars: "\u{1F441}\u{200D}\u{20E3}".into() });
1296 ctx.do_edit(EditNotification::DeleteBackward);
1297 assert_eq!(harness.debug_render(), "\u{1F441}\u{200D}|");
1298 ctx.do_edit(EditNotification::DeleteBackward);
1299 assert_eq!(harness.debug_render(), "\u{1F441}|");
1300 ctx.do_edit(EditNotification::DeleteBackward);
1301 assert_eq!(harness.debug_render(), "|");
1302
1303 ctx.do_edit(EditNotification::Insert { chars: "1\u{20E3}\u{1F1FA}".into() });
1305 ctx.do_edit(EditNotification::DeleteBackward);
1306 assert_eq!(harness.debug_render(), "1\u{20E3}|");
1307 ctx.do_edit(EditNotification::DeleteBackward);
1308 assert_eq!(harness.debug_render(), "|");
1309
1310 ctx.do_edit(EditNotification::Insert { chars: "\u{1F1FA}\u{20E3}".into() });
1312 ctx.do_edit(EditNotification::DeleteBackward);
1313 assert_eq!(harness.debug_render(), "\u{1F1FA}|");
1314 ctx.do_edit(EditNotification::DeleteBackward);
1315 assert_eq!(harness.debug_render(), "|");
1316
1317 ctx.do_edit(EditNotification::Insert { chars: "1\u{20E3}\u{1F3FB}".into() });
1319 ctx.do_edit(EditNotification::DeleteBackward);
1320 assert_eq!(harness.debug_render(), "1\u{20E3}|");
1321 ctx.do_edit(EditNotification::DeleteBackward);
1322 assert_eq!(harness.debug_render(), "|");
1323
1324 ctx.do_edit(EditNotification::Insert { chars: "\u{1F466}\u{1F3FB}\u{20E3}".into() });
1326 ctx.do_edit(EditNotification::DeleteBackward);
1327 assert_eq!(harness.debug_render(), "\u{1f466}\u{1F3FB}|");
1328 ctx.do_edit(EditNotification::DeleteBackward);
1329 assert_eq!(harness.debug_render(), "|");
1330
1331 ctx.do_edit(EditNotification::Insert { chars: "\u{2665}\u{FE0F}\u{200D}".into() });
1333 ctx.do_edit(EditNotification::DeleteBackward);
1334 assert_eq!(harness.debug_render(), "\u{2665}\u{FE0F}|");
1335 ctx.do_edit(EditNotification::DeleteBackward);
1336 assert_eq!(harness.debug_render(), "|");
1337
1338 ctx.do_edit(EditNotification::Insert { chars: "\u{1F469}\u{200D}\u{2764}\u{FE0F}\u{200D}\u{1F469}".into() });
1340 ctx.do_edit(EditNotification::DeleteBackward);
1341 assert_eq!(harness.debug_render(), "|");
1342
1343 ctx.do_edit(EditNotification::Insert { chars: "\u{200D}\u{FE0F}".into() });
1345 ctx.do_edit(EditNotification::DeleteBackward);
1346 assert_eq!(harness.debug_render(), "|");
1347
1348 ctx.do_edit(EditNotification::Insert { chars: "\u{1F469}\u{200D}\u{FE0F}".into() });
1350 ctx.do_edit(EditNotification::DeleteBackward);
1351 assert_eq!(harness.debug_render(), "\u{1F469}|");
1352 ctx.do_edit(EditNotification::DeleteBackward);
1353 assert_eq!(harness.debug_render(), "|");
1354
1355 ctx.do_edit(EditNotification::Insert { chars: "\u{2665}\u{FE0F}\u{1F1FA}".into() });
1357 ctx.do_edit(EditNotification::DeleteBackward);
1358 assert_eq!(harness.debug_render(), "\u{2665}\u{FE0F}|");
1359 ctx.do_edit(EditNotification::DeleteBackward);
1360 assert_eq!(harness.debug_render(), "|");
1361
1362 ctx.do_edit(EditNotification::Insert { chars: "\u{1F1FA}\u{FE0F}".into() });
1364 ctx.do_edit(EditNotification::DeleteBackward);
1365 assert_eq!(harness.debug_render(), "|");
1366
1367 ctx.do_edit(EditNotification::Insert { chars: "\u{2665}\u{FE0F}\u{1F3FB}".into() });
1369 ctx.do_edit(EditNotification::DeleteBackward);
1370 assert_eq!(harness.debug_render(), "\u{2665}\u{FE0F}|");
1371 ctx.do_edit(EditNotification::DeleteBackward);
1372 assert_eq!(harness.debug_render(), "|");
1373
1374 ctx.do_edit(EditNotification::Insert { chars: "\u{1F466}\u{1F3FB}\u{FE0F}".into() });
1376 ctx.do_edit(EditNotification::DeleteBackward);
1377 assert_eq!(harness.debug_render(), "\u{1F466}|");
1378 ctx.do_edit(EditNotification::DeleteBackward);
1379 assert_eq!(harness.debug_render(), "|");
1380
1381 ctx.do_edit(EditNotification::Insert { chars: "\u{200D}\u{1F1FA}".into() });
1383 ctx.do_edit(EditNotification::DeleteBackward);
1384 assert_eq!(harness.debug_render(), "\u{200D}|");
1385 ctx.do_edit(EditNotification::DeleteBackward);
1386 assert_eq!(harness.debug_render(), "|");
1387
1388 ctx.do_edit(EditNotification::Insert { chars: "\u{1F469}\u{200D}\u{1F1FA}".into() });
1390 ctx.do_edit(EditNotification::DeleteBackward);
1391 assert_eq!(harness.debug_render(), "\u{1F469}\u{200D}|");
1392 ctx.do_edit(EditNotification::DeleteBackward);
1393 assert_eq!(harness.debug_render(), "\u{1F469}|");
1394 ctx.do_edit(EditNotification::DeleteBackward);
1395 assert_eq!(harness.debug_render(), "|");
1396
1397 ctx.do_edit(EditNotification::Insert { chars: "\u{1F1FA}\u{200D}".into() });
1399 ctx.do_edit(EditNotification::DeleteBackward);
1400 assert_eq!(harness.debug_render(), "\u{1F1FA}|");
1401 ctx.do_edit(EditNotification::DeleteBackward);
1402 assert_eq!(harness.debug_render(), "|");
1403
1404 ctx.do_edit(EditNotification::Insert { chars: "\u{1F1FA}\u{200D}\u{1F469}".into() });
1406 ctx.do_edit(EditNotification::DeleteBackward);
1407 assert_eq!(harness.debug_render(), "|");
1408
1409 ctx.do_edit(EditNotification::Insert { chars: "\u{200D}\u{1F3FB}".into() });
1411 ctx.do_edit(EditNotification::DeleteBackward);
1412 assert_eq!(harness.debug_render(), "\u{200D}|");
1413 ctx.do_edit(EditNotification::DeleteBackward);
1414 assert_eq!(harness.debug_render(), "|");
1415
1416 ctx.do_edit(EditNotification::Insert { chars: "\u{1F469}\u{200D}\u{1F3FB}".into() });
1418 ctx.do_edit(EditNotification::DeleteBackward);
1419 assert_eq!(harness.debug_render(), "\u{1F469}\u{200D}|");
1420 ctx.do_edit(EditNotification::DeleteBackward);
1421 assert_eq!(harness.debug_render(), "\u{1F469}|");
1422 ctx.do_edit(EditNotification::DeleteBackward);
1423 assert_eq!(harness.debug_render(), "|");
1424
1425 ctx.do_edit(EditNotification::Insert { chars: "\u{1F466}\u{1F3FB}\u{200D}".into() });
1427 ctx.do_edit(EditNotification::DeleteBackward);
1428 assert_eq!(harness.debug_render(), "\u{1F466}\u{1F3FB}|");
1429 ctx.do_edit(EditNotification::DeleteBackward);
1430 assert_eq!(harness.debug_render(), "|");
1431
1432 ctx.do_edit(EditNotification::Insert { chars: "\u{1F1FA}\u{1F3FB}".into() });
1434 ctx.do_edit(EditNotification::DeleteBackward);
1435 assert_eq!(harness.debug_render(), "\u{1F1FA}|");
1436 ctx.do_edit(EditNotification::DeleteBackward);
1437 assert_eq!(harness.debug_render(), "|");
1438
1439 ctx.do_edit(EditNotification::Insert { chars: "\u{1F466}\u{1F3FB}\u{1F1FA}".into() });
1441 ctx.do_edit(EditNotification::DeleteBackward);
1442 assert_eq!(harness.debug_render(), "\u{1F466}\u{1F3FB}|");
1443 ctx.do_edit(EditNotification::DeleteBackward);
1444 assert_eq!(harness.debug_render(), "|");
1445
1446 ctx.do_edit(EditNotification::Insert { chars: "\u{1F1E6}\u{000A}".into() });
1448 ctx.do_edit(EditNotification::DeleteBackward);
1449 assert_eq!(harness.debug_render(), "\u{1F1E6}|");
1450 ctx.do_edit(EditNotification::DeleteBackward);
1451 assert_eq!(harness.debug_render(), "|");
1452 }
1453
1454 #[test]
1455 fn delete_tests() {
1456 use crate::rpc::GestureType::*;
1457 let initial_text = "\
1458 this is a string\n\
1459 that has three\n\
1460 lines.";
1461 let harness = ContextHarness::new(initial_text);
1462 let mut ctx = harness.make_context();
1463 ctx.do_edit(EditNotification::Gesture { line: 0, col: 0, ty: PointSelect });
1464
1465 ctx.do_edit(EditNotification::MoveRight);
1466 assert_eq!(harness.debug_render(),"\
1467 t|his is a string\n\
1468 that has three\n\
1469 lines." );
1470
1471 ctx.do_edit(EditNotification::DeleteBackward);
1472 assert_eq!(harness.debug_render(),"\
1473 |his is a string\n\
1474 that has three\n\
1475 lines." );
1476
1477 ctx.do_edit(EditNotification::DeleteForward);
1478 assert_eq!(harness.debug_render(),"\
1479 |is is a string\n\
1480 that has three\n\
1481 lines." );
1482
1483 ctx.do_edit(EditNotification::MoveWordRight);
1484 ctx.do_edit(EditNotification::DeleteWordForward);
1485 assert_eq!(harness.debug_render(),"\
1486 is| a string\n\
1487 that has three\n\
1488 lines." );
1489
1490 ctx.do_edit(EditNotification::DeleteWordBackward);
1491 assert_eq!(harness.debug_render(),"| \
1492 a string\n\
1493 that has three\n\
1494 lines." );
1495
1496 ctx.do_edit(EditNotification::MoveToRightEndOfLine);
1497 ctx.do_edit(EditNotification::DeleteToBeginningOfLine);
1498 assert_eq!(harness.debug_render(),"\
1499 |\nthat has three\n\
1500 lines." );
1501
1502 ctx.do_edit(EditNotification::DeleteToEndOfParagraph);
1503 ctx.do_edit(EditNotification::DeleteToEndOfParagraph);
1504 assert_eq!(harness.debug_render(),"\
1505 |\nlines." );
1506 }
1507
1508 #[test]
1509 fn simple_indentation_test() {
1510 use crate::rpc::GestureType::*;
1511 let harness = ContextHarness::new("");
1512 let mut ctx = harness.make_context();
1513 ctx.do_edit(EditNotification::Insert { chars: "hello".into() });
1515 ctx.do_edit(EditNotification::Indent);
1516 assert_eq!(harness.debug_render()," hello|");
1517 ctx.do_edit(EditNotification::Outdent);
1518 assert_eq!(harness.debug_render(),"hello|");
1519
1520 ctx.do_edit(EditNotification::Gesture { line: 0, col: 0, ty: PointSelect });
1522 ctx.do_edit(EditNotification::Insert { chars: " ".into() });
1523 assert_eq!(harness.debug_render()," |hello");
1524 ctx.do_edit(EditNotification::Outdent);
1525 assert_eq!(harness.debug_render(),"|hello");
1526
1527 ctx.do_edit(EditNotification::MoveToEndOfDocument);
1529 ctx.do_edit(EditNotification::Indent);
1530 ctx.do_edit(EditNotification::InsertNewline);
1531 ctx.do_edit(EditNotification::Insert { chars: "world".into() });
1532 assert_eq!(harness.debug_render()," hello\nworld|");
1533
1534 ctx.do_edit(EditNotification::MoveWordLeft);
1535 ctx.do_edit(EditNotification::MoveToBeginningOfDocumentAndModifySelection);
1536 ctx.do_edit(EditNotification::Indent);
1537 assert_eq!(harness.debug_render()," [| hello\n]world");
1538
1539 ctx.do_edit(EditNotification::Outdent);
1540 assert_eq!(harness.debug_render(),"[| hello\n]world");
1541 }
1542
1543 #[test]
1544 fn multiline_indentation_test() {
1545 use crate::rpc::GestureType::*;
1546 let initial_text = "\
1547 this is a string\n\
1548 that has three\n\
1549 lines.";
1550 let harness = ContextHarness::new(initial_text);
1551 let mut ctx = harness.make_context();
1552
1553 ctx.do_edit(EditNotification::Gesture { line: 0, col: 5, ty: PointSelect });
1554 assert_eq!(harness.debug_render(),"\
1555 this |is a string\n\
1556 that has three\n\
1557 lines." );
1558
1559 ctx.do_edit(EditNotification::Gesture { line: 1, col: 5, ty: ToggleSel });
1560 assert_eq!(harness.debug_render(),"\
1561 this |is a string\n\
1562 that |has three\n\
1563 lines." );
1564
1565 ctx.do_edit(EditNotification::Indent);
1567 assert_eq!(harness.debug_render()," \
1568 this |is a string\n \
1569 that |has three\n\
1570 lines." );
1571
1572 ctx.do_edit(EditNotification::Outdent);
1573 ctx.do_edit(EditNotification::Outdent);
1574 assert_eq!(harness.debug_render(),"\
1575 this |is a string\n\
1576 that |has three\n\
1577 lines." );
1578
1579 ctx.do_edit(EditNotification::Gesture { line: 1, col: 5, ty: ToggleSel });
1582 ctx.do_edit(EditNotification::Gesture { line: 1, col: 10, ty: ToggleSel });
1583 assert_eq!(harness.debug_render(),"\
1584 this |is a string\n\
1585 that has t|hree\n\
1586 lines." );
1587
1588 ctx.do_edit(EditNotification::Indent);
1589 assert_eq!(harness.debug_render()," \
1590 this |is a string\n \
1591 that has t|hree\n\
1592 lines." );
1593
1594 ctx.do_edit(EditNotification::Outdent);
1595 assert_eq!(harness.debug_render(),"\
1596 this |is a string\n\
1597 that has t|hree\n\
1598 lines." );
1599
1600 ctx.do_edit(EditNotification::Gesture { line: 1, col: 10, ty: ToggleSel });
1602 ctx.do_edit(EditNotification::MoveToEndOfDocumentAndModifySelection);
1603 ctx.do_edit(EditNotification::Indent);
1604 assert_eq!(harness.debug_render()," \
1605 this [is a string\n \
1606 that has three\n \
1607 lines.|]" );
1608
1609 ctx.do_edit(EditNotification::Outdent);
1610 assert_eq!(harness.debug_render(),"\
1611 this [is a string\n\
1612 that has three\n\
1613 lines.|]" );
1614
1615 ctx.do_edit(EditNotification::Gesture { line: 0, col: 0, ty: PointSelect });
1617 ctx.do_edit(EditNotification::Gesture { line: 2, col: 0, ty: ToggleSel });
1618 assert_eq!(harness.debug_render(),"\
1619 |this is a string\n\
1620 that has three\n\
1621 |lines." );
1622
1623 ctx.do_edit(EditNotification::Indent);
1624 assert_eq!(harness.debug_render()," \
1625 |this is a string\n\
1626 that has three\n \
1627 |lines." );
1628
1629 ctx.do_edit(EditNotification::Outdent);
1630 assert_eq!(harness.debug_render(),"\
1631 |this is a string\n\
1632 that has three\n\
1633 |lines." );
1634 }
1635
1636 #[test]
1637 fn number_change_tests() {
1638 use crate::rpc::GestureType::*;
1639 let harness = ContextHarness::new("");
1640 let mut ctx = harness.make_context();
1641 ctx.do_edit(EditNotification::Insert { chars: "1234".into() });
1643 ctx.do_edit(EditNotification::IncreaseNumber);
1644 assert_eq!(harness.debug_render(), "1235|");
1645
1646 ctx.do_edit(EditNotification::Gesture { line: 0, col: 2, ty: PointSelect });
1647 ctx.do_edit(EditNotification::IncreaseNumber);
1648 assert_eq!(harness.debug_render(), "1236|");
1649
1650 ctx.do_edit(EditNotification::DeleteToBeginningOfLine);
1651 ctx.do_edit(EditNotification::Insert { chars: "-42".into() });
1652 ctx.do_edit(EditNotification::IncreaseNumber);
1653 assert_eq!(harness.debug_render(), "-41|");
1654
1655 ctx.do_edit(EditNotification::MoveToEndOfDocument);
1657 ctx.do_edit(EditNotification::DeleteToBeginningOfLine);
1658 ctx.do_edit(EditNotification::Insert { chars: "this is a 336 text example".into() });
1659 ctx.do_edit(EditNotification::Gesture { line: 0, col: 11, ty: PointSelect });
1660 ctx.do_edit(EditNotification::DecreaseNumber);
1661 assert_eq!(harness.debug_render(), "this is a 335| text example");
1662
1663 ctx.do_edit(EditNotification::MoveToEndOfDocument);
1665 ctx.do_edit(EditNotification::DeleteToBeginningOfLine);
1666 ctx.do_edit(EditNotification::Insert { chars: "this is a -336 text example".into() });
1667 ctx.do_edit(EditNotification::Gesture { line: 0, col: 11, ty: PointSelect });
1668 ctx.do_edit(EditNotification::DecreaseNumber);
1669 assert_eq!(harness.debug_render(), "this is a -337| text example");
1670
1671 ctx.do_edit(EditNotification::MoveToEndOfDocument);
1673 ctx.do_edit(EditNotification::DeleteToBeginningOfLine);
1674 ctx.do_edit(EditNotification::Insert { chars: "this is a -336 text example".into() });
1675 ctx.do_edit(EditNotification::Gesture { line: 0, col: 15, ty: PointSelect });
1676 ctx.do_edit(EditNotification::DecreaseNumber);
1677 assert_eq!(harness.debug_render(), "this is a -336 |text example");
1678
1679 ctx.do_edit(EditNotification::MoveToEndOfDocument);
1681 ctx.do_edit(EditNotification::DeleteToBeginningOfLine);
1682 ctx.do_edit(EditNotification::Insert { chars: "this is a 336 text example".into() });
1683 ctx.do_edit(EditNotification::Gesture { line: 0, col: 11, ty: PointSelect });
1684 ctx.do_edit(EditNotification::IncreaseNumber);
1685 ctx.do_edit(EditNotification::IncreaseNumber);
1686 ctx.do_edit(EditNotification::IncreaseNumber);
1687 assert_eq!(harness.debug_render(), "this is a 339| text example");
1688
1689 ctx.do_edit(EditNotification::MoveToEndOfDocument);
1691 ctx.do_edit(EditNotification::DeleteToBeginningOfLine);
1692 ctx.do_edit(EditNotification::Insert { chars: "this is a 10 text example".into() });
1693 ctx.do_edit(EditNotification::Gesture { line: 0, col: 11, ty: PointSelect });
1694 ctx.do_edit(EditNotification::DecreaseNumber);
1695 assert_eq!(harness.debug_render(), "this is a 9| text example");
1696
1697 ctx.do_edit(EditNotification::MoveToEndOfDocument);
1699 ctx.do_edit(EditNotification::DeleteToBeginningOfLine);
1700 ctx.do_edit(EditNotification::Insert { chars: "this is a 0 text example".into() });
1701 ctx.do_edit(EditNotification::Gesture { line: 0, col: 11, ty: PointSelect });
1702 ctx.do_edit(EditNotification::DecreaseNumber);
1703 assert_eq!(harness.debug_render(), "this is a -1| text example");
1704
1705 ctx.do_edit(EditNotification::MoveToEndOfDocument);
1707 ctx.do_edit(EditNotification::DeleteToBeginningOfLine);
1708 ctx.do_edit(EditNotification::Insert { chars: "this is a -1 text example".into() });
1709 ctx.do_edit(EditNotification::Gesture { line: 0, col: 12, ty: PointSelect });
1710 ctx.do_edit(EditNotification::IncreaseNumber);
1711 assert_eq!(harness.debug_render(), "this is a 0| text example");
1712
1713 ctx.do_edit(EditNotification::MoveToEndOfDocument);
1715 ctx.do_edit(EditNotification::DeleteToBeginningOfLine);
1716 ctx.do_edit(EditNotification::Insert { chars: "this is a 10 text example".into() });
1717 ctx.do_edit(EditNotification::Gesture { line: 0, col: 10, ty: PointSelect });
1718 ctx.do_edit(EditNotification::MoveToEndOfDocumentAndModifySelection);
1719 ctx.do_edit(EditNotification::DecreaseNumber);
1720 assert_eq!(harness.debug_render(), "this is a [10 text example|]");
1721
1722 ctx.do_edit(EditNotification::MoveToEndOfDocument);
1724 ctx.do_edit(EditNotification::DeleteToBeginningOfLine);
1725 ctx.do_edit(EditNotification::Insert { chars: "this is a 10 text example".into() });
1726 ctx.do_edit(EditNotification::Gesture { line: 0, col: 5, ty: PointSelect });
1727 ctx.do_edit(EditNotification::MoveToEndOfDocumentAndModifySelection);
1728 ctx.do_edit(EditNotification::DecreaseNumber);
1729 assert_eq!(harness.debug_render(), "this [is a 10 text example|]");
1730
1731 ctx.do_edit(EditNotification::MoveToEndOfDocument);
1733 ctx.do_edit(EditNotification::DeleteToBeginningOfLine);
1734 ctx.do_edit(EditNotification::Insert { chars: "this is a 10".into() });
1735 ctx.do_edit(EditNotification::Gesture { line: 0, col: 0, ty: PointSelect });
1736 ctx.do_edit(EditNotification::MoveToEndOfDocumentAndModifySelection);
1737 ctx.do_edit(EditNotification::IncreaseNumber);
1738 assert_eq!(harness.debug_render(), "[this is a 11|]");
1739
1740 ctx.do_edit(EditNotification::MoveToEndOfDocument);
1742 ctx.do_edit(EditNotification::DeleteToBeginningOfLine);
1743 ctx.do_edit(EditNotification::Insert { chars: "this is a 1000 text example".into() });
1744 ctx.do_edit(EditNotification::Gesture { line: 0, col: 11, ty: PointSelect });
1745 ctx.do_edit(EditNotification::MoveRightAndModifySelection);
1746 ctx.do_edit(EditNotification::DecreaseNumber);
1747 assert_eq!(harness.debug_render(), "this is a 999| text example");
1748
1749 ctx.do_edit(EditNotification::MoveToEndOfDocument);
1751 ctx.do_edit(EditNotification::DeleteToBeginningOfLine);
1752 ctx.do_edit(EditNotification::Insert { chars: "10_000".into() });
1753 ctx.do_edit(EditNotification::MoveToEndOfDocument);
1754 ctx.do_edit(EditNotification::IncreaseNumber);
1755 assert_eq!(harness.debug_render(), "10_000|");
1756
1757 ctx.do_edit(EditNotification::MoveToEndOfDocument);
1759 ctx.do_edit(EditNotification::DeleteToBeginningOfLine);
1760 ctx.do_edit(EditNotification::Insert { chars: "4.55".into() });
1761 ctx.do_edit(EditNotification::MoveToEndOfDocument);
1762 ctx.do_edit(EditNotification::IncreaseNumber);
1763 assert_eq!(harness.debug_render(), "4.56|");
1764
1765 ctx.do_edit(EditNotification::MoveToEndOfDocument);
1767 ctx.do_edit(EditNotification::DeleteToBeginningOfLine);
1768 ctx.do_edit(EditNotification::Insert { chars: "0xFF03".into() });
1769 ctx.do_edit(EditNotification::MoveToEndOfDocument);
1770 ctx.do_edit(EditNotification::IncreaseNumber);
1771 assert_eq!(harness.debug_render(), "0xFF03|");
1772
1773 ctx.do_edit(EditNotification::MoveToEndOfDocument);
1775 ctx.do_edit(EditNotification::DeleteToBeginningOfLine);
1776 let multi_text = "\
1777 example 42 number\n\
1778 example 90 number\n\
1779 Done.";
1780 ctx.do_edit(EditNotification::Insert { chars: multi_text.into() });
1781 ctx.do_edit(EditNotification::Gesture { line: 1, col: 9, ty: PointSelect });
1782 ctx.do_edit(EditNotification::AddSelectionAbove);
1783 ctx.do_edit(EditNotification::IncreaseNumber);
1784 assert_eq!(harness.debug_render(), "\
1785 example 43| number\n\
1786 example 91| number\n\
1787 Done.");
1788 }
1789
1790 #[test]
1791 fn text_recording() {
1792 use crate::rpc::GestureType::*;
1793 let initial_text = "";
1794 let harness = ContextHarness::new(initial_text);
1795 let mut ctx = harness.make_context();
1796
1797 let recording_name = String::new();
1798
1799 ctx.do_edit(EditNotification::Gesture { line: 0, col: 0, ty: PointSelect });
1800 assert_eq!(harness.debug_render(), "|");
1801
1802 ctx.do_edit(EditNotification::ToggleRecording { recording_name: Some(recording_name.clone()) });
1803
1804 ctx.do_edit(EditNotification::Insert { chars: "Foo ".to_owned() });
1805 ctx.do_edit(EditNotification::Insert { chars: "B".to_owned() });
1806 ctx.do_edit(EditNotification::Insert { chars: "A".to_owned() });
1807 ctx.do_edit(EditNotification::Insert { chars: "R".to_owned() });
1808 assert_eq!(harness.debug_render(), "Foo BAR|");
1809
1810 ctx.do_edit(EditNotification::ToggleRecording { recording_name: Some(recording_name.clone())});
1811 ctx.do_edit(EditNotification::Insert { chars: " ".to_owned() });
1812
1813 ctx.do_edit(EditNotification::PlayRecording { recording_name });
1814 assert_eq!(harness.debug_render(), "Foo BAR Foo BAR|");
1815 }
1816
1817 #[test]
1818 fn movement_recording() {
1819 use crate::rpc::GestureType::*;
1820 let initial_text = "\
1821 this is a string\n\
1822 that has about\n\
1823 four really nice\n\
1824 lines to see.";
1825 let harness = ContextHarness::new(initial_text);
1826 let mut ctx = harness.make_context();
1827
1828 let recording_name = String::new();
1829
1830 ctx.do_edit(EditNotification::Gesture { line: 0, col: 5, ty: PointSelect });
1831 assert_eq!(harness.debug_render(),"\
1832 this |is a string\n\
1833 that has about\n\
1834 four really nice\n\
1835 lines to see." );
1836
1837 ctx.do_edit(EditNotification::ToggleRecording { recording_name: Some(recording_name.clone()) });
1838
1839 ctx.do_edit(EditNotification::AddSelectionBelow);
1841 ctx.do_edit(EditNotification::MoveToRightEndOfLine);
1842 ctx.do_edit(EditNotification::MoveWordLeftAndModifySelection);
1843 ctx.do_edit(EditNotification::Transpose);
1844 ctx.do_edit(EditNotification::CollapseSelections);
1845 ctx.do_edit(EditNotification::MoveToRightEndOfLine);
1846 assert_eq!(harness.debug_render(),"\
1847 this is a about|\n\
1848 that has string\n\
1849 four really nice\n\
1850 lines to see." );
1851
1852 ctx.do_edit(EditNotification::ToggleRecording { recording_name: Some(recording_name.clone())});
1853
1854 ctx.do_edit(EditNotification::Gesture { line: 2, col: 5, ty: PointSelect });
1855 ctx.do_edit(EditNotification::PlayRecording { recording_name: recording_name.clone() });
1856 assert_eq!(harness.debug_render(),"\
1857 this is a about\n\
1858 that has string\n\
1859 four really see.|\n\
1860 lines to nice" );
1861
1862 ctx.do_edit(EditNotification::Undo);
1864 assert_eq!(harness.debug_render(),"\
1865 this is a about\n\
1866 that has string\n\
1867 four really nice|\n\
1868 lines to see." );
1869
1870 ctx.do_edit(EditNotification::Redo);
1872 assert_eq!(harness.debug_render(),"\
1873 this is a about\n\
1874 that has string\n\
1875 four really see.|\n\
1876 lines to nice" );
1877
1878 ctx.do_edit(EditNotification::Undo);
1880 ctx.do_edit(EditNotification::Undo);
1881 ctx.do_edit(EditNotification::ClearRecording { recording_name: recording_name.clone() });
1882 ctx.do_edit(EditNotification::PlayRecording { recording_name });
1883 assert_eq!(harness.debug_render(),"\
1884 this is a string\n\
1885 that has about\n\
1886 four really nice|\n\
1887 lines to see." );
1888 }
1889
1890 #[test]
1891 fn test_exact_position() {
1892 use crate::rpc::GestureType::*;
1893 let initial_text = "\
1894 this is a string\n\
1895 that has three\n\
1896 \n\
1897 lines.\n\
1898 And lines with very different length.";
1899 let harness = ContextHarness::new(initial_text);
1900 let mut ctx = harness.make_context();
1901 ctx.do_edit(EditNotification::Gesture { line: 1, col: 5, ty: PointSelect });
1902 ctx.do_edit(EditNotification::AddSelectionAbove);
1903 assert_eq!(harness.debug_render(),"\
1904 this |is a string\n\
1905 that |has three\n\
1906 \n\
1907 lines.\n\
1908 And lines with very different length.");
1909
1910 ctx.do_edit(EditNotification::CollapseSelections);
1911 ctx.do_edit(EditNotification::Gesture { line: 1, col: 5, ty: PointSelect });
1912 ctx.do_edit(EditNotification::AddSelectionBelow);
1913 assert_eq!(harness.debug_render(),"\
1914 this is a string\n\
1915 that |has three\n\
1916 \n\
1917 lines|.\n\
1918 And lines with very different length.");
1919
1920 ctx.do_edit(EditNotification::CollapseSelections);
1921 ctx.do_edit(EditNotification::Gesture { line: 4, col: 10, ty: PointSelect });
1922 ctx.do_edit(EditNotification::AddSelectionAbove);
1923 assert_eq!(harness.debug_render(),"\
1924 this is a string\n\
1925 that has t|hree\n\
1926 \n\
1927 lines.\n\
1928 And lines |with very different length.");
1929 }
1930
1931 #[test]
1932 fn test_illegal_plugin_edit() {
1933 use xi_rope::DeltaBuilder;
1934 use crate::plugins::rpc::{PluginNotification, PluginEdit};
1935 use crate::plugins::PluginPid;
1936
1937 let text = "text";
1938 let harness = ContextHarness::new(text);
1939 let mut ctx = harness.make_context();
1940 let rev_token = ctx.editor.borrow().get_head_rev_token();
1941
1942 let iv = Interval::new(1, 1);
1943 let mut builder = DeltaBuilder::new(0); builder.replace(iv, "1".into());
1945
1946 let edit_one = PluginEdit {
1947 rev: rev_token,
1948 delta: builder.build(),
1949 priority: 55,
1950 after_cursor: false,
1951 undo_group: None,
1952 author: "plugin_one".into(),
1953 };
1954
1955 ctx.do_plugin_cmd(PluginPid(1), PluginNotification::Edit { edit: edit_one });
1956 let new_rev_token = ctx.editor.borrow().get_head_rev_token();
1957 assert_eq!(rev_token, new_rev_token);
1959 }
1960
1961
1962 #[test]
1963 fn empty_transpose() {
1964 let harness = ContextHarness::new("");
1965 let mut ctx = harness.make_context();
1966
1967 ctx.do_edit(EditNotification::Transpose);
1968
1969 assert_eq!(harness.debug_render(), "|"); }
1971
1972 #[test]
1974 fn eol_multicursor_transpose() {
1975 use crate::rpc::GestureType::*;
1976
1977 let harness = ContextHarness::new("word\n");
1978 let mut ctx = harness.make_context();
1979
1980 ctx.do_edit(EditNotification::Gesture{line: 0, col: 4, ty: PointSelect}); ctx.do_edit(EditNotification::AddSelectionBelow); ctx.do_edit(EditNotification::Transpose);
1983
1984 assert_eq!(harness.debug_render(), "wor\nd|");
1985 }
1986}