freya_code_editor/
metrics.rs

1use freya_core::prelude::consume_root_context;
2use freya_engine::prelude::*;
3use ropey::Rope;
4use tree_sitter::InputEdit;
5
6use crate::{
7    editor_theme::SyntaxTheme,
8    languages::LanguageId,
9    syntax::*,
10};
11
12pub struct EditorMetrics {
13    pub(crate) syntax_blocks: SyntaxBlocks,
14    pub(crate) longest_width: f32,
15    pub(crate) highlighter: SyntaxHighlighter,
16}
17
18impl Default for EditorMetrics {
19    fn default() -> Self {
20        Self::new()
21    }
22}
23
24impl EditorMetrics {
25    pub fn new() -> Self {
26        Self {
27            syntax_blocks: SyntaxBlocks::default(),
28            longest_width: 0.0,
29            highlighter: SyntaxHighlighter::new(),
30        }
31    }
32
33    pub fn measure_longest_line(&mut self, font_size: f32, rope: &Rope) {
34        // We assume the font used is monospaced.
35
36        // Calculate character width by measuring a reference character
37        let font_collection = consume_root_context::<FontCollection>();
38        let mut paragraph_style = ParagraphStyle::default();
39        let mut text_style = TextStyle::default();
40        text_style.set_font_size(font_size);
41        text_style.set_font_families(&["Jetbrains Mono"]);
42        paragraph_style.set_text_style(&text_style);
43        let mut paragraph_builder = ParagraphBuilder::new(&paragraph_style, font_collection);
44
45        // Measure a single character to get the monospace character width
46        paragraph_builder.add_text("W");
47        let mut paragraph = paragraph_builder.build();
48        paragraph.layout(f32::MAX);
49        let char_width = paragraph.longest_line();
50
51        // Find the line with the maximum character count
52        let max_chars = rope.lines().map(|line| line.len_chars()).max().unwrap_or(0);
53
54        self.longest_width = max_chars as f32 * char_width;
55    }
56
57    pub fn run_parser(
58        &mut self,
59        rope: &Rope,
60        language_id: LanguageId,
61        edit: Option<InputEdit>,
62        theme: &SyntaxTheme,
63    ) {
64        self.highlighter.set_language(language_id, theme);
65        self.highlighter
66            .parse(rope, &mut self.syntax_blocks, edit, theme);
67    }
68}