Clip UTF-16 offsets in text for range (#20968)
When launching the Pinyin keyboard, macOS will sometimes try to peek one character back in the string. This caused a panic if the preceding character was an emoji. The docs say "don't assume the range is valid", so now we don't. Release Notes: - (macOS) Fixed a panic when using the Pinyin keyboard with emojis
This commit is contained in:
parent
7285cdb955
commit
ebaa270baf
6 changed files with 70 additions and 16 deletions
|
@ -9,8 +9,12 @@ use std::ops::Range;
|
|||
/// See [`InputHandler`] for details on how to implement each method.
|
||||
pub trait ViewInputHandler: 'static + Sized {
|
||||
/// See [`InputHandler::text_for_range`] for details
|
||||
fn text_for_range(&mut self, range: Range<usize>, cx: &mut ViewContext<Self>)
|
||||
-> Option<String>;
|
||||
fn text_for_range(
|
||||
&mut self,
|
||||
range: Range<usize>,
|
||||
adjusted_range: &mut Option<Range<usize>>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Option<String>;
|
||||
|
||||
/// See [`InputHandler::selected_text_range`] for details
|
||||
fn selected_text_range(
|
||||
|
@ -89,10 +93,12 @@ impl<V: ViewInputHandler> InputHandler for ElementInputHandler<V> {
|
|||
fn text_for_range(
|
||||
&mut self,
|
||||
range_utf16: Range<usize>,
|
||||
adjusted_range: &mut Option<Range<usize>>,
|
||||
cx: &mut WindowContext,
|
||||
) -> Option<String> {
|
||||
self.view
|
||||
.update(cx, |view, cx| view.text_for_range(range_utf16, cx))
|
||||
self.view.update(cx, |view, cx| {
|
||||
view.text_for_range(range_utf16, adjusted_range, cx)
|
||||
})
|
||||
}
|
||||
|
||||
fn replace_text_in_range(
|
||||
|
|
|
@ -643,9 +643,13 @@ impl PlatformInputHandler {
|
|||
}
|
||||
|
||||
#[cfg_attr(any(target_os = "linux", target_os = "freebsd"), allow(dead_code))]
|
||||
fn text_for_range(&mut self, range_utf16: Range<usize>) -> Option<String> {
|
||||
fn text_for_range(
|
||||
&mut self,
|
||||
range_utf16: Range<usize>,
|
||||
adjusted: &mut Option<Range<usize>>,
|
||||
) -> Option<String> {
|
||||
self.cx
|
||||
.update(|cx| self.handler.text_for_range(range_utf16, cx))
|
||||
.update(|cx| self.handler.text_for_range(range_utf16, adjusted, cx))
|
||||
.ok()
|
||||
.flatten()
|
||||
}
|
||||
|
@ -712,6 +716,7 @@ impl PlatformInputHandler {
|
|||
|
||||
/// A struct representing a selection in a text buffer, in UTF16 characters.
|
||||
/// This is different from a range because the head may be before the tail.
|
||||
#[derive(Debug)]
|
||||
pub struct UTF16Selection {
|
||||
/// The range of text in the document this selection corresponds to
|
||||
/// in UTF16 characters.
|
||||
|
@ -749,6 +754,7 @@ pub trait InputHandler: 'static {
|
|||
fn text_for_range(
|
||||
&mut self,
|
||||
range_utf16: Range<usize>,
|
||||
adjusted_range: &mut Option<Range<usize>>,
|
||||
cx: &mut WindowContext,
|
||||
) -> Option<String>;
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ use std::{
|
|||
cell::Cell,
|
||||
ffi::{c_void, CStr},
|
||||
mem,
|
||||
ops::Range,
|
||||
path::PathBuf,
|
||||
ptr::{self, NonNull},
|
||||
rc::Rc,
|
||||
|
@ -1754,15 +1755,21 @@ extern "C" fn attributed_substring_for_proposed_range(
|
|||
this: &Object,
|
||||
_: Sel,
|
||||
range: NSRange,
|
||||
_actual_range: *mut c_void,
|
||||
actual_range: *mut c_void,
|
||||
) -> id {
|
||||
with_input_handler(this, |input_handler| {
|
||||
let range = range.to_range()?;
|
||||
if range.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let mut adjusted: Option<Range<usize>> = None;
|
||||
|
||||
let selected_text = input_handler.text_for_range(range.clone())?;
|
||||
let selected_text = input_handler.text_for_range(range.clone(), &mut adjusted)?;
|
||||
if let Some(adjusted) = adjusted {
|
||||
if adjusted != range {
|
||||
unsafe { (actual_range as *mut NSRange).write(NSRange::from(adjusted)) };
|
||||
}
|
||||
}
|
||||
unsafe {
|
||||
let string: id = msg_send![class!(NSAttributedString), alloc];
|
||||
let string: id = msg_send![string, initWithString: ns_string(&selected_text)];
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue