Skip to main content

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