
The Zed Plex fonts were found to violate the OFL by using the word Plex in the name. Lilex has better ligatures and box-drawing characters than Zed Plex Mono, but Zed Plex Sans should be identical to IBM Plex Sans. Closes #15542 Closes zed-industries/zed-fonts#31 Release Notes: - The "Zed Plex Sans" and "Zed Plex Mono" fonts have been replaced with "IBM Plex Sans" and "Lilex". The old names still work for backward compatibility. Other than fixing line-drawing characters, and improving the ligatures, there should be little visual change as the fonts are all of the same family. - Introduced ".ZedSans" and ".ZedMono" as aliases to allow us to easily change the default fonts in the future. These currently default to "IBM Plex Sans" and "Lilex" respectively.
260 lines
8.2 KiB
Rust
260 lines
8.2 KiB
Rust
pub mod editor_lsp_test_context;
|
|
pub mod editor_test_context;
|
|
|
|
use std::{rc::Rc, sync::LazyLock};
|
|
|
|
pub use crate::rust_analyzer_ext::expand_macro_recursively;
|
|
use crate::{
|
|
DisplayPoint, Editor, EditorMode, FoldPlaceholder, MultiBuffer, SelectionEffects,
|
|
display_map::{
|
|
Block, BlockPlacement, CustomBlockId, DisplayMap, DisplayRow, DisplaySnapshot,
|
|
ToDisplayPoint,
|
|
},
|
|
};
|
|
use collections::HashMap;
|
|
use gpui::{
|
|
AppContext as _, Context, Entity, EntityId, Font, FontFeatures, FontStyle, FontWeight, Pixels,
|
|
VisualTestContext, Window, font, size,
|
|
};
|
|
use multi_buffer::ToPoint;
|
|
use pretty_assertions::assert_eq;
|
|
use project::{Project, project_settings::DiagnosticSeverity};
|
|
use ui::{App, BorrowAppContext, px};
|
|
use util::test::{marked_text_offsets, marked_text_ranges};
|
|
|
|
#[cfg(test)]
|
|
#[ctor::ctor]
|
|
fn init_logger() {
|
|
zlog::init_test();
|
|
}
|
|
|
|
pub fn test_font() -> Font {
|
|
static TEST_FONT: LazyLock<Font> = LazyLock::new(|| {
|
|
#[cfg(not(target_os = "windows"))]
|
|
{
|
|
font("Helvetica")
|
|
}
|
|
|
|
#[cfg(target_os = "windows")]
|
|
{
|
|
font("Courier New")
|
|
}
|
|
});
|
|
|
|
TEST_FONT.clone()
|
|
}
|
|
|
|
// Returns a snapshot from text containing '|' character markers with the markers removed, and DisplayPoints for each one.
|
|
#[track_caller]
|
|
pub fn marked_display_snapshot(
|
|
text: &str,
|
|
cx: &mut gpui::App,
|
|
) -> (DisplaySnapshot, Vec<DisplayPoint>) {
|
|
let (unmarked_text, markers) = marked_text_offsets(text);
|
|
|
|
let font = Font {
|
|
family: ".ZedMono".into(),
|
|
features: FontFeatures::default(),
|
|
fallbacks: None,
|
|
weight: FontWeight::default(),
|
|
style: FontStyle::default(),
|
|
};
|
|
let font_size: Pixels = 14usize.into();
|
|
|
|
let buffer = MultiBuffer::build_simple(&unmarked_text, cx);
|
|
let display_map = cx.new(|cx| {
|
|
DisplayMap::new(
|
|
buffer,
|
|
font,
|
|
font_size,
|
|
None,
|
|
1,
|
|
1,
|
|
FoldPlaceholder::test(),
|
|
DiagnosticSeverity::Warning,
|
|
cx,
|
|
)
|
|
});
|
|
let snapshot = display_map.update(cx, |map, cx| map.snapshot(cx));
|
|
let markers = markers
|
|
.into_iter()
|
|
.map(|offset| offset.to_display_point(&snapshot))
|
|
.collect();
|
|
|
|
(snapshot, markers)
|
|
}
|
|
|
|
#[track_caller]
|
|
pub fn select_ranges(
|
|
editor: &mut Editor,
|
|
marked_text: &str,
|
|
window: &mut Window,
|
|
cx: &mut Context<Editor>,
|
|
) {
|
|
let (unmarked_text, text_ranges) = marked_text_ranges(marked_text, true);
|
|
assert_eq!(editor.text(cx), unmarked_text);
|
|
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
|
|
s.select_ranges(text_ranges)
|
|
});
|
|
}
|
|
|
|
#[track_caller]
|
|
pub fn assert_text_with_selections(
|
|
editor: &mut Editor,
|
|
marked_text: &str,
|
|
cx: &mut Context<Editor>,
|
|
) {
|
|
let (unmarked_text, text_ranges) = marked_text_ranges(marked_text, true);
|
|
assert_eq!(editor.text(cx), unmarked_text, "text doesn't match");
|
|
assert_eq!(
|
|
editor.selections.ranges(cx),
|
|
text_ranges,
|
|
"selections don't match",
|
|
);
|
|
}
|
|
|
|
// RA thinks this is dead code even though it is used in a whole lot of tests
|
|
#[allow(dead_code)]
|
|
#[cfg(any(test, feature = "test-support"))]
|
|
pub(crate) fn build_editor(
|
|
buffer: Entity<MultiBuffer>,
|
|
window: &mut Window,
|
|
cx: &mut Context<Editor>,
|
|
) -> Editor {
|
|
Editor::new(EditorMode::full(), buffer, None, window, cx)
|
|
}
|
|
|
|
pub(crate) fn build_editor_with_project(
|
|
project: Entity<Project>,
|
|
buffer: Entity<MultiBuffer>,
|
|
window: &mut Window,
|
|
cx: &mut Context<Editor>,
|
|
) -> Editor {
|
|
Editor::new(EditorMode::full(), buffer, Some(project), window, cx)
|
|
}
|
|
|
|
#[derive(Default)]
|
|
struct TestBlockContent(
|
|
HashMap<(EntityId, CustomBlockId), Rc<dyn Fn(&mut VisualTestContext) -> String>>,
|
|
);
|
|
|
|
impl gpui::Global for TestBlockContent {}
|
|
|
|
pub fn set_block_content_for_tests(
|
|
editor: &Entity<Editor>,
|
|
id: CustomBlockId,
|
|
cx: &mut App,
|
|
f: impl Fn(&mut VisualTestContext) -> String + 'static,
|
|
) {
|
|
cx.update_default_global::<TestBlockContent, _>(|bc, _| {
|
|
bc.0.insert((editor.entity_id(), id), Rc::new(f))
|
|
});
|
|
}
|
|
|
|
pub fn block_content_for_tests(
|
|
editor: &Entity<Editor>,
|
|
id: CustomBlockId,
|
|
cx: &mut VisualTestContext,
|
|
) -> Option<String> {
|
|
let f = cx.update(|_, cx| {
|
|
cx.default_global::<TestBlockContent>()
|
|
.0
|
|
.get(&(editor.entity_id(), id))
|
|
.cloned()
|
|
})?;
|
|
Some(f(cx))
|
|
}
|
|
|
|
pub fn editor_content_with_blocks(editor: &Entity<Editor>, cx: &mut VisualTestContext) -> String {
|
|
cx.draw(
|
|
gpui::Point::default(),
|
|
size(px(3000.0), px(3000.0)),
|
|
|_, _| editor.clone(),
|
|
);
|
|
let (snapshot, mut lines, blocks) = editor.update_in(cx, |editor, window, cx| {
|
|
let snapshot = editor.snapshot(window, cx);
|
|
let text = editor.display_text(cx);
|
|
let lines = text.lines().map(|s| s.to_string()).collect::<Vec<String>>();
|
|
let blocks = snapshot
|
|
.blocks_in_range(DisplayRow(0)..snapshot.max_point().row())
|
|
.map(|(row, block)| (row, block.clone()))
|
|
.collect::<Vec<_>>();
|
|
(snapshot, lines, blocks)
|
|
});
|
|
for (row, block) in blocks {
|
|
match block {
|
|
Block::Custom(custom_block) => {
|
|
if let BlockPlacement::Near(x) = &custom_block.placement {
|
|
if snapshot.intersects_fold(x.to_point(&snapshot.buffer_snapshot)) {
|
|
continue;
|
|
}
|
|
};
|
|
let content = block_content_for_tests(&editor, custom_block.id, cx)
|
|
.expect("block content not found");
|
|
// 2: "related info 1 for diagnostic 0"
|
|
if let Some(height) = custom_block.height {
|
|
if height == 0 {
|
|
lines[row.0 as usize - 1].push_str(" § ");
|
|
lines[row.0 as usize - 1].push_str(&content);
|
|
} else {
|
|
let block_lines = content.lines().collect::<Vec<_>>();
|
|
assert_eq!(block_lines.len(), height as usize);
|
|
lines[row.0 as usize].push_str("§ ");
|
|
lines[row.0 as usize].push_str(block_lines[0].trim_end());
|
|
for i in 1..height as usize {
|
|
if row.0 as usize + i >= lines.len() {
|
|
lines.push("".to_string());
|
|
};
|
|
lines[row.0 as usize + i].push_str("§ ");
|
|
lines[row.0 as usize + i].push_str(block_lines[i].trim_end());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Block::FoldedBuffer {
|
|
first_excerpt,
|
|
height,
|
|
} => {
|
|
lines[row.0 as usize].push_str(&cx.update(|_, cx| {
|
|
format!(
|
|
"§ {}",
|
|
first_excerpt
|
|
.buffer
|
|
.file()
|
|
.unwrap()
|
|
.file_name(cx)
|
|
.to_string_lossy()
|
|
)
|
|
}));
|
|
for row in row.0 + 1..row.0 + height {
|
|
lines[row as usize].push_str("§ -----");
|
|
}
|
|
}
|
|
Block::ExcerptBoundary {
|
|
excerpt,
|
|
height,
|
|
starts_new_buffer,
|
|
} => {
|
|
if starts_new_buffer {
|
|
lines[row.0 as usize].push_str(&cx.update(|_, cx| {
|
|
format!(
|
|
"§ {}",
|
|
excerpt
|
|
.buffer
|
|
.file()
|
|
.unwrap()
|
|
.file_name(cx)
|
|
.to_string_lossy()
|
|
)
|
|
}));
|
|
} else {
|
|
lines[row.0 as usize].push_str("§ -----")
|
|
}
|
|
for row in row.0 + 1..row.0 + height {
|
|
lines[row as usize].push_str("§ -----");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
lines.join("\n")
|
|
}
|