Repository: lapce/lapce
File: lapce-ui/src/editor/view.rs (Rust)

Code before:
            EnsureVisiblePosition::TopOfWindow => {
                // Cursor line will be at the top edge, thus center of the view
                // is half height down.
                let h = height as usize;
                let h = if h > margin { h - margin } else { margin };
                Point::new(cursor.x, cursor.y + h as f64)
            },
            EnsureVisiblePosition::BottomOfWindow => {
                // Cursor line will be at the bottom edge, thus center of the
                // view is half height up.
                let h = height as usize;
                let h = if h > margin { h - margin } else { margin };
                let y = cursor.y as usize;
                let y = if h > y { y } else { y - h };
                Point::new(cursor.x, y as f64)
            }
        };
        let rect = Rect::ZERO.with_origin(center).inflate(width, height);

        let editor_size = *data.editor.size.borrow();
        let size = LapceEditor::get_size(data, ctx.text(), editor_size, panels, env);
        let scroll = self.editor.widget_mut().editor.widget_mut().inner_mut();
        scroll.set_child_size(size);
        if scroll.scroll_to_visible(rect, env) {
            ctx.submit_command(Command::new(
                LAPCE_UI_COMMAND,
                LapceUICommand::ResetFade,
                Target::Widget(self.editor.widget().scroll_id),
            ));
        }
    }

    fn ensure_cursor_visible(
        &mut self,
        ctx: &mut EventCtx,
        data: &LapceEditorBufferData,
        panels: &im::HashMap<PanelPosition, Arc<PanelData>>,
        position: Option<&EnsureVisiblePosition>,
        env: &Env,
    ) {
        let line_height = data.config.editor.line_height as f64;
        let editor_size = *data.editor.size.borrow();
        let size = LapceEditor::get_size(data, ctx.text(), editor_size, panels, env);

        let rect = Self::cursor_region(data, ctx.text());
        let scroll_id = self.editor.widget().scroll_id;
        let scroll = self.editor.widget_mut().editor.widget_mut().inner_mut();
        scroll.set_child_size(size);
        let old_scroll_offset = scroll.offset();
        if scroll.scroll_to_visible(rect, env) {
            ctx.submit_command(Command::new(

Review comment (suggestion):
This pattern is repeated often enough to deserve its own function. ~This is basically `saturating_sub`, right?~ No it's not. Anyway, I also think this code is complicated enough to warrant some tests.

Code after:
        let half_height = (editor_size.height / 2.0).ceil();

        // Find the top edge of the cursor.
        let cursor_top =
            cursor_center.sub((0.0, ((line_height as f64) * 0.5).floor()));

        // Find where the center of the rect to show in the editor view.
        let view_center = match position {
            EnsureVisiblePosition::CenterOfWindow => {
                // Cursor line will be at the center of the view.
                cursor_top
            }
            EnsureVisiblePosition::TopOfWindow => {
                // Cursor line will be at the top edge of the view, thus the
                // view center will be below the current cursor.y by
                // `half_height` minus `margin`.
                let h = (half_height as usize)
                    .saturating_sub(MARGIN_LINES * line_height);
                Point::new(cursor_top.x, cursor_top.y + (h as f64))
                // TODO: When the cursor is near the top of the *buffer*, the
                // view will not move for this command.  We need an ephemeral
                // message, on the status bar for example, to inform the user.
                // This is not an error or warning.
            }
            EnsureVisiblePosition::BottomOfWindow => {
                // Cursor line will be shown at the bottom edge of the window,
                // thus the view center will be above the current cursor.y by
                // `half_height` minus `margin`.
                let h = (half_height as usize)
                    // Plus 1 to compensate for cursor_top.
                    .saturating_sub((MARGIN_LINES + 1) * line_height);
                let y = cursor_top.y as usize;
                let y = if y > h { y - h } else { y };
                Point::new(cursor_top.x, y as f64)
                // TODO: See above for when cursor is near the top of the
                // *buffer*.
            }
        };
        Rect::ZERO
            .with_origin(view_center)
            .inflate(half_width, half_height)
    }

    pub fn ensure_cursor_position(
        &mut self,
        ctx: &mut EventCtx,
        data: &LapceEditorBufferData,
        panels: &im::HashMap<PanelPosition, Arc<PanelData>>,
        position: &EnsureVisiblePosition,
        env: &Env,
    ) {