Compare commits

...

10 Commits

Author SHA1 Message Date
Zed Bot
b49f020551 Bump to 0.163.1 for @ConradIrwin 2024-11-21 17:41:27 +00:00
gcp-cherry-pick-bot[bot]
226680f800 Fix keybindings on a Spanish ISO keyboard (cherry-pick #20995) (#20998)
Cherry-picked Fix keybindings on a Spanish ISO keyboard (#20995)

Co-Authored-By: Peter <peter@zed.dev>

Also reformatted the mappings to be easier to read/edit by hand.

Release Notes:

- Fixed keyboard shortcuts on Spanish ISO keyboards

---------

Co-authored-by: Peter <peter@zed.dev>

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
Co-authored-by: Peter <peter@zed.dev>
2024-11-21 10:26:53 -07:00
gcp-cherry-pick-bot[bot]
a882efe679 vim: Fix shortcuts that require shift+punct (cherry-pick #20990) (#20992)
Cherry-picked vim: Fix shortcuts that require shift+punct (#20990)

Fixes a bug I introduced in #20953

Release Notes:

- N/A

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2024-11-21 09:54:00 -07:00
gcp-cherry-pick-bot[bot]
21b1a0580c Clip UTF-16 offsets in text for range (cherry-pick #20968) (#20969)
Cherry-picked 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

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2024-11-20 22:19:25 -07:00
Conrad Irwin
90baed50a9 Use our own git clone in daft release notes 2024-11-20 22:05:25 -07:00
gcp-cherry-pick-bot[bot]
7275ee53ee Drop platform lock when setting menu (cherry-pick #20962) (#20965)
Cherry-picked Drop platform lock when setting menu (#20962)

Turns out setting the menu (sometimes) calls `selected_range` on the
input
handler.

https://zed-industries.slack.com/archives/C04S6T1T7TQ/p1732160078058279

Release Notes:

- Fixed a panic when reloading keymaps

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2024-11-20 21:43:28 -07:00
gcp-cherry-pick-bot[bot]
0a169c0f70 Rename ime_key -> key_char and update behavior (cherry-pick #20953) (#20957)
Cherry-picked Rename ime_key -> key_char and update behavior (#20953)

As part of the recent changes to keyboard support, ime_key is no longer
populated by the IME; but instead by the keyboard.

As part of #20877 I changed some code to assume that falling back to key
was
ok, but this was not ok; instead we need to populate this more similarly
to how
it was done before #20336.

The alternative fix could be to instead of simulating these events in
our own
code to push a fake native event back to the platform input handler.

Closes #ISSUE

Release Notes:

- Fixed a bug where tapping `shift` coudl type "shift" if you had a
binding on "shift shift"

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2024-11-20 20:54:06 -07:00
gcp-cherry-pick-bot[bot]
31ad658c13 Don't re-render the menu so often (cherry-pick #20914) (#20915)
Cherry-picked Don't re-render the menu so often (#20914)

Closes #20710

Release Notes:

- Fixes opening the menu when Chinese Pinyin keyboard is in use

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2024-11-20 15:38:22 -07:00
Peter Tripp
8444a6f4ee Fix for fetch-tags error. 2024-11-20 11:53:37 -05:00
Joseph T. Lyons
209d666470 v0.163.x preview 2024-11-20 10:45:22 -05:00
26 changed files with 1580 additions and 289 deletions

View File

@@ -244,8 +244,8 @@ jobs:
#
# 25 was chosen arbitrarily.
fetch-depth: 25
fetch-tags: true
clean: false
ref: ${{ github.ref }}
- name: Limit target directory size
run: script/clear-target-dir-if-larger-than 100

2
Cargo.lock generated
View File

@@ -15422,7 +15422,7 @@ dependencies = [
[[package]]
name = "zed"
version = "0.163.0"
version = "0.163.1"
dependencies = [
"activity_indicator",
"anyhow",

View File

@@ -14434,15 +14434,16 @@ impl ViewInputHandler for Editor {
fn text_for_range(
&mut self,
range_utf16: Range<usize>,
adjusted_range: &mut Option<Range<usize>>,
cx: &mut ViewContext<Self>,
) -> Option<String> {
Some(
self.buffer
.read(cx)
.read(cx)
.text_for_range(OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end))
.collect(),
)
let snapshot = self.buffer.read(cx).read(cx);
let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
if (start.0..end.0) != range_utf16 {
adjusted_range.replace(start.0..end.0);
}
Some(snapshot.text_for_range(start..end).collect())
}
fn selected_text_range(

View File

@@ -15,7 +15,10 @@ actions!(
SelectAll,
Home,
End,
ShowCharacterPalette
ShowCharacterPalette,
Paste,
Cut,
Copy,
]
);
@@ -107,6 +110,28 @@ impl TextInput {
cx.show_character_palette();
}
fn paste(&mut self, _: &Paste, cx: &mut ViewContext<Self>) {
if let Some(text) = cx.read_from_clipboard().and_then(|item| item.text()) {
self.replace_text_in_range(None, &text.replace("\n", " "), cx);
}
}
fn copy(&mut self, _: &Copy, cx: &mut ViewContext<Self>) {
if !self.selected_range.is_empty() {
cx.write_to_clipboard(ClipboardItem::new_string(
(&self.content[self.selected_range.clone()]).to_string(),
));
}
}
fn cut(&mut self, _: &Copy, cx: &mut ViewContext<Self>) {
if !self.selected_range.is_empty() {
cx.write_to_clipboard(ClipboardItem::new_string(
(&self.content[self.selected_range.clone()]).to_string(),
));
self.replace_text_in_range(None, "", cx)
}
}
fn move_to(&mut self, offset: usize, cx: &mut ViewContext<Self>) {
self.selected_range = offset..offset;
cx.notify()
@@ -219,9 +244,11 @@ impl ViewInputHandler for TextInput {
fn text_for_range(
&mut self,
range_utf16: Range<usize>,
actual_range: &mut Option<Range<usize>>,
_cx: &mut ViewContext<Self>,
) -> Option<String> {
let range = self.range_from_utf16(&range_utf16);
actual_range.replace(self.range_to_utf16(&range));
Some(self.content[range].to_string())
}
@@ -497,6 +524,9 @@ impl Render for TextInput {
.on_action(cx.listener(Self::home))
.on_action(cx.listener(Self::end))
.on_action(cx.listener(Self::show_character_palette))
.on_action(cx.listener(Self::paste))
.on_action(cx.listener(Self::cut))
.on_action(cx.listener(Self::copy))
.on_mouse_down(MouseButton::Left, cx.listener(Self::on_mouse_down))
.on_mouse_up(MouseButton::Left, cx.listener(Self::on_mouse_up))
.on_mouse_up_out(MouseButton::Left, cx.listener(Self::on_mouse_up))
@@ -581,8 +611,8 @@ impl Render for InputExample {
format!(
"{:} {}",
ks.unparse(),
if let Some(ime_key) = ks.ime_key.as_ref() {
format!("-> {:?}", ime_key)
if let Some(key_char) = ks.key_char.as_ref() {
format!("-> {:?}", key_char)
} else {
"".to_owned()
}
@@ -602,6 +632,9 @@ fn main() {
KeyBinding::new("shift-left", SelectLeft, None),
KeyBinding::new("shift-right", SelectRight, None),
KeyBinding::new("cmd-a", SelectAll, None),
KeyBinding::new("cmd-v", Paste, None),
KeyBinding::new("cmd-c", Copy, None),
KeyBinding::new("cmd-x", Cut, None),
KeyBinding::new("home", Home, None),
KeyBinding::new("end", End, None),
KeyBinding::new("ctrl-cmd-space", ShowCharacterPalette, None),

View File

@@ -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(

View File

@@ -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>;

View File

@@ -12,14 +12,15 @@ pub struct Keystroke {
/// e.g. for option-s, key is "s"
pub key: String,
/// ime_key is the character inserted by the IME engine when that key was pressed.
/// e.g. for option-s, ime_key is "ß"
pub ime_key: Option<String>,
/// key_char is the character that could have been typed when
/// this binding was pressed.
/// e.g. for s this is "s", for option-s "ß", and cmd-s None
pub key_char: Option<String>,
}
impl Keystroke {
/// When matching a key we cannot know whether the user intended to type
/// the ime_key or the key itself. On some non-US keyboards keys we use in our
/// the key_char or the key itself. On some non-US keyboards keys we use in our
/// bindings are behind option (for example `$` is typed `alt-ç` on a Czech keyboard),
/// and on some keyboards the IME handler converts a sequence of keys into a
/// specific character (for example `"` is typed as `" space` on a brazilian keyboard).
@@ -27,10 +28,10 @@ impl Keystroke {
/// This method assumes that `self` was typed and `target' is in the keymap, and checks
/// both possibilities for self against the target.
pub(crate) fn should_match(&self, target: &Keystroke) -> bool {
if let Some(ime_key) = self
.ime_key
if let Some(key_char) = self
.key_char
.as_ref()
.filter(|ime_key| ime_key != &&self.key)
.filter(|key_char| key_char != &&self.key)
{
let ime_modifiers = Modifiers {
control: self.modifiers.control,
@@ -38,7 +39,7 @@ impl Keystroke {
..Default::default()
};
if &target.key == ime_key && target.modifiers == ime_modifiers {
if &target.key == key_char && target.modifiers == ime_modifiers {
return true;
}
}
@@ -47,9 +48,9 @@ impl Keystroke {
}
/// key syntax is:
/// [ctrl-][alt-][shift-][cmd-][fn-]key[->ime_key]
/// ime_key syntax is only used for generating test events,
/// when matching a key with an ime_key set will be matched without it.
/// [ctrl-][alt-][shift-][cmd-][fn-]key[->key_char]
/// key_char syntax is only used for generating test events,
/// when matching a key with an key_char set will be matched without it.
pub fn parse(source: &str) -> anyhow::Result<Self> {
let mut control = false;
let mut alt = false;
@@ -57,7 +58,7 @@ impl Keystroke {
let mut platform = false;
let mut function = false;
let mut key = None;
let mut ime_key = None;
let mut key_char = None;
let mut components = source.split('-').peekable();
while let Some(component) = components.next() {
@@ -74,7 +75,7 @@ impl Keystroke {
break;
} else if next.len() > 1 && next.starts_with('>') {
key = Some(String::from(component));
ime_key = Some(String::from(&next[1..]));
key_char = Some(String::from(&next[1..]));
components.next();
} else {
return Err(anyhow!("Invalid keystroke `{}`", source));
@@ -118,7 +119,7 @@ impl Keystroke {
function,
},
key,
ime_key,
key_char: key_char,
})
}
@@ -154,7 +155,7 @@ impl Keystroke {
/// Returns true if this keystroke left
/// the ime system in an incomplete state.
pub fn is_ime_in_progress(&self) -> bool {
self.ime_key.is_none()
self.key_char.is_none()
&& (is_printable_key(&self.key) || self.key.is_empty())
&& !(self.modifiers.platform
|| self.modifiers.control
@@ -162,17 +163,17 @@ impl Keystroke {
|| self.modifiers.alt)
}
/// Returns a new keystroke with the ime_key filled.
/// Returns a new keystroke with the key_char filled.
/// This is used for dispatch_keystroke where we want users to
/// be able to simulate typing "space", etc.
pub fn with_simulated_ime(mut self) -> Self {
if self.ime_key.is_none()
if self.key_char.is_none()
&& !self.modifiers.platform
&& !self.modifiers.control
&& !self.modifiers.function
&& !self.modifiers.alt
{
self.ime_key = match self.key.as_str() {
self.key_char = match self.key.as_str() {
"space" => Some(" ".into()),
"tab" => Some("\t".into()),
"enter" => Some("\n".into()),

View File

@@ -742,14 +742,14 @@ impl Keystroke {
}
}
// Ignore control characters (and DEL) for the purposes of ime_key
let ime_key =
// Ignore control characters (and DEL) for the purposes of key_char
let key_char =
(key_utf32 >= 32 && key_utf32 != 127 && !key_utf8.is_empty()).then_some(key_utf8);
Keystroke {
modifiers,
key,
ime_key,
key_char,
}
}

View File

@@ -1208,7 +1208,7 @@ impl Dispatch<wl_keyboard::WlKeyboard, ()> for WaylandClientStatePtr {
compose.feed(keysym);
match compose.status() {
xkb::Status::Composing => {
keystroke.ime_key = None;
keystroke.key_char = None;
state.pre_edit_text =
compose.utf8().or(Keystroke::underlying_dead_key(keysym));
let pre_edit =
@@ -1220,7 +1220,7 @@ impl Dispatch<wl_keyboard::WlKeyboard, ()> for WaylandClientStatePtr {
xkb::Status::Composed => {
state.pre_edit_text.take();
keystroke.ime_key = compose.utf8();
keystroke.key_char = compose.utf8();
if let Some(keysym) = compose.keysym() {
keystroke.key = xkb::keysym_get_name(keysym);
}
@@ -1340,7 +1340,7 @@ impl Dispatch<zwp_text_input_v3::ZwpTextInputV3, ()> for WaylandClientStatePtr {
keystroke: Keystroke {
modifiers: Modifiers::default(),
key: commit_text.clone(),
ime_key: Some(commit_text),
key_char: Some(commit_text),
},
is_held: false,
}));

View File

@@ -687,11 +687,11 @@ impl WaylandWindowStatePtr {
}
}
if let PlatformInput::KeyDown(event) = input {
if let Some(ime_key) = &event.keystroke.ime_key {
if let Some(key_char) = &event.keystroke.key_char {
let mut state = self.state.borrow_mut();
if let Some(mut input_handler) = state.input_handler.take() {
drop(state);
input_handler.replace_text_in_range(None, ime_key);
input_handler.replace_text_in_range(None, key_char);
self.state.borrow_mut().input_handler = Some(input_handler);
}
}

View File

@@ -178,7 +178,7 @@ pub struct X11ClientState {
pub(crate) compose_state: Option<xkbc::compose::State>,
pub(crate) pre_edit_text: Option<String>,
pub(crate) composing: bool,
pub(crate) pre_ime_key_down: Option<Keystroke>,
pub(crate) pre_key_char_down: Option<Keystroke>,
pub(crate) cursor_handle: cursor::Handle,
pub(crate) cursor_styles: HashMap<xproto::Window, CursorStyle>,
pub(crate) cursor_cache: HashMap<CursorStyle, xproto::Cursor>,
@@ -446,7 +446,7 @@ impl X11Client {
compose_state,
pre_edit_text: None,
pre_ime_key_down: None,
pre_key_char_down: None,
composing: false,
cursor_handle,
@@ -858,7 +858,7 @@ impl X11Client {
let modifiers = modifiers_from_state(event.state);
state.modifiers = modifiers;
state.pre_ime_key_down.take();
state.pre_key_char_down.take();
let keystroke = {
let code = event.detail.into();
let xkb_state = state.previous_xkb_state.clone();
@@ -880,13 +880,13 @@ impl X11Client {
match compose_state.status() {
xkbc::Status::Composed => {
state.pre_edit_text.take();
keystroke.ime_key = compose_state.utf8();
keystroke.key_char = compose_state.utf8();
if let Some(keysym) = compose_state.keysym() {
keystroke.key = xkbc::keysym_get_name(keysym);
}
}
xkbc::Status::Composing => {
keystroke.ime_key = None;
keystroke.key_char = None;
state.pre_edit_text = compose_state
.utf8()
.or(crate::Keystroke::underlying_dead_key(keysym));
@@ -1156,7 +1156,7 @@ impl X11Client {
match event {
Event::KeyPress(event) | Event::KeyRelease(event) => {
let mut state = self.0.borrow_mut();
state.pre_ime_key_down = Some(Keystroke::from_xkb(
state.pre_key_char_down = Some(Keystroke::from_xkb(
&state.xkb,
state.modifiers,
event.detail.into(),
@@ -1187,11 +1187,11 @@ impl X11Client {
fn xim_handle_commit(&self, window: xproto::Window, text: String) -> Option<()> {
let window = self.get_window(window).unwrap();
let mut state = self.0.borrow_mut();
let keystroke = state.pre_ime_key_down.take();
let keystroke = state.pre_key_char_down.take();
state.composing = false;
drop(state);
if let Some(mut keystroke) = keystroke {
keystroke.ime_key = Some(text.clone());
keystroke.key_char = Some(text.clone());
window.handle_input(PlatformInput::KeyDown(crate::KeyDownEvent {
keystroke,
is_held: false,

View File

@@ -846,9 +846,9 @@ impl X11WindowStatePtr {
if let PlatformInput::KeyDown(event) = input {
let mut state = self.state.borrow_mut();
if let Some(mut input_handler) = state.input_handler.take() {
if let Some(ime_key) = &event.keystroke.ime_key {
if let Some(key_char) = &event.keystroke.key_char {
drop(state);
input_handler.replace_text_in_range(None, ime_key);
input_handler.replace_text_in_range(None, key_char);
state = self.state.borrow_mut();
}
state.input_handler = Some(input_handler);

View File

@@ -245,7 +245,7 @@ unsafe fn parse_keystroke(native_event: id) -> Keystroke {
.charactersIgnoringModifiers()
.to_str()
.to_string();
let mut ime_key = None;
let mut key_char = None;
let first_char = characters.chars().next().map(|ch| ch as u16);
let modifiers = native_event.modifierFlags();
@@ -261,13 +261,19 @@ unsafe fn parse_keystroke(native_event: id) -> Keystroke {
#[allow(non_upper_case_globals)]
let key = match first_char {
Some(SPACE_KEY) => {
ime_key = Some(" ".to_string());
key_char = Some(" ".to_string());
"space".to_string()
}
Some(TAB_KEY) => {
key_char = Some("\t".to_string());
"tab".to_string()
}
Some(ENTER_KEY) | Some(NUMPAD_ENTER_KEY) => {
key_char = Some("\n".to_string());
"enter".to_string()
}
Some(BACKSPACE_KEY) => "backspace".to_string(),
Some(ENTER_KEY) | Some(NUMPAD_ENTER_KEY) => "enter".to_string(),
Some(ESCAPE_KEY) => "escape".to_string(),
Some(TAB_KEY) => "tab".to_string(),
Some(SHIFT_TAB_KEY) => "tab".to_string(),
Some(NSUpArrowFunctionKey) => "up".to_string(),
Some(NSDownArrowFunctionKey) => "down".to_string(),
@@ -335,6 +341,18 @@ unsafe fn parse_keystroke(native_event: id) -> Keystroke {
chars_ignoring_modifiers = chars_with_cmd;
}
if !control && !command && !function {
let mut mods = NO_MOD;
if shift {
mods |= SHIFT_MOD;
}
if alt {
mods |= OPTION_MOD;
}
key_char = Some(chars_for_modified_key(native_event.keyCode(), mods));
}
let mut key = if shift
&& chars_ignoring_modifiers
.chars()
@@ -348,20 +366,6 @@ unsafe fn parse_keystroke(native_event: id) -> Keystroke {
chars_ignoring_modifiers
};
if always_use_cmd_layout || alt {
let mut mods = NO_MOD;
if shift {
mods |= SHIFT_MOD;
}
if alt {
mods |= OPTION_MOD;
}
let alt_key = chars_for_modified_key(native_event.keyCode(), mods);
if alt_key != key {
ime_key = Some(alt_key);
}
};
key
}
};
@@ -375,7 +379,7 @@ unsafe fn parse_keystroke(native_event: id) -> Keystroke {
function,
},
key,
ime_key,
key_char,
}
}

View File

@@ -844,7 +844,9 @@ impl Platform for MacPlatform {
let app: id = msg_send![APP_CLASS, sharedApplication];
let mut state = self.0.lock();
let actions = &mut state.menu_actions;
app.setMainMenu_(self.create_menu_bar(menus, NSWindow::delegate(app), actions, keymap));
let menu = self.create_menu_bar(menus, NSWindow::delegate(app), actions, keymap);
drop(state);
app.setMainMenu_(menu);
}
}

View File

@@ -38,6 +38,7 @@ use std::{
cell::Cell,
ffi::{c_void, CStr},
mem,
ops::Range,
path::PathBuf,
ptr::{self, NonNull},
rc::Rc,
@@ -1283,18 +1284,17 @@ extern "C" fn handle_key_event(this: &Object, native_event: id, key_equivalent:
}
if event.is_held {
let handled = with_input_handler(&this, |input_handler| {
if !input_handler.apple_press_and_hold_enabled() {
input_handler.replace_text_in_range(
None,
&event.keystroke.ime_key.unwrap_or(event.keystroke.key),
);
if let Some(key_char) = event.keystroke.key_char.as_ref() {
let handled = with_input_handler(&this, |input_handler| {
if !input_handler.apple_press_and_hold_enabled() {
input_handler.replace_text_in_range(None, &key_char);
return YES;
}
NO
});
if handled == Some(YES) {
return YES;
}
NO
});
if handled == Some(YES) {
return YES;
}
}
@@ -1437,7 +1437,7 @@ extern "C" fn cancel_operation(this: &Object, _sel: Sel, _sender: id) {
let keystroke = Keystroke {
modifiers: Default::default(),
key: ".".into(),
ime_key: None,
key_char: None,
};
let event = PlatformInput::KeyDown(KeyDownEvent {
keystroke: keystroke.clone(),
@@ -1755,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)];

View File

@@ -386,7 +386,7 @@ fn handle_char_msg(
return Some(1);
};
drop(lock);
let ime_key = keystroke.ime_key.clone();
let key_char = keystroke.key_char.clone();
let event = KeyDownEvent {
keystroke,
is_held: lparam.0 & (0x1 << 30) > 0,
@@ -397,7 +397,7 @@ fn handle_char_msg(
if dispatch_event_result.default_prevented || !dispatch_event_result.propagate {
return Some(0);
}
let Some(ime_char) = ime_key else {
let Some(ime_char) = key_char else {
return Some(1);
};
with_input_handler(&state_ptr, |input_handler| {
@@ -1172,7 +1172,7 @@ fn parse_syskeydown_msg_keystroke(wparam: WPARAM) -> Option<Keystroke> {
Some(Keystroke {
modifiers,
key,
ime_key: None,
key_char: None,
})
}
@@ -1220,7 +1220,7 @@ fn parse_keydown_msg_keystroke(wparam: WPARAM) -> Option<KeystrokeOrModifier> {
return Some(KeystrokeOrModifier::Keystroke(Keystroke {
modifiers,
key: format!("f{}", offset + 1),
ime_key: None,
key_char: None,
}));
};
return None;
@@ -1231,7 +1231,7 @@ fn parse_keydown_msg_keystroke(wparam: WPARAM) -> Option<KeystrokeOrModifier> {
Some(KeystrokeOrModifier::Keystroke(Keystroke {
modifiers,
key,
ime_key: None,
key_char: None,
}))
}
@@ -1253,7 +1253,7 @@ fn parse_char_msg_keystroke(wparam: WPARAM) -> Option<Keystroke> {
Some(Keystroke {
modifiers,
key,
ime_key: Some(first_char.to_string()),
key_char: Some(first_char.to_string()),
})
}
}
@@ -1327,7 +1327,7 @@ fn basic_vkcode_to_string(code: u16, modifiers: Modifiers) -> Option<Keystroke>
Some(Keystroke {
modifiers,
key,
ime_key: None,
key_char: None,
})
}

View File

@@ -3038,7 +3038,7 @@ impl<'a> WindowContext<'a> {
return true;
}
if let Some(input) = keystroke.with_simulated_ime().ime_key {
if let Some(input) = keystroke.key_char {
if let Some(mut input_handler) = self.window.platform_window.take_input_handler() {
input_handler.dispatch_input(&input, self);
self.window.platform_window.set_input_handler(input_handler);
@@ -3267,7 +3267,7 @@ impl<'a> WindowContext<'a> {
if let Some(key) = key {
keystroke = Some(Keystroke {
key: key.to_string(),
ime_key: None,
key_char: None,
modifiers: Modifiers::default(),
});
}
@@ -3482,13 +3482,7 @@ impl<'a> WindowContext<'a> {
if !self.propagate_event {
continue 'replay;
}
if let Some(input) = replay
.keystroke
.with_simulated_ime()
.ime_key
.as_ref()
.cloned()
{
if let Some(input) = replay.keystroke.key_char.as_ref().cloned() {
if let Some(mut input_handler) = self.window.platform_window.take_input_handler() {
input_handler.dispatch_input(&input, self);
self.window.platform_window.set_input_handler(input_handler)

View File

@@ -206,7 +206,7 @@ fn render_markdown_list_item(
let secondary_modifier = Keystroke {
key: "".to_string(),
modifiers: Modifiers::secondary_key(),
ime_key: None,
key_char: None,
};
Tooltip::text(
format!("{}-click to toggle the checkbox", secondary_modifier),

File diff suppressed because it is too large Load Diff

View File

@@ -343,7 +343,7 @@ mod test {
function: false,
},
key: "🖖🏻".to_string(), //2 char string
ime_key: None,
key_char: None,
};
assert_eq!(to_esc_str(&ks, &TermMode::NONE, false), None);
}

View File

@@ -1001,6 +1001,7 @@ impl InputHandler for TerminalInputHandler {
fn text_for_range(
&mut self,
_: std::ops::Range<usize>,
_: &mut Option<std::ops::Range<usize>>,
_: &mut WindowContext,
) -> Option<String> {
None

View File

@@ -83,7 +83,7 @@ impl Vim {
cx: &mut ViewContext<Self>,
) {
// handled by handle_literal_input
if keystroke_event.keystroke.ime_key.is_some() {
if keystroke_event.keystroke.key_char.is_some() {
return;
};

View File

@@ -2,7 +2,7 @@
description = "The fast, collaborative code editor."
edition = "2021"
name = "zed"
version = "0.163.0"
version = "0.163.1"
publish = false
license = "GPL-3.0-or-later"
authors = ["Zed Team <hi@zed.dev>"]

View File

@@ -1 +1 @@
dev
preview

View File

@@ -824,8 +824,13 @@ pub fn handle_keymap_file_changes(
})
.detach();
cx.on_keyboard_layout_change(move |_| {
keyboard_layout_tx.unbounded_send(()).ok();
let mut current_mapping = settings::get_key_equivalents(cx.keyboard_layout());
cx.on_keyboard_layout_change(move |cx| {
let next_mapping = settings::get_key_equivalents(cx.keyboard_layout());
if next_mapping != current_mapping {
current_mapping = next_mapping;
keyboard_layout_tx.unbounded_send(()).ok();
}
})
.detach();

View File

@@ -19,24 +19,45 @@ async function main() {
process.exit(1);
}
let priorVersion = [parts[0], parts[1], parts[2] - 1].join(".");
let suffix = "";
if (channel == "preview") {
suffix = "-pre";
if (parts[2] == 0) {
priorVersion = [parts[0], parts[1] - 1, 0].join(".");
}
} else if (!ensureTag(`v${priorVersion}`)) {
console.log("Copy the release notes from preview.");
// currently we can only draft notes for patch releases.
if (parts[2] == 0) {
process.exit(0);
}
let priorVersion = [parts[0], parts[1], parts[2] - 1].join(".");
let suffix = channel == "preview" ? "-pre" : "";
let [tag, priorTag] = [`v${version}${suffix}`, `v${priorVersion}${suffix}`];
if (!ensureTag(tag) || !ensureTag(priorTag)) {
console.log("Could not draft release notes, missing a tag:", tag, priorTag);
process.exit(0);
try {
execFileSync("rm", ["-rf", "target/shallow_clone"]);
execFileSync("git", [
"clone",
"https://github.com/zed-industries/zed",
"target/shallow_clone",
"--filter=tree:0",
"--no-checkout",
"--branch",
tag,
"--depth",
100,
]);
execFileSync("git", [
"-C",
"target/shallow_clone",
"rev-parse",
"--verify",
tag,
]);
execFileSync("git", [
"-C",
"target/shallow_clone",
"rev-parse",
"--verify",
priorTag,
]);
} catch (e) {
console.error(e.stderr.toString());
process.exit(1);
}
const newCommits = getCommits(priorTag, tag);
@@ -69,7 +90,13 @@ async function main() {
function getCommits(oldTag, newTag) {
const pullRequestNumbers = execFileSync(
"git",
["log", `${oldTag}..${newTag}`, "--format=DIVIDER\n%H|||%B"],
[
"-C",
"target/shallow_clone",
"log",
`${oldTag}..${newTag}`,
"--format=DIVIDER\n%H|||%B",
],
{ encoding: "utf8" },
)
.replace(/\r\n/g, "\n")
@@ -99,18 +126,3 @@ function getCommits(oldTag, newTag) {
return pullRequestNumbers;
}
function ensureTag(tag) {
try {
execFileSync("git", ["rev-parse", "--verify", tag]);
return true;
} catch (e) {
try {
execFileSync("git"[("fetch", "origin", "--shallow-exclude", tag)]);
execFileSync("git"[("fetch", "origin", "--deepen", "1")]);
return true;
} catch (e) {
return false;
}
}
}