use std::fmt;
use std::io;
use std::vec::Vec;
use nu_ansi_term::Color::{Fixed, Green, Red, Yellow};
use nu_ansi_term::Style;
use bytesize::ByteSize;
use syntect::easy::HighlightLines;
use syntect::highlighting::Color;
use syntect::highlighting::FontStyle;
use syntect::highlighting::Theme;
use syntect::parsing::SyntaxSet;
use content_inspector::ContentType;
use encoding_rs::{UTF_16BE, UTF_16LE};
use unicode_width::UnicodeWidthChar;
use crate::assets::{HighlightingAssets, SyntaxReferenceInSet};
use crate::config::Config;
#[cfg(feature = "git")]
use crate::decorations::LineChangesDecoration;
use crate::decorations::{Decoration, GridBorderDecoration, LineNumberDecoration};
#[cfg(feature = "git")]
use crate::diff::LineChanges;
use crate::error::*;
use crate::input::OpenedInput;
use crate::line_range::RangeCheckResult;
use crate::preprocessor::{expand_tabs, replace_nonprintable};
use crate::style::StyleComponent;
use crate::terminal::{as_terminal_escaped, to_ansi_color};
use crate::vscreen::{AnsiStyle, EscapeSequence, EscapeSequenceIterator};
use crate::wrapping::WrappingMode;
const ANSI_UNDERLINE_ENABLE: EscapeSequence = EscapeSequence::CSI {
raw_sequence: "\x1B[4m",
parameters: "4",
intermediates: "",
final_byte: "m",
};
const ANSI_UNDERLINE_DISABLE: EscapeSequence = EscapeSequence::CSI {
raw_sequence: "\x1B[24m",
parameters: "24",
intermediates: "",
final_byte: "m",
};
const EMPTY_SYNTECT_STYLE: syntect::highlighting::Style = syntect::highlighting::Style {
foreground: Color {
r: 127,
g: 127,
b: 127,
a: 255,
},
background: Color {
r: 127,
g: 127,
b: 127,
a: 255,
},
font_style: FontStyle::empty(),
};
pub enum OutputHandle<'a> {
IoWrite(&'a mut dyn io::Write),
FmtWrite(&'a mut dyn fmt::Write),
}
impl<'a> OutputHandle<'a> {
fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result<()> {
match self {
Self::IoWrite(handle) => handle.write_fmt(args).map_err(Into::into),
Self::FmtWrite(handle) => handle.write_fmt(args).map_err(Into::into),
}
}
}
pub(crate) trait Printer {
fn print_header(
&mut self,
handle: &mut OutputHandle,
input: &OpenedInput,
add_header_padding: bool,
) -> Result<()>;
fn print_footer(&mut self, handle: &mut OutputHandle, input: &OpenedInput) -> Result<()>;
fn print_snip(&mut self, handle: &mut OutputHandle) -> Result<()>;
fn print_line(
&mut self,
out_of_range: bool,
handle: &mut OutputHandle,
line_number: usize,
line_buffer: &[u8],
) -> Result<()>;
}
pub struct SimplePrinter<'a> {
config: &'a Config<'a>,
consecutive_empty_lines: usize,
}
impl<'a> SimplePrinter<'a> {
pub fn new(config: &'a Config) -> Self {
SimplePrinter {
config,
consecutive_empty_lines: 0,
}
}
}
impl<'a> Printer for SimplePrinter<'a> {
fn print_header(
&mut self,
_handle: &mut OutputHandle,
_input: &OpenedInput,
_add_header_padding: bool,
) -> Result<()> {
Ok(())
}
fn print_footer(&mut self, _handle: &mut OutputHandle, _input: &OpenedInput) -> Result<()> {
Ok(())
}
fn print_snip(&mut self, _handle: &mut OutputHandle) -> Result<()> {
Ok(())
}
fn print_line(
&mut self,
out_of_range: bool,
handle: &mut OutputHandle,
_line_number: usize,
line_buffer: &[u8],
) -> Result<()> {
// Skip squeezed lines.
if let Some(squeeze_limit) = self.config.squeeze_lines {
if String::from_utf8_lossy(line_buffer)
.trim_end_matches(|c| c == '\r' || c == '\n')
.is_empty()
{
self.consecutive_empty_lines += 1;
if self.consecutive_empty_lines > squeeze_limit {
return Ok(());
}
} else {
self.consecutive_empty_lines = 0;
}
}
if !out_of_range {
if self.config.show_nonprintable {
let line = replace_nonprintable(
line_buffer,
self.config.tab_width,
self.config.nonprintable_notation,
);