Detailed changes
@@ -1233,6 +1233,7 @@ pub struct Editor {
autoindent_mode: Option<AutoindentMode>,
workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
input_enabled: bool,
+ expects_character_input: bool,
use_modal_editing: bool,
read_only: bool,
leader_id: Option<CollaboratorId>,
@@ -2469,6 +2470,7 @@ impl Editor {
collapse_matches: false,
workspace: None,
input_enabled: !is_minimap,
+ expects_character_input: !is_minimap,
use_modal_editing: full_mode,
read_only: is_minimap,
use_autoclose: true,
@@ -3365,6 +3367,10 @@ impl Editor {
self.input_enabled = input_enabled;
}
+ pub fn set_expects_character_input(&mut self, expects_character_input: bool) {
+ self.expects_character_input = expects_character_input;
+ }
+
pub fn set_edit_predictions_hidden_for_vim_mode(
&mut self,
hidden: bool,
@@ -28409,7 +28415,7 @@ impl EntityInputHandler for Editor {
}
fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
- self.input_enabled
+ self.expects_character_input
}
}
@@ -1062,6 +1062,13 @@ impl PlatformInputHandler {
pub fn accepts_text_input(&mut self, window: &mut Window, cx: &mut App) -> bool {
self.handler.accepts_text_input(window, cx)
}
+
+ #[allow(dead_code)]
+ pub fn query_accepts_text_input(&mut self) -> bool {
+ self.cx
+ .update(|window, cx| self.handler.accepts_text_input(window, cx))
+ .unwrap_or(true)
+ }
}
/// A struct representing a selection in a text buffer, in UTF16 characters.
@@ -593,33 +593,63 @@ impl WindowsWindowInner {
}
pub(crate) fn update_ime_position(&self, handle: HWND, caret_position: POINT) {
+ let Some(ctx) = ImeContext::get(handle) else {
+ return;
+ };
unsafe {
- let ctx = ImmGetContext(handle);
- if ctx.is_invalid() {
- return;
- }
+ ImmSetCompositionWindow(
+ *ctx,
+ &COMPOSITIONFORM {
+ dwStyle: CFS_POINT,
+ ptCurrentPos: caret_position,
+ ..Default::default()
+ },
+ )
+ .ok()
+ .log_err();
- let config = COMPOSITIONFORM {
- dwStyle: CFS_POINT,
- ptCurrentPos: caret_position,
- ..Default::default()
- };
- ImmSetCompositionWindow(ctx, &config).ok().log_err();
- let config = CANDIDATEFORM {
- dwStyle: CFS_CANDIDATEPOS,
- ptCurrentPos: caret_position,
- ..Default::default()
- };
- ImmSetCandidateWindow(ctx, &config).ok().log_err();
- ImmReleaseContext(handle, ctx).ok().log_err();
+ ImmSetCandidateWindow(
+ *ctx,
+ &CANDIDATEFORM {
+ dwStyle: CFS_CANDIDATEPOS,
+ ptCurrentPos: caret_position,
+ ..Default::default()
+ },
+ )
+ .ok()
+ .log_err();
+ }
+ }
+
+ fn update_ime_enabled(&self, handle: HWND) {
+ let ime_enabled = self
+ .with_input_handler(|input_handler| input_handler.query_accepts_text_input())
+ .unwrap_or(false);
+ if ime_enabled == self.state.ime_enabled.get() {
+ return;
+ }
+ self.state.ime_enabled.set(ime_enabled);
+ unsafe {
+ if ime_enabled {
+ ImmAssociateContextEx(handle, HIMC::default(), IACE_DEFAULT)
+ .ok()
+ .log_err();
+ } else {
+ if let Some(ctx) = ImeContext::get(handle) {
+ ImmNotifyIME(*ctx, NI_COMPOSITIONSTR, CPS_COMPLETE, 0)
+ .ok()
+ .log_err();
+ }
+ ImmAssociateContextEx(handle, HIMC::default(), 0)
+ .ok()
+ .log_err();
+ }
}
}
fn handle_ime_composition(&self, handle: HWND, lparam: LPARAM) -> Option<isize> {
- let ctx = unsafe { ImmGetContext(handle) };
- let result = self.handle_ime_composition_inner(ctx, lparam);
- unsafe { ImmReleaseContext(handle, ctx).ok().log_err() };
- result
+ let ctx = ImeContext::get(handle)?;
+ self.handle_ime_composition_inner(*ctx, lparam)
}
fn handle_ime_composition_inner(&self, ctx: HIMC, lparam: LPARAM) -> Option<isize> {
@@ -1123,6 +1153,7 @@ impl WindowsWindowInner {
});
self.state.callbacks.request_frame.set(Some(request_frame));
+ self.update_ime_enabled(handle);
unsafe { ValidateRect(Some(handle), None).ok().log_err() };
Some(0)
@@ -1205,6 +1236,36 @@ impl WindowsWindowInner {
}
}
+struct ImeContext {
+ hwnd: HWND,
+ himc: HIMC,
+}
+
+impl ImeContext {
+ fn get(hwnd: HWND) -> Option<Self> {
+ let himc = unsafe { ImmGetContext(hwnd) };
+ if himc.is_invalid() {
+ return None;
+ }
+ Some(Self { hwnd, himc })
+ }
+}
+
+impl std::ops::Deref for ImeContext {
+ type Target = HIMC;
+ fn deref(&self) -> &HIMC {
+ &self.himc
+ }
+}
+
+impl Drop for ImeContext {
+ fn drop(&mut self) {
+ unsafe {
+ ImmReleaseContext(self.hwnd, self.himc).ok().log_err();
+ }
+ }
+}
+
fn handle_key_event<F>(
wparam: WPARAM,
lparam: LPARAM,
@@ -52,6 +52,7 @@ pub struct WindowsWindowState {
pub callbacks: Callbacks,
pub input_handler: Cell<Option<PlatformInputHandler>>,
+ pub ime_enabled: Cell<bool>,
pub pending_surrogate: Cell<Option<u16>>,
pub last_reported_modifiers: Cell<Option<Modifiers>>,
pub last_reported_capslock: Cell<Option<Capslock>>,
@@ -142,6 +143,7 @@ impl WindowsWindowState {
min_size,
callbacks,
input_handler: Cell::new(input_handler),
+ ime_enabled: Cell::new(true),
pending_surrogate: Cell::new(pending_surrogate),
last_reported_modifiers: Cell::new(last_reported_modifiers),
last_reported_capslock: Cell::new(last_reported_capslock),
@@ -978,6 +978,7 @@ impl Vim {
editor.set_clip_at_line_ends(false, cx);
editor.set_collapse_matches(false);
editor.set_input_enabled(true);
+ editor.set_expects_character_input(true);
editor.set_autoindent(true);
editor.selections.set_line_mode(false);
editor.unregister_addon::<VimAddon>();
@@ -1346,6 +1347,15 @@ impl Vim {
}
}
+ fn expects_character_input(&self) -> bool {
+ if let Some(operator) = self.operator_stack.last() {
+ if operator.is_waiting(self.mode) {
+ return true;
+ }
+ }
+ self.editor_input_enabled()
+ }
+
pub fn editor_input_enabled(&self) -> bool {
match self.mode {
Mode::Insert => {
@@ -2058,6 +2068,7 @@ impl Vim {
clip_at_line_ends: self.clip_at_line_ends(),
collapse_matches: !HelixModeSetting::get_global(cx).0,
input_enabled: self.editor_input_enabled(),
+ expects_character_input: self.expects_character_input(),
autoindent: self.should_autoindent(),
cursor_offset_on_selection: self.mode.is_visual(),
line_mode: matches!(self.mode, Mode::VisualLine),
@@ -2075,6 +2086,7 @@ impl Vim {
editor.set_clip_at_line_ends(state.clip_at_line_ends, cx);
editor.set_collapse_matches(state.collapse_matches);
editor.set_input_enabled(state.input_enabled);
+ editor.set_expects_character_input(state.expects_character_input);
editor.set_autoindent(state.autoindent);
editor.set_cursor_offset_on_selection(state.cursor_offset_on_selection);
editor.selections.set_line_mode(state.line_mode);
@@ -2087,6 +2099,7 @@ struct VimEditorSettingsState {
clip_at_line_ends: bool,
collapse_matches: bool,
input_enabled: bool,
+ expects_character_input: bool,
autoindent: bool,
cursor_offset_on_selection: bool,
line_mode: bool,