<commit_before>//! Command processor

use std::cell::RefCell;
use std::fmt;
use std::rc::Rc;
use unicode_segmentation::UnicodeSegmentation;
use unicode_width::UnicodeWidthChar;

use super::{Context, Helper, Result};
use crate::highlight::Highlighter;
use crate::history::Direction;
use crate::keymap::{Anchor, At, CharSearch, Cmd, Movement, RepeatCount, Word};
use crate::keymap::{InputState, Refresher};
use crate::line_buffer::{LineBuffer, WordAction, MAX_LINE};
use crate::tty::{Position, RawReader, Renderer};
use crate::undo::Changeset;
use crate::validate::Validator;

/// Represent the state during line editing.
/// Implement rendering.
pub struct State<'out, 'prompt, H: Helper> {
    pub out: &'out mut dyn Renderer,
    prompt: &'prompt str,  // Prompt to display (rl_prompt)
    prompt_size: Position, // Prompt Unicode/visible width and height
    pub line: LineBuffer,  // Edited line buffer
    pub cursor: Position,  /* Cursor position (relative to the start of the prompt
                            * for `row`) */
    pub old_rows: usize, // Number of rows used so far (from start of prompt to end of input)
    saved_line_for_history: LineBuffer, // Current edited line before history browsing
    byte_buffer: [u8; 4],
    pub changes: Rc<RefCell<Changeset>>, // changes to line, for undo/redo
    pub helper: Option<&'out H>,
    pub ctx: Context<'out>,   // Give access to history for `hinter`
    pub hint: Option<String>, // last hint displayed
    highlight_char: bool,     // `true` if a char has been highlighted
}

enum Info<'m> {
    NoHint,
    Hint,
    Msg(Option<&'m str>),
}

impl<'out, 'prompt, H: Helper> State<'out, 'prompt, H> {
    pub fn new(
        out: &'out mut dyn Renderer,
        prompt: &'prompt str,
        helper: Option<&'out H>,
        ctx: Context<'out>,
    ) -> State<'out, 'prompt, H> {
        let capacity = MAX_LINE;
        let prompt_size = out.calculate_position(prompt, Position::default());
        State {
            out,
            prompt,
            prompt_size,
            line: LineBuffer::with_capacity(capacity),
            cursor: prompt_size,
            old_rows: 0,
            saved_line_for_history: LineBuffer::with_capacity(capacity),
            byte_buffer: [0; 4],
            changes: Rc::new(RefCell::new(Changeset::new())),
            helper,
            ctx,
            hint: None,
            highlight_char: false,
        }
    }

    pub fn highlighter(&self) -> Option<&dyn Highlighter> {
        if self.out.colors_enabled() {
            self.helper.map(|h| h as &dyn Highlighter)
        } else {
            None
        }
    }

    pub fn next_cmd<R: RawReader>(
        &mut self,
        input_state: &mut InputState,
        rdr: &mut R,
        single_esc_abort: bool,
    ) -> Result<Cmd> {
        loop {
            let rc = input_state.next_cmd(rdr, self, single_esc_abort);
            if rc.is_err() && self.out.sigwinch() {
                self.out.update_size();
                self.refresh_line()?;
                continue;
            }
            if let Ok(Cmd::Replace(_, _)) = rc {
                self.changes.borrow_mut().begin();
            }
            return rc;<commit_msg>Change AcceptLine to SelfInsert if the line doesn't validate<commit_after>//! Command processor

use std::cell::RefCell;
use std::fmt;
use std::rc::Rc;
use unicode_segmentation::UnicodeSegmentation;
use unicode_width::UnicodeWidthChar;

use super::{Context, Helper, Result};
use crate::highlight::Highlighter;
use crate::history::Direction;
use crate::keymap::{Anchor, At, CharSearch, Cmd, Movement, RepeatCount, Word};
use crate::keymap::{InputState, Refresher};
use crate::line_buffer::{LineBuffer, WordAction, MAX_LINE};
use crate::tty::{Position, RawReader, Renderer};
use crate::undo::Changeset;

/// Represent the state during line editing.
/// Implement rendering.
pub struct State<'out, 'prompt, H: Helper> {
    pub out: &'out mut dyn Renderer,
    prompt: &'prompt str,  // Prompt to display (rl_prompt)
    prompt_size: Position, // Prompt Unicode/visible width and height
    pub line: LineBuffer,  // Edited line buffer
    pub cursor: Position,  /* Cursor position (relative to the start of the prompt
                            * for `row`) */
    pub old_rows: usize, // Number of rows used so far (from start of prompt to end of input)
    saved_line_for_history: LineBuffer, // Current edited line before history browsing
    byte_buffer: [u8; 4],
    pub changes: Rc<RefCell<Changeset>>, // changes to line, for undo/redo
    pub helper: Option<&'out H>,
    pub ctx: Context<'out>,   // Give access to history for `hinter`
    pub hint: Option<String>, // last hint displayed
    highlight_char: bool,     // `true` if a char has been highlighted
}

enum Info<'m> {
    NoHint,
    Hint,
    Msg(Option<&'m str>),
}

impl<'out, 'prompt, H: Helper> State<'out, 'prompt, H> {
    pub fn new(
        out: &'out mut dyn Renderer,
        prompt: &'prompt str,
        helper: Option<&'out H>,
        ctx: Context<'out>,
    ) -> State<'out, 'prompt, H> {
        let capacity = MAX_LINE;
        let prompt_size = out.calculate_position(prompt, Position::default());
        State {
            out,
            prompt,
            prompt_size,
            line: LineBuffer::with_capacity(capacity),
            cursor: prompt_size,
            old_rows: 0,
            saved_line_for_history: LineBuffer::with_capacity(capacity),
            byte_buffer: [0; 4],
            changes: Rc::new(RefCell::new(Changeset::new())),
            helper,
            ctx,
            hint: None,
            highlight_char: false,
        }
    }

    pub fn highlighter(&self) -> Option<&dyn Highlighter> {
        if self.out.colors_enabled() {
            self.helper.map(|h| h as &dyn Highlighter)
        } else {
            None
        }
    }

    pub fn next_cmd<R: RawReader>(
        &mut self,
        input_state: &mut InputState,
        rdr: &mut R,
        single_esc_abort: bool,
    ) -> Result<Cmd> {
        loop {
            let rc = input_state.next_cmd(rdr, self, single_esc_abort);
            if rc.is_err() && self.out.sigwinch() {
                self.out.update_size();
                self.refresh_line()?;
                continue;
            }
            if let Ok(Cmd::Replace(_, _)) = rc {
                self.changes.borrow_mut().begin();
            }
            if let Some(validator) = self.helper {
                if let Ok(Cmd::AcceptLine) = rc {
                    if !validator.is_valid(self.line.as_str()) {
                        return Ok(Cmd::SelfInsert(1, '\n'));
                    }
                }
            }
            return rc;
{'fraction_non_alphanumeric': 0.12451593684837653, 'fraction_numerical': 0.0016383675901102174, 'mean_word_length': 2.280410356619443, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1112866', 'n_tokens_mistral': 2034, 'n_tokens_neox': 2010, 'n_words': 562}