Merge remote-tracking branch 'origin/main' into cache

# Conflicts:
#	crates/gpui/src/window.rs
This commit is contained in:
Antonio Scandurra 2024-01-12 14:31:13 +01:00
commit 94293b3bf9
73 changed files with 2531 additions and 1824 deletions

View file

@ -978,8 +978,12 @@ extern "C" fn send_event(this: &mut Object, _sel: Sel, native_event: id) {
unsafe {
if let Some(event) = InputEvent::from_native(native_event, None) {
let platform = get_mac_platform(this);
if let Some(callback) = platform.0.lock().event.as_mut() {
if !callback(event) {
let mut lock = platform.0.lock();
if let Some(mut callback) = lock.event.take() {
drop(lock);
let result = callback(event);
platform.0.lock().event.get_or_insert(callback);
if !result {
return;
}
}
@ -1004,30 +1008,42 @@ extern "C" fn did_finish_launching(this: &mut Object, _: Sel, _: id) {
extern "C" fn should_handle_reopen(this: &mut Object, _: Sel, _: id, has_open_windows: bool) {
if !has_open_windows {
let platform = unsafe { get_mac_platform(this) };
if let Some(callback) = platform.0.lock().reopen.as_mut() {
let mut lock = platform.0.lock();
if let Some(mut callback) = lock.reopen.take() {
drop(lock);
callback();
platform.0.lock().reopen.get_or_insert(callback);
}
}
}
extern "C" fn did_become_active(this: &mut Object, _: Sel, _: id) {
let platform = unsafe { get_mac_platform(this) };
if let Some(callback) = platform.0.lock().become_active.as_mut() {
let mut lock = platform.0.lock();
if let Some(mut callback) = lock.become_active.take() {
drop(lock);
callback();
platform.0.lock().become_active.get_or_insert(callback);
}
}
extern "C" fn did_resign_active(this: &mut Object, _: Sel, _: id) {
let platform = unsafe { get_mac_platform(this) };
if let Some(callback) = platform.0.lock().resign_active.as_mut() {
let mut lock = platform.0.lock();
if let Some(mut callback) = lock.resign_active.take() {
drop(lock);
callback();
platform.0.lock().resign_active.get_or_insert(callback);
}
}
extern "C" fn will_terminate(this: &mut Object, _: Sel, _: id) {
let platform = unsafe { get_mac_platform(this) };
if let Some(callback) = platform.0.lock().quit.as_mut() {
let mut lock = platform.0.lock();
if let Some(mut callback) = lock.quit.take() {
drop(lock);
callback();
platform.0.lock().quit.get_or_insert(callback);
}
}
@ -1047,22 +1063,27 @@ extern "C" fn open_urls(this: &mut Object, _: Sel, _: id, urls: id) {
.collect::<Vec<_>>()
};
let platform = unsafe { get_mac_platform(this) };
if let Some(callback) = platform.0.lock().open_urls.as_mut() {
let mut lock = platform.0.lock();
if let Some(mut callback) = lock.open_urls.take() {
drop(lock);
callback(urls);
platform.0.lock().open_urls.get_or_insert(callback);
}
}
extern "C" fn handle_menu_item(this: &mut Object, _: Sel, item: id) {
unsafe {
let platform = get_mac_platform(this);
let mut platform = platform.0.lock();
if let Some(mut callback) = platform.menu_command.take() {
let mut lock = platform.0.lock();
if let Some(mut callback) = lock.menu_command.take() {
let tag: NSInteger = msg_send![item, tag];
let index = tag as usize;
if let Some(action) = platform.menu_actions.get(index) {
callback(action.as_ref());
if let Some(action) = lock.menu_actions.get(index) {
let action = action.boxed_clone();
drop(lock);
callback(&*action);
}
platform.menu_command = Some(callback);
platform.0.lock().menu_command.get_or_insert(callback);
}
}
}
@ -1071,14 +1092,20 @@ extern "C" fn validate_menu_item(this: &mut Object, _: Sel, item: id) -> bool {
unsafe {
let mut result = false;
let platform = get_mac_platform(this);
let mut platform = platform.0.lock();
if let Some(mut callback) = platform.validate_menu_command.take() {
let mut lock = platform.0.lock();
if let Some(mut callback) = lock.validate_menu_command.take() {
let tag: NSInteger = msg_send![item, tag];
let index = tag as usize;
if let Some(action) = platform.menu_actions.get(index) {
if let Some(action) = lock.menu_actions.get(index) {
let action = action.boxed_clone();
drop(lock);
result = callback(action.as_ref());
}
platform.validate_menu_command = Some(callback);
platform
.0
.lock()
.validate_menu_command
.get_or_insert(callback);
}
result
}
@ -1087,10 +1114,11 @@ extern "C" fn validate_menu_item(this: &mut Object, _: Sel, item: id) -> bool {
extern "C" fn menu_will_open(this: &mut Object, _: Sel, _: id) {
unsafe {
let platform = get_mac_platform(this);
let mut platform = platform.0.lock();
if let Some(mut callback) = platform.will_open_menu.take() {
let mut lock = platform.0.lock();
if let Some(mut callback) = lock.will_open_menu.take() {
drop(lock);
callback();
platform.will_open_menu = Some(callback);
platform.0.lock().will_open_menu.get_or_insert(callback);
}
}
}

View file

@ -190,6 +190,9 @@ impl MacTextSystemState {
for font in family.fonts() {
let mut font = font.load()?;
open_type::apply_features(&mut font, features);
let Some(_) = font.glyph_for_char('m') else {
continue;
};
let font_id = FontId(self.fonts.len());
font_ids.push(font_id);
let postscript_name = font.postscript_name().unwrap();
@ -592,169 +595,49 @@ impl From<FontStyle> for FontkitStyle {
}
}
// #[cfg(test)]
// mod tests {
// use super::*;
// use crate::AppContext;
// use font_kit::properties::{Style, Weight};
// use platform::FontSystem as _;
#[cfg(test)]
mod tests {
use crate::{font, px, FontRun, MacTextSystem, PlatformTextSystem};
// #[crate::test(self, retries = 5)]
// fn test_layout_str(_: &mut AppContext) {
// // This is failing intermittently on CI and we don't have time to figure it out
// let fonts = FontSystem::new();
// let menlo = fonts.load_family("Menlo", &Default::default()).unwrap();
// let menlo_regular = RunStyle {
// font_id: fonts.select_font(&menlo, &Properties::new()).unwrap(),
// color: Default::default(),
// underline: Default::default(),
// };
// let menlo_italic = RunStyle {
// font_id: fonts
// .select_font(&menlo, Properties::new().style(Style::Italic))
// .unwrap(),
// color: Default::default(),
// underline: Default::default(),
// };
// let menlo_bold = RunStyle {
// font_id: fonts
// .select_font(&menlo, Properties::new().weight(Weight::BOLD))
// .unwrap(),
// color: Default::default(),
// underline: Default::default(),
// };
// assert_ne!(menlo_regular, menlo_italic);
// assert_ne!(menlo_regular, menlo_bold);
// assert_ne!(menlo_italic, menlo_bold);
#[test]
fn test_wrap_line() {
let fonts = MacTextSystem::new();
let font_id = fonts.font_id(&font("Helvetica")).unwrap();
// let line = fonts.layout_line(
// "hello world",
// 16.0,
// &[(2, menlo_bold), (4, menlo_italic), (5, menlo_regular)],
// );
// assert_eq!(line.runs.len(), 3);
// assert_eq!(line.runs[0].font_id, menlo_bold.font_id);
// assert_eq!(line.runs[0].glyphs.len(), 2);
// assert_eq!(line.runs[1].font_id, menlo_italic.font_id);
// assert_eq!(line.runs[1].glyphs.len(), 4);
// assert_eq!(line.runs[2].font_id, menlo_regular.font_id);
// assert_eq!(line.runs[2].glyphs.len(), 5);
// }
let line = "one two three four five\n";
let wrap_boundaries = fonts.wrap_line(line, font_id, px(16.), px(64.0));
assert_eq!(wrap_boundaries, &["one two ".len(), "one two three ".len()]);
// #[test]
// fn test_glyph_offsets() -> crate::Result<()> {
// let fonts = FontSystem::new();
// let zapfino = fonts.load_family("Zapfino", &Default::default())?;
// let zapfino_regular = RunStyle {
// font_id: fonts.select_font(&zapfino, &Properties::new())?,
// color: Default::default(),
// underline: Default::default(),
// };
// let menlo = fonts.load_family("Menlo", &Default::default())?;
// let menlo_regular = RunStyle {
// font_id: fonts.select_font(&menlo, &Properties::new())?,
// color: Default::default(),
// underline: Default::default(),
// };
let line = "aaa ααα ✋✋✋ 🎉🎉🎉\n";
let wrap_boundaries = fonts.wrap_line(line, font_id, px(16.), px(64.0));
assert_eq!(
wrap_boundaries,
&["aaa ααα ".len(), "aaa ααα ✋✋✋ ".len(),]
);
}
// let text = "This is, m𐍈re 𐍈r less, Zapfino!𐍈";
// let line = fonts.layout_line(
// text,
// 16.0,
// &[
// (9, zapfino_regular),
// (13, menlo_regular),
// (text.len() - 22, zapfino_regular),
// ],
// );
// assert_eq!(
// line.runs
// .iter()
// .flat_map(|r| r.glyphs.iter())
// .map(|g| g.index)
// .collect::<Vec<_>>(),
// vec![0, 2, 4, 5, 7, 8, 9, 10, 14, 15, 16, 17, 21, 22, 23, 24, 26, 27, 28, 29, 36, 37],
// );
// Ok(())
// }
#[test]
fn test_layout_line_bom_char() {
let fonts = MacTextSystem::new();
let font_id = fonts.font_id(&font("Helvetica")).unwrap();
let line = "\u{feff}";
let mut style = FontRun {
font_id,
len: line.len(),
};
// #[test]
// #[ignore]
// fn test_rasterize_glyph() {
// use std::{fs::File, io::BufWriter, path::Path};
let layout = fonts.layout_line(line, px(16.), &[style]);
assert_eq!(layout.len, line.len());
assert!(layout.runs.is_empty());
// let fonts = FontSystem::new();
// let font_ids = fonts.load_family("Fira Code", &Default::default()).unwrap();
// let font_id = fonts.select_font(&font_ids, &Default::default()).unwrap();
// let glyph_id = fonts.glyph_for_char(font_id, 'G').unwrap();
// const VARIANTS: usize = 1;
// for i in 0..VARIANTS {
// let variant = i as f32 / VARIANTS as f32;
// let (bounds, bytes) = fonts
// .rasterize_glyph(
// font_id,
// 16.0,
// glyph_id,
// vec2f(variant, variant),
// 2.,
// RasterizationOptions::Alpha,
// )
// .unwrap();
// let name = format!("/Users/as-cii/Desktop/twog-{}.png", i);
// let path = Path::new(&name);
// let file = File::create(path).unwrap();
// let w = &mut BufWriter::new(file);
// let mut encoder = png::Encoder::new(w, bounds.width() as u32, bounds.height() as u32);
// encoder.set_color(png::ColorType::Grayscale);
// encoder.set_depth(png::BitDepth::Eight);
// let mut writer = encoder.write_header().unwrap();
// writer.write_image_data(&bytes).unwrap();
// }
// }
// #[test]
// fn test_wrap_line() {
// let fonts = FontSystem::new();
// let font_ids = fonts.load_family("Helvetica", &Default::default()).unwrap();
// let font_id = fonts.select_font(&font_ids, &Default::default()).unwrap();
// let line = "one two three four five\n";
// let wrap_boundaries = fonts.wrap_line(line, font_id, 16., 64.0);
// assert_eq!(wrap_boundaries, &["one two ".len(), "one two three ".len()]);
// let line = "aaa ααα ✋✋✋ 🎉🎉🎉\n";
// let wrap_boundaries = fonts.wrap_line(line, font_id, 16., 64.0);
// assert_eq!(
// wrap_boundaries,
// &["aaa ααα ".len(), "aaa ααα ✋✋✋ ".len(),]
// );
// }
// #[test]
// fn test_layout_line_bom_char() {
// let fonts = FontSystem::new();
// let font_ids = fonts.load_family("Helvetica", &Default::default()).unwrap();
// let style = RunStyle {
// font_id: fonts.select_font(&font_ids, &Default::default()).unwrap(),
// color: Default::default(),
// underline: Default::default(),
// };
// let line = "\u{feff}";
// let layout = fonts.layout_line(line, 16., &[(line.len(), style)]);
// assert_eq!(layout.len, line.len());
// assert!(layout.runs.is_empty());
// let line = "a\u{feff}b";
// let layout = fonts.layout_line(line, 16., &[(line.len(), style)]);
// assert_eq!(layout.len, line.len());
// assert_eq!(layout.runs.len(), 1);
// assert_eq!(layout.runs[0].glyphs.len(), 2);
// assert_eq!(layout.runs[0].glyphs[0].id, 68); // a
// // There's no glyph for \u{feff}
// assert_eq!(layout.runs[0].glyphs[1].id, 69); // b
// }
// }
let line = "a\u{feff}b";
style.len = line.len();
let layout = fonts.layout_line(line, px(16.), &[style]);
assert_eq!(layout.len, line.len());
assert_eq!(layout.runs.len(), 1);
assert_eq!(layout.runs[0].glyphs.len(), 2);
assert_eq!(layout.runs[0].glyphs[0].id, 68u32.into()); // a
// There's no glyph for \u{feff}
assert_eq!(layout.runs[0].glyphs[1].id, 69u32.into()); // b
}
}

View file

@ -268,6 +268,7 @@ unsafe fn build_window_class(name: &'static str, superclass: &Class) -> *const C
sel!(windowShouldClose:),
window_should_close as extern "C" fn(&Object, Sel, id) -> BOOL,
);
decl.add_method(sel!(close), close_window as extern "C" fn(&Object, Sel));
decl.add_method(
@ -683,9 +684,6 @@ impl Drop for MacWindow {
this.executor
.spawn(async move {
unsafe {
// todo!() this panic()s when you click the red close button
// unless should_close returns false.
// (luckliy in zed it always returns false)
window.close();
}
})
@ -1104,37 +1102,7 @@ extern "C" fn handle_key_event(this: &Object, native_event: id, key_equivalent:
.flatten()
.is_some();
if !is_composing {
// if the IME has changed the key, we'll first emit an event with the character
// generated by the IME system; then fallback to the keystroke if that is not
// handled.
// cases that we have working:
// - " on a brazillian layout by typing <quote><space>
// - ctrl-` on a brazillian layout by typing <ctrl-`>
// - $ on a czech QWERTY layout by typing <alt-4>
// - 4 on a czech QWERTY layout by typing <shift-4>
// - ctrl-4 on a czech QWERTY layout by typing <ctrl-alt-4> (or <ctrl-shift-4>)
if ime_text.is_some() && ime_text.as_ref() != Some(&event.keystroke.key) {
let event_with_ime_text = KeyDownEvent {
is_held: false,
keystroke: Keystroke {
// we match ctrl because some use-cases need it.
// we don't match alt because it's often used to generate the optional character
// we don't match shift because we're not here with letters (usually)
// we don't match cmd/fn because they don't seem to use IME
modifiers: Default::default(),
key: ime_text.clone().unwrap(),
ime_key: None, // todo!("handle IME key")
},
};
handled = callback(InputEvent::KeyDown(event_with_ime_text));
}
if !handled {
// empty key happens when you type a deadkey in input composition.
// (e.g. on a brazillian keyboard typing quote is a deadkey)
if !event.keystroke.key.is_empty() {
handled = callback(InputEvent::KeyDown(event));
}
}
handled = callback(InputEvent::KeyDown(event));
}
if !handled {
@ -1574,6 +1542,9 @@ extern "C" fn insert_text(this: &Object, _: Sel, text: id, replacement_range: NS
replacement_range,
text: text.to_string(),
});
if text.to_string().to_ascii_lowercase() != pending_key_down.0.keystroke.key {
pending_key_down.0.keystroke.ime_key = Some(text.to_string());
}
window_state.lock().pending_key_down = Some(pending_key_down);
}
}