Repository: alacritty/alacritty
File: alacritty/src/display.rs (Rust)

Code before:
        self.renderer.with_loader(|mut api| {
            let _ = cache.update_font_size(font, size_info.dpr, &mut api);
        });

        // Update cell size
        let (cell_width, cell_height) = compute_cell_size(config, &self.glyph_cache.font_metrics());
        size_info.cell_width = cell_width;
        size_info.cell_height = cell_height;
    }

    /// Process update events
    pub fn handle_update<T>(
        &mut self,
        terminal: &mut Term<T>,
        pty_resize_handle: &mut dyn OnResize,
        message_buffer: &MessageBuffer,
        config: &Config,
        update_pending: DisplayUpdate,
    ) {
        // Update font size and cell dimensions
        if update_pending.font.is_some() || update_pending.cursor.is_some() {
            if let Some(font) = update_pending.font {
                self.update_glyph_cache(config, font);
            } else if update_pending.cursor.is_some() {
                self.update_glyph_cache(config, config.font.clone());
            }
        }

        let cell_width = self.size_info.cell_width;
        let cell_height = self.size_info.cell_height;

        // Recalculate padding
        let mut padding_x = f32::from(config.window.padding.x) * self.size_info.dpr as f32;
        let mut padding_y = f32::from(config.window.padding.y) * self.size_info.dpr as f32;

        // Update the window dimensions
        if let Some(size) = update_pending.dimensions {
            // Ensure we have at least one column and row
            self.size_info.width = (size.width as f32).max(cell_width + 2. * padding_x);
            self.size_info.height = (size.height as f32).max(cell_height + 2. * padding_y);
        }

        // Distribute excess padding equally on all sides
        if config.window.dynamic_padding {
            padding_x = dynamic_padding(padding_x, self.size_info.width, cell_width);
            padding_y = dynamic_padding(padding_y, self.size_info.height, cell_height);
        }

        self.size_info.padding_x = padding_x.floor() as f32;
        self.size_info.padding_y = padding_y.floor() as f32;


Review comment (performance):
This is basically the only thing that prevents me from just saying this PR is good to go except for a few style issues.

What we're doing here just doesn't seem to align with what the actual intent is.

What we want to do is remove the cursor from the font cache, so that it is reloaded with the new metrics. However what we actually do is reload the font, which coincidentally clears the cache and with it the cursor.

As far as I can see there are two solutions to this, either we make it possible to just do what we want (clear the cache), or we make sure that the cache doesn't need to be cleared, but a different glyph is loaded automatically.

If we clear the cache is a bit annoying, since it drops all fonts which kinda isn't really what we want, but it would be possible.

Reloading the cursor can be done by just adding its width to the cursor key though, which will automatically make sure a new cursor is loaded when it changes, however the old glyph will stick around like that and leak. But I think it shouldn't be too big of a deal in this case. The same thing could be achieved by removing the element from the `cursor_cache` manually.

So I think it might be best to just add an API to reload the font-cache in place maybe? If done correctly, we should probably be able to call that method from `update_font_size`, so that `update_font_size` only updates the values and then the reload function does all the heavy lifting. That way we just expose the API in different ways rather than adding a bunch more code.

Code after:
        self.renderer.with_loader(|mut api| {
            let _ = cache.update_font_size(font, size_info.dpr, &mut api);
        });

        // Update cell size
        let (cell_width, cell_height) = compute_cell_size(config, &self.glyph_cache.font_metrics());
        size_info.cell_width = cell_width;
        size_info.cell_height = cell_height;
    }

    /// Clear glyph cache.
    fn clear_glyph_cache(&mut self) {
        let cache = &mut self.glyph_cache;
        self.renderer.with_loader(|mut api| {
            cache.clear_glyph_cache(&mut api);
        });
    }

    /// Process update events.
    pub fn handle_update<T>(
        &mut self,
        terminal: &mut Term<T>,
        pty_resize_handle: &mut dyn OnResize,
        message_buffer: &MessageBuffer,
        config: &Config,
        update_pending: DisplayUpdate,
    ) {
        // Update font size and cell dimensions
        if let Some(font) = update_pending.font {
            self.update_glyph_cache(config, font);
        } else if update_pending.cursor {
            self.clear_glyph_cache();
        }

        let cell_width = self.size_info.cell_width;
        let cell_height = self.size_info.cell_height;

        // Recalculate padding
        let mut padding_x = f32::from(config.window.padding.x) * self.size_info.dpr as f32;
        let mut padding_y = f32::from(config.window.padding.y) * self.size_info.dpr as f32;

        // Update the window dimensions
        if let Some(size) = update_pending.dimensions {
            // Ensure we have at least one column and row
            self.size_info.width = (size.width as f32).max(cell_width + 2. * padding_x);
            self.size_info.height = (size.height as f32).max(cell_height + 2. * padding_y);
        }

        // Distribute excess padding equally on all sides
        if config.window.dynamic_padding {
            padding_x = dynamic_padding(padding_x, self.size_info.width, cell_width);