Repository: microsoft/edit
File: src/bin/edit/draw_editor.rs (Rust)

Code before:
                action = Action::Discard;
            }
        }
        ctx.table_end();
    }
    if ctx.modal_end() {
        action = Action::Cancel;
    }

    match action {
        Action::None => return,
        Action::Save => state.wants_save = true,
        Action::Discard => state.documents.remove_active(),
        Action::Cancel => state.wants_exit = false,
    }

    state.wants_close = false;
    ctx.toss_focus_up();
}


fn validate_goto_point(line: &str, current: Point) -> Result<Point, ()> {
    let parts: Vec<_> = line.splitn(2, ':').collect();
    Ok(match parts.len() {
        1 => {
            if let Ok(line) = parts[0].parse::<i32>() {
                Point { y: line - 1, x: current.x }
            } else {
                return Err(());
            }
        }
        2 => {
            if let Ok(line) = parts[0].parse::<i32>() {
                if let Ok(column) = parts[1].parse::<i32>() {
                    Point { y: line - 1, x: column }
                } else {
                    return Err(());
                }
            } else {
                return Err(());
            }
        }
        _ => unreachable!()
    })
}


pub fn draw_goto_menu(ctx: &mut Context, state: &mut State) {
    ctx.modal_begin("goto", loc(LocId::FileGoto));
    {
        if ctx.editline("goto-line", &mut state.goto_target) {

Review comment (suggestion):
FYI: this allows negative numbers, e.g. `-123`, `1:-32`.

This seems to be handled well by the editor (looks like it just goes to the nearest valid spot), but it might be a better experience to mark negative numbers as invalid

Code after:
                action = Action::Save;
            } else if ctx.consume_shortcut(vk::N) {
                action = Action::Discard;
            }
        }
        ctx.table_end();
    }
    if ctx.modal_end() {
        action = Action::Cancel;
    }

    match action {
        Action::None => return,
        Action::Save => state.wants_save = true,
        Action::Discard => state.documents.remove_active(),
        Action::Cancel => state.wants_exit = false,
    }

    state.wants_close = false;
    ctx.toss_focus_up();
}

pub fn draw_goto_menu(ctx: &mut Context, state: &mut State) {
    let Some(doc) = state.documents.active_mut() else {
        // Goto does not make sense if there is no active document
        state.wants_goto = false;
        return;
    };
    let mut done = false;

    ctx.modal_begin("goto", loc(LocId::FileGoto));
    {
        if ctx.editline("goto-line", &mut state.goto_target) {
            state.goto_invalid = false;
        }
        if state.goto_invalid {
            ctx.attr_background_rgba(ctx.indexed(IndexedColor::Red));
            ctx.attr_foreground_rgba(ctx.indexed(IndexedColor::BrightWhite));
        }

        ctx.attr_intrinsic_size(Size { width: 24, height: 1 });
        ctx.steal_focus();

        if ctx.consume_shortcut(vk::RETURN) {
            let mut buf = doc.buffer.borrow_mut();
            match validate_goto_point(&state.goto_target) {
                Ok(point) => {
                    buf.cursor_move_to_logical(point);
                    done = true;
                }
                Err(_) => state.goto_invalid = true,