nexedit 0.2.2

A vim-like text editor, with simple shortcuts.
Documentation
use crate::errors::*;
use crate::models::application::modes::SearchSelectMode;
use crate::presenters::current_buffer_status_line_data;
use crate::view::{Colors, CursorType, StatusLineData, Style, View};
use scribe::buffer::Position;
use scribe::Workspace;
use std::cmp;
use std::fmt::Display;
use unicode_segmentation::UnicodeSegmentation;

pub fn display<T: Display>(
    workspace: &mut Workspace,
    mode: &mut dyn SearchSelectMode<T>,
    view: &mut View,
) -> Result<()> {
    let data;
    let padded_message;
    let mut presenter = view.build_presenter()?;
    let mode_config = mode.config().clone();
    let mut padded_content = Vec::new();
    let mut remaining_lines = Vec::new();

    let buffer_status = current_buffer_status_line_data(workspace);

    if let Some(buf) = workspace.current_buffer.as_ref() {
        data = buf.data();
        presenter.print_buffer(buf, &data, &workspace.syntax_set, None, None)?;

        presenter.print_status_line(&[
            StatusLineData {
                content: format!(" {} ", mode),
                style: Style::Default,
                colors: Colors::Inverted,
            },
            buffer_status,
        ]);
    }

    if let Some(message) = mode.message() {
        padded_message = format!("{:width$}", message, width = presenter.width());
        presenter.print(
            &Position { line: 0, offset: 0 },
            Style::Default,
            Colors::Default,
            &padded_message,
        );
    } else {
        for (line, result) in mode.results().enumerate() {
            let (content, colors, style) = if line == mode.selected_index() {
                (format!("> {}", result), Colors::Focused, Style::Bold)
            } else {
                (format!("  {}", result), Colors::Default, Style::Default)
            };

            let trimmed_content: String = content
                .graphemes(true)
                .enumerate()
                .take_while(|(i, _)| i < &presenter.width())
                .map(|(_, g)| g)
                .collect();

            padded_content.push((
                Position { line, offset: 0 },
                style,
                colors,
                format!("{:width$}", trimmed_content, width = presenter.width()),
            ));
        }

        for (position, style, colors, content) in padded_content.iter() {
            presenter.print(position, *style, *colors, content);
        }
    }

    for line in cmp::max(mode.results().len(), 1)..mode_config.max_results {
        remaining_lines.push((
            Position { line, offset: 0 },
            Style::Default,
            Colors::Default,
            format!("{:width$}", ' ', width = presenter.width()),
        ));
    }

    for (position, style, colors, content) in remaining_lines.iter() {
        presenter.print(position, *style, *colors, content);
    }

    let line = mode_config.max_results;
    let colors = if mode.insert_mode() {
        Colors::Insert
    } else {
        Colors::Inverted
    };

    let padded_content = format!("{:width$}", mode.query(), width = presenter.width());

    presenter.print(
        &Position { line, offset: 0 },
        Style::Bold,
        colors,
        &padded_content,
    );

    if mode.insert_mode() {
        presenter.set_cursor(Some(Position {
            line: mode_config.max_results,
            offset: mode.query().graphemes(true).count(),
        }));

        presenter.set_cursor_type(CursorType::BlinkingBar);
    } else {
        presenter.set_cursor(None);
    }

    presenter.present()?;

    Ok(())
}