@@ -11,8 +11,8 @@ use client::{
};
use collections::{BTreeMap, HashMap, HashSet};
use editor::{
- self, ConfirmCodeAction, ConfirmCompletion, ConfirmRename, Editor, Input, Redo, Rename,
- ToOffset, ToggleCodeActions, Undo,
+ self, ConfirmCodeAction, ConfirmCompletion, ConfirmRename, Editor, Redo, Rename, ToOffset,
+ ToggleCodeActions, Undo,
};
use futures::{channel::mpsc, Future, StreamExt as _};
use gpui::{
@@ -154,9 +154,7 @@ async fn test_share_project(
// .await;
// Edit the buffer as client B and see that edit as client A.
- editor_b.update(cx_b, |editor, cx| {
- editor.handle_input(&Input("ok, ".into()), cx)
- });
+ editor_b.update(cx_b, |editor, cx| editor.handle_input("ok, ", cx));
buffer_a
.condition(&cx_a, |buffer, _| buffer.text() == "ok, b-contents")
.await;
@@ -1751,7 +1749,7 @@ async fn test_collaborating_with_completion(cx_a: &mut TestAppContext, cx_b: &mu
// Type a completion trigger character as the guest.
editor_b.update(cx_b, |editor, cx| {
editor.change_selections(None, cx, |s| s.select_ranges([13..13]));
- editor.handle_input(&Input(".".into()), cx);
+ editor.handle_input(".", cx);
cx.focus(&editor_b);
});
@@ -228,6 +228,7 @@ impl_internal_actions!(editor, [Scroll, Select, Jump]);
enum DocumentHighlightRead {}
enum DocumentHighlightWrite {}
+enum InputComposition {}
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum Direction {
@@ -240,7 +241,6 @@ pub fn init(cx: &mut MutableAppContext) {
cx.add_action(|this: &mut Editor, action: &Scroll, cx| this.set_scroll_position(action.0, cx));
cx.add_action(Editor::select);
cx.add_action(Editor::cancel);
- cx.add_action(Editor::handle_input);
cx.add_action(Editor::newline);
cx.add_action(Editor::backspace);
cx.add_action(Editor::delete);
@@ -1813,13 +1813,11 @@ impl Editor {
cx.propagate_action();
}
- pub fn handle_input(&mut self, action: &Input, cx: &mut ViewContext<Self>) {
+ pub fn handle_input(&mut self, text: &str, cx: &mut ViewContext<Self>) {
if !self.input_enabled {
- cx.propagate_action();
return;
}
- let text = action.0.as_ref();
if !self.skip_autoclose_end(text, cx) {
self.transact(cx, |this, cx| {
if !this.surround_with_bracket_pair(text, cx) {
@@ -5522,6 +5520,13 @@ impl Editor {
cx.notify();
}
+ pub fn text_highlights<'a, T: 'static>(
+ &'a self,
+ cx: &'a AppContext,
+ ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
+ self.display_map.read(cx).text_highlights(TypeId::of::<T>())
+ }
+
pub fn clear_text_highlights<T: 'static>(
&mut self,
cx: &mut ViewContext<Self>,
@@ -5871,6 +5876,80 @@ impl View for Editor {
context
}
+
+ fn text_for_range(&self, range: Range<usize>, cx: &AppContext) -> Option<String> {
+ Some(
+ self.buffer
+ .read(cx)
+ .read(cx)
+ .text_for_range(range)
+ .collect(),
+ )
+ }
+
+ fn selected_text_range(&self, cx: &AppContext) -> Option<Range<usize>> {
+ Some(self.selections.newest(cx).range())
+ }
+
+ fn set_selected_text_range(&mut self, range: Range<usize>, cx: &mut ViewContext<Self>) {
+ self.change_selections(None, cx, |selections| selections.select_ranges([range]));
+ }
+
+ fn marked_text_range(&self, cx: &AppContext) -> Option<Range<usize>> {
+ let range = self.text_highlights::<InputComposition>(cx)?.1.get(0)?;
+ Some(range.to_offset(&*self.buffer.read(cx).read(cx)))
+ }
+
+ fn unmark_text(&mut self, cx: &mut ViewContext<Self>) {
+ self.clear_text_highlights::<InputComposition>(cx);
+ }
+
+ fn replace_text_in_range(
+ &mut self,
+ range: Option<Range<usize>>,
+ text: &str,
+ cx: &mut ViewContext<Self>,
+ ) {
+ self.transact(cx, |this, cx| {
+ if let Some(range) = range {
+ this.set_selected_text_range(range, cx);
+ }
+ this.handle_input(text, cx);
+ });
+ }
+
+ fn replace_and_mark_text_in_range(
+ &mut self,
+ range: Option<Range<usize>>,
+ text: &str,
+ _new_selected_range: Option<Range<usize>>,
+ cx: &mut ViewContext<Self>,
+ ) {
+ self.transact(cx, |this, cx| {
+ let range = range.or_else(|| {
+ let ranges = this.text_highlights::<InputComposition>(cx)?.1;
+ let range = ranges.first()?;
+ let snapshot = this.buffer.read(cx).read(cx);
+ Some(range.to_offset(&*snapshot))
+ });
+ if let Some(range) = range {
+ this.set_selected_text_range(range, cx);
+ }
+
+ let selection = this.selections.newest_anchor();
+ let marked_range = {
+ let snapshot = this.buffer.read(cx).read(cx);
+ selection.start.bias_left(&*snapshot)..selection.end.bias_right(&*snapshot)
+ };
+ this.highlight_text::<InputComposition>(
+ vec![marked_range],
+ this.style(cx).composition_mark,
+ cx,
+ );
+
+ this.handle_input(text, cx);
+ });
+ }
}
fn build_style(
@@ -8241,9 +8320,9 @@ mod tests {
// is pasted at each cursor.
cx.set_state("|two oneβ
four three six five |");
cx.update_editor(|e, cx| {
- e.handle_input(&Input("( ".into()), cx);
+ e.handle_input("( ", cx);
e.paste(&Paste, cx);
- e.handle_input(&Input(") ".into()), cx);
+ e.handle_input(") ", cx);
});
cx.assert_editor_state(indoc! {"
( oneβ
@@ -8918,9 +8997,9 @@ mod tests {
])
});
- view.handle_input(&Input("{".to_string()), cx);
- view.handle_input(&Input("{".to_string()), cx);
- view.handle_input(&Input("{".to_string()), cx);
+ view.handle_input("{", cx);
+ view.handle_input("{", cx);
+ view.handle_input("{", cx);
assert_eq!(
view.text(cx),
"
@@ -8933,9 +9012,9 @@ mod tests {
);
view.move_right(&MoveRight, cx);
- view.handle_input(&Input("}".to_string()), cx);
- view.handle_input(&Input("}".to_string()), cx);
- view.handle_input(&Input("}".to_string()), cx);
+ view.handle_input("}", cx);
+ view.handle_input("}", cx);
+ view.handle_input("}", cx);
assert_eq!(
view.text(cx),
"
@@ -8948,8 +9027,8 @@ mod tests {
);
view.undo(&Undo, cx);
- view.handle_input(&Input("/".to_string()), cx);
- view.handle_input(&Input("*".to_string()), cx);
+ view.handle_input("/", cx);
+ view.handle_input("*", cx);
assert_eq!(
view.text(cx),
"
@@ -8968,7 +9047,7 @@ mod tests {
DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0),
])
});
- view.handle_input(&Input("*".to_string()), cx);
+ view.handle_input("*", cx);
assert_eq!(
view.text(cx),
"
@@ -8986,7 +9065,7 @@ mod tests {
view.change_selections(None, cx, |s| {
s.select_display_ranges([DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)])
});
- view.handle_input(&Input("{".to_string()), cx);
+ view.handle_input("{", cx);
assert_eq!(
view.text(cx),
"
@@ -9002,7 +9081,7 @@ mod tests {
view.change_selections(None, cx, |s| {
s.select_display_ranges([DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1)])
});
- view.handle_input(&Input("{".to_string()), cx);
+ view.handle_input("{", cx);
assert_eq!(
view.text(cx),
"
@@ -9019,7 +9098,7 @@ mod tests {
);
view.undo(&Undo, cx);
- view.handle_input(&Input("[".to_string()), cx);
+ view.handle_input("[", cx);
assert_eq!(
view.text(cx),
"
@@ -9039,7 +9118,7 @@ mod tests {
view.change_selections(None, cx, |s| {
s.select_display_ranges([DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1)])
});
- view.handle_input(&Input("[".to_string()), cx);
+ view.handle_input("[", cx);
assert_eq!(
view.text(cx),
"
@@ -9095,9 +9174,9 @@ mod tests {
])
});
- view.handle_input(&Input("{".to_string()), cx);
- view.handle_input(&Input("{".to_string()), cx);
- view.handle_input(&Input("{".to_string()), cx);
+ view.handle_input("{", cx);
+ view.handle_input("{", cx);
+ view.handle_input("{", cx);
assert_eq!(
view.text(cx),
"
@@ -9177,9 +9256,9 @@ mod tests {
])
});
- editor.handle_input(&Input("{".to_string()), cx);
- editor.handle_input(&Input("{".to_string()), cx);
- editor.handle_input(&Input("_".to_string()), cx);
+ editor.handle_input("{", cx);
+ editor.handle_input("{", cx);
+ editor.handle_input("_", cx);
assert_eq!(
editor.text(cx),
"
@@ -9905,7 +9984,7 @@ mod tests {
])
});
- view.handle_input(&Input("X".to_string()), cx);
+ view.handle_input("X", cx);
assert_eq!(view.text(cx), "Xaaaa\nXbbbb");
assert_eq!(
view.selections.ranges(cx),
@@ -9945,7 +10024,7 @@ mod tests {
assert_eq!(view.text(cx), expected_text);
view.change_selections(None, cx, |s| s.select_ranges(selection_ranges));
- view.handle_input(&Input("X".to_string()), cx);
+ view.handle_input("X", cx);
let (expected_text, expected_selections) = marked_text_ranges(indoc! {"
aaaa
@@ -920,11 +920,7 @@ mod tests {
item.downcast::<Editor>().unwrap()
});
- cx.update(|cx| {
- editor.update(cx, |editor, cx| {
- editor.handle_input(&editor::Input("x".into()), cx)
- })
- });
+ cx.update(|cx| editor.update(cx, |editor, cx| editor.handle_input("x", cx)));
app_state
.fs
.as_fake()
@@ -971,7 +967,7 @@ mod tests {
editor.language_at(0, cx).unwrap(),
&languages::PLAIN_TEXT
));
- editor.handle_input(&editor::Input("hi".into()), cx);
+ editor.handle_input("hi", cx);
assert!(editor.is_dirty(cx));
});
@@ -997,7 +993,7 @@ mod tests {
// Edit the file and save it again. This time, there is no filename prompt.
editor.update(cx, |editor, cx| {
- editor.handle_input(&editor::Input(" there".into()), cx);
+ editor.handle_input(" there", cx);
assert_eq!(editor.is_dirty(cx.as_ref()), true);
});
let save_task = workspace.update(cx, |workspace, cx| workspace.save_active_item(false, cx));
@@ -1057,7 +1053,7 @@ mod tests {
editor.language_at(0, cx).unwrap(),
&languages::PLAIN_TEXT
));
- editor.handle_input(&editor::Input("hi".into()), cx);
+ editor.handle_input("hi", cx);
assert!(editor.is_dirty(cx.as_ref()));
});
@@ -2,6 +2,7 @@ import Theme from "../themes/common/theme";
import {
backgroundColor,
border,
+ borderColor,
iconColor,
player,
popoverShadow,
@@ -138,8 +139,8 @@ export default function editor(theme: Theme) {
invalidHintDiagnostic: diagnostic(theme, "muted"),
invalidInformationDiagnostic: diagnostic(theme, "muted"),
invalidWarningDiagnostic: diagnostic(theme, "muted"),
- hover_popover: hoverPopover(theme),
- link_definition: {
+ hoverPopover: hoverPopover(theme),
+ linkDefinition: {
color: theme.syntax.linkUri.color,
underline: theme.syntax.linkUri.underline,
},
@@ -159,6 +160,12 @@ export default function editor(theme: Theme) {
background: backgroundColor(theme, "on500", "base"),
}
},
+ compositionMark: {
+ underline: {
+ thickness: 1.0,
+ color: borderColor(theme, "active")
+ },
+ },
syntax,
};
}