use std::io::{stdout, IsTerminal, Write};
use prettytable::{format, Cell, Row, Table};
use termcolor::Color::*;
use termcolor::{Buffer, BufferWriter, WriteColor};
use crate::Opt;
macro_rules! color_bold {
($fmt:ident, $color:ident, $str:expr) => {{
$fmt.set_color(
::termcolor::ColorSpec::new()
.set_bold(true)
.set_fg(Some($color)),
)?;
write!($fmt, "{}", $str)?;
$fmt.reset()
}};
}
macro_rules! color {
($fmt:ident, $color:ident, $str:expr) => {{
$fmt.set_color(::termcolor::ColorSpec::new().set_fg(Some($color)))?;
write!($fmt, "{}", $str)?;
$fmt.reset()
}};
}
macro_rules! color_dim {
($fmt:ident, $color:ident, $str:expr) => {{
$fmt.set_color(
::termcolor::ColorSpec::new()
.set_fg(Some($color))
.set_intense(false),
)?;
write!($fmt, "{}", $str)?;
$fmt.reset()
}};
}
fn union_demangle(s: &str) -> String {
rustc_demangle::try_demangle(s)
.ok()
.map(|v| v.to_string())
.unwrap_or_else(|| {
match cpp_demangle::Symbol::new(s)
.ok()
.and_then(|s| s.demangle().ok())
{
Some(sym) => sym,
None => s.to_owned(),
}
})
}
pub fn new_table(title: Row) -> Table {
let sep = format::LineSeparator::new('-', '|', ' ', ' ');
let format = format::FormatBuilder::new()
.column_separator(' ')
.borders(' ')
.separators(&[], sep)
.padding(1, 1)
.build();
let mut phdr_table = Table::new();
phdr_table.set_titles(title);
phdr_table.set_format(format);
phdr_table
}
pub fn truncate(opt: &Opt, string: &str) -> String {
if string.is_empty() {
return string.to_owned();
}
let mut s = if opt.demangle {
union_demangle(string)
} else {
string.into()
};
if s.len() > opt.truncate {
s.truncate(opt.truncate);
s += "…";
}
s
}
pub fn string_cell(opt: &Opt, string: &str) -> Cell {
if string.is_empty() {
Cell::new("")
} else {
let s = truncate(opt, string);
Cell::new(&s).style_spec("FYb")
}
}
pub fn str_cell(s: &str) -> Cell {
if s.is_empty() {
Cell::new("")
} else {
Cell::new(s).style_spec("FYb")
}
}
fn even_odd_cell(i: usize, cell: Cell) -> Cell {
if i % 2 == 0 {
cell.style_spec("FdBw")
} else {
cell.style_spec("FwBd")
}
}
pub fn idx_cell(i: usize) -> Cell {
let cell = Cell::new(&format!("{}", i));
even_odd_cell(i, cell)
}
pub fn name_even_odd_cell(opt: &Opt, i: usize, name: &str) -> Cell {
even_odd_cell(i, string_cell(opt, name))
}
pub fn addr_cell(addr: u64) -> Cell {
Cell::new(&format!("{:>16x} ", addr)).style_spec("Frr")
}
pub fn offsetx_cell(offset: u64) -> Cell {
Cell::new(&format!("{:#x} ", offset)).style_spec("Fy")
}
pub fn addrx_cell(addr: u64) -> Cell {
Cell::new(&format!("{:#x} ", addr)).style_spec("Fr")
}
pub fn memx_cell(maddr: u64) -> Cell {
Cell::new(&format!("{:<#x} ", maddr)).style_spec("bFr")
}
pub fn sz_cell(size: u64) -> Cell {
Cell::new(&format!("{:<#x} ", size)).style_spec("Fg")
}
pub fn memsz_cell(memsz: u64) -> Cell {
Cell::new(&format!("{:<#x} ", memsz)).style_spec("bFg")
}
pub fn x_cell(num: u64) -> Cell {
Cell::new(&format!("{:#x}", num))
}
pub fn cell<T: AsRef<str>>(n: T) -> Cell {
Cell::new(n.as_ref())
}
pub fn bool_cell(b: bool) -> Cell {
let cell = Cell::new(&format!("{} ", b));
if b {
cell.style_spec("bFg")
} else {
cell.style_spec("bFr")
}
}
pub fn fmt_hdr(fmt: &mut Buffer, name: &str) -> ::std::io::Result<()> {
color!(fmt, White, name)
}
pub fn fmt_hdr_size(fmt: &mut Buffer, name: &str, size: usize) -> ::std::io::Result<()> {
color_dim!(fmt, White, format!("{}({})", name, size))
}
pub fn fmt_header(fmt: &mut Buffer, name: &str, size: usize) -> ::std::io::Result<()> {
fmt_hdr_size(fmt, name, size)?;
writeln!(fmt, ":")?;
Ok(())
}
pub fn fmt_addr(fmt: &mut Buffer, addr: u64) -> ::std::io::Result<()> {
color!(fmt, Red, format!("{:x}", addr))
}
pub fn fmt_addr_right(fmt: &mut Buffer, addr: u64) -> ::std::io::Result<()> {
color!(fmt, Red, format!("{:>16x}", addr))
}
pub fn fmt_addrx(fmt: &mut Buffer, addr: u64) -> ::std::io::Result<()> {
color!(fmt, Red, format!("{:#x}", addr))
}
pub fn fmt_isize(fmt: &mut Buffer, i: isize) -> ::std::io::Result<()> {
color!(fmt, Red, format!("{}", i))
}
pub fn fmt_off(fmt: &mut Buffer, off: u64) -> ::std::io::Result<()> {
color!(fmt, Yellow, format!("{:#x}", off))
}
pub fn fmt_string(fmt: &mut Buffer, opt: &Opt, s: &str) -> ::std::io::Result<()> {
color_bold!(
fmt,
Yellow,
if opt.demangle {
union_demangle(s)
} else {
s.into()
}
)
}
pub fn fmt_str_option(fmt: &mut Buffer, s: Option<&str>) -> ::std::io::Result<()> {
if let Some(s) = s {
fmt_str(fmt, s)
} else {
fmt_name_dim(fmt, "None")
}
}
pub fn fmt_str(fmt: &mut Buffer, s: &str) -> ::std::io::Result<()> {
color_bold!(fmt, Yellow, s)
}
pub fn fmt_bool(fmt: &mut Buffer, b: bool) -> ::std::io::Result<()> {
if b {
fmt.set_color(
::termcolor::ColorSpec::new()
.set_bold(true)
.set_intense(true)
.set_fg(Some(Green)),
)?;
} else {
fmt.set_color(
::termcolor::ColorSpec::new()
.set_bold(true)
.set_intense(true)
.set_fg(Some(Red)),
)?;
}
write!(fmt, "{}", b)?;
fmt.reset()
}
pub fn fmt_name_bold(fmt: &mut Buffer, s: &str) -> ::std::io::Result<()> {
color_bold!(fmt, White, s)
}
pub fn fmt_name_dim(fmt: &mut Buffer, s: &str) -> ::std::io::Result<()> {
color_dim!(fmt, White, s)
}
pub fn fmt_name_color(
fmt: &mut Buffer,
s: &str,
color: ::termcolor::Color,
) -> ::std::io::Result<()> {
color!(fmt, color, s)
}
pub fn fmt_lib(fmt: &mut Buffer, s: &str) -> ::std::io::Result<()> {
color_bold!(fmt, Blue, s)
}
pub fn fmt_lib_right(fmt: &mut Buffer, s: &str) -> ::std::io::Result<()> {
color_bold!(fmt, Blue, format!("{:>16}", s))
}
pub fn fmt_cyan(fmt: &mut Buffer, s: &str) -> ::std::io::Result<()> {
color!(fmt, Cyan, s)
}
pub fn fmt_sz(fmt: &mut Buffer, fmt_sz: u64) -> ::std::io::Result<()> {
color!(fmt, Green, format!("{:#x}", fmt_sz))
}
pub fn fmt_idx(fmt: &mut Buffer, i: usize) -> ::std::io::Result<()> {
let index = format!("{:>4}", i);
if i % 2 == 0 {
fmt.set_color(::termcolor::ColorSpec::new().set_fg(Some(White)))?;
} else {
fmt.set_color(
::termcolor::ColorSpec::new()
.set_bg(Some(White))
.set_fg(Some(Black)),
)?;
}
write!(fmt, "{}", index)?;
fmt.reset()
}
pub fn flush(
fmt: &mut Buffer,
writer: &BufferWriter,
table: &Table,
color: bool,
) -> ::std::io::Result<()> {
writer.print(fmt)?;
fmt.clear();
print_table_to_stdout(table, color)
}
pub(crate) fn print_table_to_stdout(
table: &prettytable::Table,
force_colorize: bool,
) -> Result<(), std::io::Error> {
match (term::stdout(), stdout().is_terminal() || force_colorize) {
(Some(mut o), true) => table.print_term(&mut *o),
_ => table.print(&mut std::io::stdout()),
}
.map(|_| ())
}