<commit_before>use std::str;
use std::cmp;
use std::path::Path;
use std::path::PathBuf;
use util::string_with_repeat;
use std::error::Error;
use std::ascii::AsciiExt;
use rustbox::{RustBox};
use rustbox::keyboard::Key;


use super::super::buffer::Buffer;
use super::super::segment::Segment;

use super::common::{Rect, u8_to_hex};
use super::RustBoxEx::{RustBoxEx, Style};
use super::input::Input;
use super::inputline::{InputLine, GotoInputLine, FindInputLine, PathInputLine};
use super::overlay::OverlayText;

#[derive(Debug)]
enum UndoAction {
    Delete(isize, isize),
    Insert(isize, Vec<u8>),
    Write(isize, Vec<u8>),
}

#[derive(Copy,Clone,Debug)]
pub enum HexEditActions {
    Edit(char),
    SwitchView,
    MoveLeft,
    MoveRight,
    MoveUp,
    MoveDown,
    MovePageUp,
    MovePageDown,
    Delete,
    DeleteWithMove,
    CopySelection,
    CutSelection,
    PasteSelection,
    Undo,
    ToggleInsert,
    ToggleSelecion,
    HelpView,
    AskGoto,
    AskFind,
    AskOpen,
    AskSave
}

signalreceiver_decl!{HexEditSignalReceiver(HexEdit)}

pub struct HexEdit {
    buffer: Segment,
    cursor_pos: isize,
    cur_height: isize,
    cur_width: isize,
    nibble_width: isize,
    nibble_size: isize,
    data_size: isize,
    status_log: Vec<String>,
    data_offset: isize,
    nibble_start: isize,
    nibble_active: bool,
    selection_start: Option<isize>,
    insert_mode: bool,
    input: Input,
    undo_stack: Vec<UndoAction>,
    input_entry: Option<Box<InputLine>>,
    overlay: Option<OverlayText>,
    cur_path: Option<PathBuf>,
    clipboard: Option<Vec<u8>>,

    signal_receiver: Option<HexEditSignalReceiver>,
}

impl HexEdit {
    pub fn new() -> HexEdit {
        HexEdit {
            buffer: Segment::new(),
            cursor_pos: 0,
            nibble_size: 0,
            cur_width: 50,
            cur_height: 50,
            nibble_width: 1,
            data_offset: 0,
            nibble_start: 0,
            data_size: 0,
            status_log: vec!("Press C-/ for help".to_string()),
            nibble_active: true,
            selection_start: None,
            insert_mode: false,
            input_entry: None,
            undo_stack: Vec::new(),
            overlay: None,
            cur_path: None,
            clipboard: None,
            input: Input::new(),
            signal_receiver: Some(HexEditSignalReceiver::new()),
        }
    }

    fn reset(&mut self) {
        self.cursor_pos = 0;
        self.data_offset = 0;
        self.nibble_active = true;
        self.selection_start = None;
        self.insert_mode = false;
        self.input_entry = None;
        self.undo_stack = Vec::new();
        self.recalculate();
    }

    pub fn draw_view(&mut self, rb: &RustBox) {
        let nibble_view_start = self.nibble_start;
        let byte_view_start = nibble_view_start + (self.nibble_width / 2) * 3;

        let mut prev_in_selection = false;

        let extra_none: &[Option<&u8>] = &[None];

        let start_iter = (self.data_offset / 2) as usize;
        let stop_iter = cmp::min(start_iter + (self.nibble_size / 2) as usize, self.buffer.len());

        for (byte_i, maybe_byte) in self.buffer.iter_range(start_iter, stop_iter)
        // This is needed for the "fake" last element for insertion mode
            .map(|x| Some(x))
            .chain(extra_none.iter().map(|n| *n))
            .enumerate() {

            let row = byte_i as isize / (self.nibble_width / 2);
            let offset = byte_i as isize % (self.nibble_width / 2);
            let byte_pos = byte_i as isize + self.data_offset / 2;

            if offset == 0 {
                if self.nibble_start == 5 {
                    rb.print_style(0, row as usize, Style::Default, &format!("{:04X}", byte_pos));
                } else {
                    rb.print_style(0, row as usize, Style::Default, &format!("{:04X}:{:04X}", byte_pos >> 16, byte_pos & 0xFFFF));
                }
            }

            let mut hex_str = [' ', ' '];
            let mut byte_str = '.';
            match maybe_byte {
                Some(&byte) => {
                    let (char_0, char_1) = u8_to_hex(byte);
                    hex_str[0] = char_0;
                    hex_str[1] = char_1;
                    let bc =  byte as char;
                    if bc.is_ascii() && bc.is_alphanumeric() {
                        byte_str = bc;
                    }
                }

                // Then this is the last iteration so that insertion past the last byte works
                None => {
                    byte_str = ' ';
                }<commit_msg>Fix the selection being overdraw to the left<commit_after>use std::str;
use std::cmp;
use std::path::Path;
use std::path::PathBuf;
use util::string_with_repeat;
use std::error::Error;
use std::ascii::AsciiExt;
use rustbox::{RustBox};
use rustbox::keyboard::Key;


use super::super::buffer::Buffer;
use super::super::segment::Segment;

use super::common::{Rect, u8_to_hex};
use super::RustBoxEx::{RustBoxEx, Style};
use super::input::Input;
use super::inputline::{InputLine, GotoInputLine, FindInputLine, PathInputLine};
use super::overlay::OverlayText;

#[derive(Debug)]
enum UndoAction {
    Delete(isize, isize),
    Insert(isize, Vec<u8>),
    Write(isize, Vec<u8>),
}

#[derive(Copy,Clone,Debug)]
pub enum HexEditActions {
    Edit(char),
    SwitchView,
    MoveLeft,
    MoveRight,
    MoveUp,
    MoveDown,
    MovePageUp,
    MovePageDown,
    Delete,
    DeleteWithMove,
    CopySelection,
    CutSelection,
    PasteSelection,
    Undo,
    ToggleInsert,
    ToggleSelecion,
    HelpView,
    AskGoto,
    AskFind,
    AskOpen,
    AskSave
}

signalreceiver_decl!{HexEditSignalReceiver(HexEdit)}

pub struct HexEdit {
    buffer: Segment,
    cursor_pos: isize,
    cur_height: isize,
    cur_width: isize,
    nibble_width: isize,
    nibble_size: isize,
    data_size: isize,
    status_log: Vec<String>,
    data_offset: isize,
    nibble_start: isize,
    nibble_active: bool,
    selection_start: Option<isize>,
    insert_mode: bool,
    input: Input,
    undo_stack: Vec<UndoAction>,
    input_entry: Option<Box<InputLine>>,
    overlay: Option<OverlayText>,
    cur_path: Option<PathBuf>,
    clipboard: Option<Vec<u8>>,

    signal_receiver: Option<HexEditSignalReceiver>,
}

impl HexEdit {
    pub fn new() -> HexEdit {
        HexEdit {
            buffer: Segment::new(),
            cursor_pos: 0,
            nibble_size: 0,
            cur_width: 50,
            cur_height: 50,
            nibble_width: 1,
            data_offset: 0,
            nibble_start: 0,
            data_size: 0,
            status_log: vec!("Press C-/ for help".to_string()),
            nibble_active: true,
            selection_start: None,
            insert_mode: false,
            input_entry: None,
            undo_stack: Vec::new(),
            overlay: None,
            cur_path: None,
            clipboard: None,
            input: Input::new(),
            signal_receiver: Some(HexEditSignalReceiver::new()),
        }
    }

    fn reset(&mut self) {
        self.cursor_pos = 0;
        self.data_offset = 0;
        self.nibble_active = true;
        self.selection_start = None;
        self.insert_mode = false;
        self.input_entry = None;
        self.undo_stack = Vec::new();
        self.recalculate();
    }

    pub fn draw_view(&mut self, rb: &RustBox) {
        let nibble_view_start = self.nibble_start;
        let byte_view_start = nibble_view_start + (self.nibble_width / 2) * 3;

        let mut prev_in_selection = false;

        let extra_none: &[Option<&u8>] = &[None];

        let start_iter = (self.data_offset / 2) as usize;
        let stop_iter = cmp::min(start_iter + (self.nibble_size / 2) as usize, self.buffer.len());

        for (byte_i, maybe_byte) in self.buffer.iter_range(start_iter, stop_iter)
        // This is needed for the "fake" last element for insertion mode
            .map(|x| Some(x))
            .chain(extra_none.iter().map(|n| *n))
            .enumerate() {

            let row = byte_i as isize / (self.nibble_width / 2);
            let offset = byte_i as isize % (self.nibble_width / 2);
            let byte_pos = byte_i as isize + self.data_offset / 2;

            if offset == 0 {
                if self.nibble_start == 5 {
                    rb.print_style(0, row as usize, Style::Default, &format!("{:04X}", byte_pos));
                } else {
                    rb.print_style(0, row as usize, Style::Default, &format!("{:04X}:{:04X}", byte_pos >> 16, byte_pos & 0xFFFF));
                }
                prev_in_selection = false;
            }

            let mut hex_str = [' ', ' '];
            let mut byte_str = '.';
            match maybe_byte {
                Some(&byte) => {
                    let (char_0, char_1) = u8_to_hex(byte);
                    hex_str[0] = char_0;
                    hex_str[1] = char_1;
                    let bc =  byte as char;
                    if bc.is_ascii() && bc.is_alphanumeric() {
                        byte_str = bc;
                    }
                }

                // Then this is the last iteration so that insertion past the last byte works
                None => {
                    byte_str = ' ';
                }
{'fraction_non_alphanumeric': 0.11849462365591398, 'fraction_numerical': 0.00946236559139785, 'mean_word_length': 2.034584013050571, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 39, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '454537', 'n_tokens_mistral': 3106, 'n_tokens_neox': 2991, 'n_words': 669}