Skip to content

Commit

Permalink
Render IME selected string in different color from other preedit string
Browse files Browse the repository at this point in the history
  • Loading branch information
kumattau committed Jun 5, 2022
1 parent 9b6329b commit 13eef3d
Show file tree
Hide file tree
Showing 10 changed files with 221 additions and 34 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion wezterm-gui/src/scripting/guiwin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ impl UserData for GuiWin {
.notify(TermWindowNotif::Apply(Box::new(move |term_window| {
tx.try_send(match term_window.composition_status() {
DeadKeyStatus::None => None,
DeadKeyStatus::Composing(s) => Some(s.clone()),
DeadKeyStatus::Composing(s, ..) => Some(s.clone()),
})
.ok();
})));
Expand Down
56 changes: 51 additions & 5 deletions wezterm-gui/src/termwindow/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1891,16 +1891,18 @@ impl super::TermWindow {
};

// Referencing the text being composed, but only if it belongs to this pane
let composing = if cursor_idx.is_some() {
if let DeadKeyStatus::Composing(composing) = &self.dead_key_status {
Some(composing)
let (composing, selected_range) = if cursor_idx.is_some() {
if let DeadKeyStatus::Composing(composing, selected_range) = &self.dead_key_status {
(Some(composing), selected_range.as_ref())
} else {
None
(None, None)
}
} else {
None
(None, None)
};

let mut selected_start = 0;
let mut selected_width = 0;
let mut composition_width = 0;

let (bidi_enabled, bidi_direction) = params.line.bidi_info();
Expand All @@ -1923,6 +1925,12 @@ impl super::TermWindow {
);
cell_clusters = line.cluster(bidi_hint);
composition_width = unicode_column_width(composing, None);

if let Some(selected_range) = selected_range {
selected_start = unicode_column_width(&composing[..selected_range.start], None);
selected_width = unicode_column_width(&composing[selected_range.clone()], None);
}

&cell_clusters
} else {
cell_clusters = params.line.cluster(bidi_hint);
Expand All @@ -1944,6 +1952,12 @@ impl super::TermWindow {
0..0
};

let selected_cursor_range = if selected_width > 0 {
params.cursor.x + selected_start..params.cursor.x + selected_start + selected_width
} else {
0..0
};

let cursor_range_pixels = params.left_pixel_x + cursor_range.start as f32 * cell_width
..params.left_pixel_x + cursor_range.end as f32 * cell_width;

Expand Down Expand Up @@ -2140,6 +2154,38 @@ impl super::TermWindow {

quad.set_fg_color(cursor_border_color);
quad.set_alt_color_and_mix_value(cursor_border_color_alt, cursor_border_mix);

if !selected_cursor_range.is_empty()
&& (cursor_range.start <= selected_cursor_range.start)
&& (selected_cursor_range.end <= cursor_range.end)
{
let mut quad = layers[0].allocate()?;
quad.set_position(
pos_x
+ (selected_cursor_range.start - cursor_range.start) as f32
* cell_width,
pos_y,
pos_x
+ (selected_cursor_range.end - cursor_range.start) as f32 * cell_width,
pos_y + cell_height,
);
quad.set_hsv(hsv);
quad.set_has_color(false);

quad.set_texture(
gl_state
.glyph_cache
.borrow_mut()
.cursor_sprite(
cursor_shape,
&params.render_metrics,
(selected_cursor_range.end - selected_cursor_range.start) as u8,
)?
.texture_coords(),
);

quad.set_fg_color(params.selection_bg);
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion window/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ smithay-client-toolkit = {version = "0.15", default-features=false, optional=tru
wayland-protocols = {version="0.29", optional=true}
wayland-client = {version="0.29", optional=true}
wayland-egl = {version="0.29", optional=true}
xcb-imdkit = { version="0.2", git="https://github.com/wez/xcb-imdkit-rs.git", rev="ede7c71b85fe2537efef6cf999a45690316211cf"}
xcb-imdkit = {version="0.2", git="https://github.com/kumattau/xcb-imdkit-rs.git", rev="9ba1522493167c2430f20b06597240bd00bebd81"}

[target.'cfg(target_os="macos")'.dependencies]
cocoa = "0.20"
Expand Down
3 changes: 2 additions & 1 deletion window/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use bitflags::bitflags;
use config::{ConfigHandle, Dimension, GeometryOrigin};
use promise::Future;
use std::any::Any;
use std::ops::Range;
use std::path::PathBuf;
use std::rc::Rc;
use thiserror::Error;
Expand Down Expand Up @@ -131,7 +132,7 @@ pub enum DeadKeyStatus {
None,
/// Holding until composition is done; the string is the uncommitted
/// composition text to show as a placeholder
Composing(String),
Composing(String, Option<Range<usize>>),
}

#[derive(Debug)]
Expand Down
7 changes: 6 additions & 1 deletion window/src/os/macos/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,16 @@ fn nsstring(s: &str) -> StrongPtr {
unsafe { StrongPtr::new(NSString::alloc(nil).init_str(s)) }
}

unsafe fn nsstring_to_str<'a>(mut ns: *mut Object) -> &'a str {
unsafe fn unattributed(mut ns: *mut Object) -> *mut Object {
let is_astring: bool = msg_send![ns, isKindOfClass: class!(NSAttributedString)];
if is_astring {
ns = msg_send![ns, string];
}
ns
}

unsafe fn nsstring_to_str<'a>(mut ns: *mut Object) -> &'a str {
ns = unattributed(ns);
let data = NSString::UTF8String(ns as id) as *const u8;
let len = NSString::len(ns as id);
let bytes = std::slice::from_raw_parts(data, len);
Expand Down
63 changes: 59 additions & 4 deletions window/src/os/macos/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#![allow(clippy::let_unit_value)]

use super::keycodes::*;
use super::{nsstring, nsstring_to_str};
use super::{nsstring, nsstring_to_str, unattributed};
use crate::connection::ConnectionOps;
use crate::parameters::{Border, Parameters, TitleBar};
use crate::{
Expand Down Expand Up @@ -41,6 +41,7 @@ use raw_window_handle::{HasRawWindowHandle, RawWindowHandle};
use std::any::Any;
use std::cell::RefCell;
use std::ffi::c_void;
use std::ops::Range;
use std::path::PathBuf;
use std::rc::Rc;
use std::str::FromStr;
Expand Down Expand Up @@ -434,6 +435,7 @@ impl Window {
ime_last_event: None,
live_resizing: false,
ime_text: String::new(),
selected_range: None,
}));

let window: id = msg_send![get_window_class(), alloc];
Expand Down Expand Up @@ -1154,6 +1156,7 @@ struct Inner {
live_resizing: bool,

ime_text: String,
selected_range: Option<Range<usize>>,
}

#[repr(C)]
Expand Down Expand Up @@ -1637,6 +1640,7 @@ impl WindowView {
if let Some(myself) = Self::get_this(this) {
let mut inner = myself.inner.borrow_mut();
inner.ime_text = s.to_string();
inner.selected_range = calc_str_selected_range(astring, selected_range, s.len());

/*
let key_is_down = inner.key_is_down.take().unwrap_or(true);
Expand Down Expand Up @@ -2095,7 +2099,7 @@ impl WindowView {
Ok(TranslateStatus::Composing(composing)) => {
// Next key press in dead key sequence is pending.
inner.events.dispatch(WindowEvent::AdviseDeadKeyStatus(
DeadKeyStatus::Composing(composing),
DeadKeyStatus::Composing(composing, None),
));

return;
Expand Down Expand Up @@ -2205,7 +2209,10 @@ impl WindowView {
// If it didn't generate an event, then a composition
// is pending.
let status = if inner.ime_last_event.is_none() {
DeadKeyStatus::Composing(inner.ime_text.clone())
DeadKeyStatus::Composing(
inner.ime_text.clone(),
inner.selected_range.clone(),
)
} else {
DeadKeyStatus::None
};
Expand Down Expand Up @@ -2235,7 +2242,10 @@ impl WindowView {
let status = if inner.ime_text.is_empty() {
DeadKeyStatus::None
} else {
DeadKeyStatus::Composing(inner.ime_text.clone())
DeadKeyStatus::Composing(
inner.ime_text.clone(),
inner.selected_range.clone(),
)
};
inner
.events
Expand Down Expand Up @@ -2870,3 +2880,48 @@ fn resolve_geom(geometry: RequestedWindowGeometry) -> ResolvedGeometry {

ResolvedGeometry { pos, width, height }
}

fn calc_str_selected_range(
astring: *mut Object,
selected_range: NSRange,
max: usize,
) -> Option<Range<usize>> {
unsafe fn sub_tostr_len(ns: *mut Object, range: NSRange, max: usize) -> usize {
let sub = msg_send![ns, substringWithRange: range];
let len = nsstring_to_str(sub).len();
std::cmp::min(len, max)
}

let ns;
let ns_length;
unsafe {
ns = unattributed(astring);
ns_length = msg_send![ns, length];
}

let a_start = selected_range.0.location;
let a_end = a_start + selected_range.0.length;
if ns_length < a_end {
return None;
}

let s_start;
let s_end;
unsafe {
s_start = if 0 < a_start {
sub_tostr_len(ns, NSRange::new(0, a_start), max)
} else {
0
};
s_end = if a_end < ns_length {
s_start + sub_tostr_len(ns, NSRange::new(a_start, a_end - a_start), max)
} else {
max
};
}
if s_end <= s_start {
return None;
}

Some(s_start..s_end)
}
Loading

0 comments on commit 13eef3d

Please sign in to comment.