diff --git a/src/documents/document/edit.rs b/src/documents/document/edit.rs index d78fc2f..0b3ba85 100644 --- a/src/documents/document/edit.rs +++ b/src/documents/document/edit.rs @@ -5,6 +5,7 @@ use gpui::{AppContext as _, Context, Focusable as _, Window}; use super::{DocumentEvent, MarkdownDocument, Open}; use crate::{ documents::{ + MarkdownMode, markdown::markdown_highlights, modes::{at_edge, joint}, }, @@ -22,6 +23,14 @@ fn moved(at: usize, edit: &Option<(Range, usize)>) -> Option { } impl MarkdownDocument { + /// An empty visual document takes typing at once. + pub(super) fn focused(&mut self, window: &mut Window, cx: &mut Context) { + let empty = self.editor.read(cx).text().trim().is_empty(); + if self.mode == MarkdownMode::Visual && self.open.is_none() && empty { + self.open(None, false, window, cx); + } + } + /// Opens block `ix` as shown, or one past the end. pub(super) fn open( &mut self, diff --git a/src/documents/document/mod.rs b/src/documents/document/mod.rs index 8c8739a..f83ad16 100644 --- a/src/documents/document/mod.rs +++ b/src/documents/document/mod.rs @@ -105,11 +105,15 @@ impl MarkdownDocument { .hide_indent_guides() .highlighter(markdown_highlights) }); - let subscriptions = vec![cx.subscribe(&editor, |document, _, event, cx| { - if *event == EditorEvent::Changed { - document.changed(cx); - } - })]; + let focus = cx.focus_handle(); + let subscriptions = vec![ + cx.subscribe(&editor, |document, _, event, cx| { + if *event == EditorEvent::Changed { + document.changed(cx); + } + }), + cx.on_focus(&focus, window, Self::focused), + ]; let overdraw = window.rem_size() * 40.0; let mut document = Self { editor, @@ -123,7 +127,7 @@ impl MarkdownDocument { top: None, asks: 0, writes: 0, - focus: cx.focus_handle(), + focus, on_link: None, _subscriptions: subscriptions, }; diff --git a/src/documents/document/tests/mod.rs b/src/documents/document/tests/mod.rs index d0d2f30..ff36656 100644 --- a/src/documents/document/tests/mod.rs +++ b/src/documents/document/tests/mod.rs @@ -397,3 +397,31 @@ fn a_text_past_the_largest_read_is_never_read(cx: &mut TestAppContext) { }); assert_eq!((blocks, outline), (0, 0), "the old read is gone"); } + +/// Focus on `document`'s own handle, as an owner gives it. +fn focus(document: &Entity, cx: &mut VisualTestContext) { + let handle = document.read_with(cx, |document, cx| { + gpui::Focusable::focus_handle(document, cx) + }); + cx.update(|window, cx| window.focus(&handle, cx)); + cx.run_until_parked(); +} + +#[gpui::test] +fn an_empty_visual_document_takes_typing_on_focus(cx: &mut TestAppContext) { + let (document, cx) = open("", MarkdownMode::Visual, cx); + focus(&document, cx); + cx.simulate_input("Hi"); + assert_eq!(text(&document, cx), "Hi", "typing lands with no press"); + cx.simulate_keystrokes("escape"); + cx.run_until_parked(); + assert_eq!(text(&document, cx), "Hi", "escape keeps it"); +} + +#[gpui::test] +fn focus_opens_no_block_in_a_written_document(cx: &mut TestAppContext) { + let (document, cx) = open(TEXT, MarkdownMode::Visual, cx); + focus(&document, cx); + cx.simulate_input("x"); + assert_eq!(text(&document, cx), TEXT); +}