mirror of
https://github.com/nushell/nushell
synced 2024-11-14 08:57:08 +00:00
Merge pull request #184 from jonathandturner/pixel_ascii
Fix plugin loading and fix rendering for binary
This commit is contained in:
commit
3d28b50a53
10 changed files with 189 additions and 75 deletions
18
src/cli.rs
18
src/cli.rs
|
@ -6,6 +6,7 @@ use crate::commands::classified::{
|
||||||
};
|
};
|
||||||
use crate::commands::command::sink;
|
use crate::commands::command::sink;
|
||||||
use crate::commands::plugin::JsonRpc;
|
use crate::commands::plugin::JsonRpc;
|
||||||
|
use crate::commands::plugin::{PluginCommand, PluginSink};
|
||||||
use crate::context::Context;
|
use crate::context::Context;
|
||||||
crate use crate::errors::ShellError;
|
crate use crate::errors::ShellError;
|
||||||
use crate::evaluate::Scope;
|
use crate::evaluate::Scope;
|
||||||
|
@ -43,8 +44,6 @@ impl<T> MaybeOwned<'a, T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_plugin(path: &std::path::Path, context: &mut Context) -> Result<(), ShellError> {
|
fn load_plugin(path: &std::path::Path, context: &mut Context) -> Result<(), ShellError> {
|
||||||
use crate::commands::{command, plugin};
|
|
||||||
|
|
||||||
let mut child = std::process::Command::new(path)
|
let mut child = std::process::Command::new(path)
|
||||||
.stdin(std::process::Stdio::piped())
|
.stdin(std::process::Stdio::piped())
|
||||||
.stdout(std::process::Stdio::piped())
|
.stdout(std::process::Stdio::piped())
|
||||||
|
@ -70,20 +69,17 @@ fn load_plugin(path: &std::path::Path, context: &mut Context) -> Result<(), Shel
|
||||||
Ok(jrpc) => match jrpc.params {
|
Ok(jrpc) => match jrpc.params {
|
||||||
Ok(params) => {
|
Ok(params) => {
|
||||||
let fname = path.to_string_lossy();
|
let fname = path.to_string_lossy();
|
||||||
//println!("Loaded: {} from {}", params.name, fname);
|
|
||||||
if params.is_filter {
|
if params.is_filter {
|
||||||
let fname = fname.to_string();
|
let fname = fname.to_string();
|
||||||
context.add_commands(vec![command(
|
let name = params.name.clone();
|
||||||
¶ms.name,
|
context.add_commands(vec![Arc::new(PluginCommand::new(
|
||||||
Box::new(move |x| plugin::filter_plugin(fname.clone(), x)),
|
name, fname, params,
|
||||||
)]);
|
))]);
|
||||||
Ok(())
|
Ok(())
|
||||||
} else if params.is_sink {
|
} else if params.is_sink {
|
||||||
let fname = fname.to_string();
|
let fname = fname.to_string();
|
||||||
context.add_sinks(vec![sink(
|
let name = params.name.clone();
|
||||||
¶ms.name,
|
context.add_sinks(vec![Arc::new(PluginSink::new(name, fname, params))]);
|
||||||
Box::new(move |x| plugin::sink_plugin(fname.clone(), x)),
|
|
||||||
)]);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
#[allow(unused)]
|
||||||
macro_rules! named_type {
|
macro_rules! named_type {
|
||||||
($name:ident) => {
|
($name:ident) => {
|
||||||
$crate::parser::registry::NamedType::$($name)*
|
$crate::parser::registry::NamedType::$($name)*
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::commands::command::SinkCommandArgs;
|
|
||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
|
use crate::parser::registry;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use derive_new::new;
|
||||||
use serde::{self, Deserialize, Serialize};
|
use serde::{self, Deserialize, Serialize};
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
use std::io::BufReader;
|
use std::io::BufReader;
|
||||||
|
@ -32,6 +33,44 @@ pub enum NuResult {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(new)]
|
||||||
|
pub struct PluginCommand {
|
||||||
|
name: String,
|
||||||
|
path: String,
|
||||||
|
config: registry::CommandConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Command for PluginCommand {
|
||||||
|
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
|
filter_plugin(self.path.clone(), args)
|
||||||
|
}
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
fn config(&self) -> registry::CommandConfig {
|
||||||
|
self.config.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(new)]
|
||||||
|
pub struct PluginSink {
|
||||||
|
name: String,
|
||||||
|
path: String,
|
||||||
|
config: registry::CommandConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sink for PluginSink {
|
||||||
|
fn run(&self, args: SinkCommandArgs) -> Result<(), ShellError> {
|
||||||
|
sink_plugin(self.path.clone(), args)
|
||||||
|
}
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
fn config(&self) -> registry::CommandConfig {
|
||||||
|
self.config.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn filter_plugin(path: String, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
pub fn filter_plugin(path: String, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let mut child = std::process::Command::new(path)
|
let mut child = std::process::Command::new(path)
|
||||||
.stdin(std::process::Stdio::piped())
|
.stdin(std::process::Stdio::piped())
|
||||||
|
|
|
@ -54,9 +54,6 @@ impl ExtractType for Spanned<Value> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct FilePath;
|
|
||||||
|
|
||||||
impl ExtractType for std::path::PathBuf {
|
impl ExtractType for std::path::PathBuf {
|
||||||
fn syntax_type() -> hir::SyntaxType {
|
fn syntax_type() -> hir::SyntaxType {
|
||||||
hir::SyntaxType::Path
|
hir::SyntaxType::Path
|
||||||
|
@ -66,7 +63,7 @@ impl ExtractType for std::path::PathBuf {
|
||||||
match &value {
|
match &value {
|
||||||
Spanned {
|
Spanned {
|
||||||
item: Value::Primitive(Primitive::String(p)),
|
item: Value::Primitive(Primitive::String(p)),
|
||||||
span,
|
..
|
||||||
} => Ok(PathBuf::from(p)),
|
} => Ok(PathBuf::from(p)),
|
||||||
other => Err(ShellError::type_error("Path", other.spanned_type_name())),
|
other => Err(ShellError::type_error("Path", other.spanned_type_name())),
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ pub fn baseline_parse_token_as_string(token: &Token, source: &Text) -> hir::Expr
|
||||||
}
|
}
|
||||||
RawToken::Variable(span) => hir::Expression::variable(span, token.span),
|
RawToken::Variable(span) => hir::Expression::variable(span, token.span),
|
||||||
RawToken::Integer(_) => hir::Expression::bare(token.span),
|
RawToken::Integer(_) => hir::Expression::bare(token.span),
|
||||||
RawToken::Size(int, unit) => hir::Expression::bare(token.span),
|
RawToken::Size(_, _) => hir::Expression::bare(token.span),
|
||||||
RawToken::Bare => hir::Expression::bare(token.span),
|
RawToken::Bare => hir::Expression::bare(token.span),
|
||||||
RawToken::String(span) => hir::Expression::string(span, token.span),
|
RawToken::String(span) => hir::Expression::string(span, token.span),
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,15 +102,15 @@ impl TokenNode {
|
||||||
pub fn type_name(&self) -> String {
|
pub fn type_name(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
TokenNode::Token(t) => t.type_name(),
|
TokenNode::Token(t) => t.type_name(),
|
||||||
TokenNode::Call(s) => "command",
|
TokenNode::Call(_) => "command",
|
||||||
TokenNode::Delimited(d) => d.type_name(),
|
TokenNode::Delimited(d) => d.type_name(),
|
||||||
TokenNode::Pipeline(s) => "pipeline",
|
TokenNode::Pipeline(_) => "pipeline",
|
||||||
TokenNode::Operator(s) => "operator",
|
TokenNode::Operator(_) => "operator",
|
||||||
TokenNode::Flag(s) => "flag",
|
TokenNode::Flag(_) => "flag",
|
||||||
TokenNode::Member(s) => "member",
|
TokenNode::Member(_) => "member",
|
||||||
TokenNode::Whitespace(s) => "whitespace",
|
TokenNode::Whitespace(_) => "whitespace",
|
||||||
TokenNode::Error(s) => "error",
|
TokenNode::Error(_) => "error",
|
||||||
TokenNode::Path(s) => "path",
|
TokenNode::Path(_) => "path",
|
||||||
}
|
}
|
||||||
.to_string()
|
.to_string()
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
pub enum NamedType {
|
pub enum NamedType {
|
||||||
Switch,
|
Switch,
|
||||||
Mandatory(SyntaxType),
|
Mandatory(SyntaxType),
|
||||||
|
@ -32,10 +32,19 @@ impl PositionalType {
|
||||||
PositionalType::Mandatory(name.to_string(), SyntaxType::Any)
|
PositionalType::Mandatory(name.to_string(), SyntaxType::Any)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn optional(name: &str, ty: SyntaxType) -> PositionalType {
|
||||||
|
PositionalType::Optional(name.to_string(), ty)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn optional_any(name: &str) -> PositionalType {
|
||||||
|
PositionalType::Optional(name.to_string(), SyntaxType::Any)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn mandatory_block(name: &str) -> PositionalType {
|
pub fn mandatory_block(name: &str) -> PositionalType {
|
||||||
PositionalType::Mandatory(name.to_string(), SyntaxType::Block)
|
PositionalType::Mandatory(name.to_string(), SyntaxType::Block)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
crate fn to_coerce_hint(&self) -> Option<SyntaxType> {
|
crate fn to_coerce_hint(&self) -> Option<SyntaxType> {
|
||||||
match self {
|
match self {
|
||||||
PositionalType::Mandatory(_, SyntaxType::Block)
|
PositionalType::Mandatory(_, SyntaxType::Block)
|
||||||
|
@ -59,7 +68,7 @@ impl PositionalType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Getters, Serialize, Deserialize)]
|
#[derive(Debug, Getters, Serialize, Deserialize, Clone)]
|
||||||
#[get = "crate"]
|
#[get = "crate"]
|
||||||
pub struct CommandConfig {
|
pub struct CommandConfig {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crossterm::{cursor, terminal, Attribute, RawScreen};
|
use crossterm::{cursor, terminal, Attribute, RawScreen};
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use nu::{serve_plugin, Args, CommandConfig, Plugin, ShellError, Spanned, Value};
|
use nu::{serve_plugin, Args, CommandConfig, NamedType, Plugin, ShellError, Spanned, Value};
|
||||||
use pretty_hex::*;
|
use pretty_hex::*;
|
||||||
|
|
||||||
struct BinaryView;
|
struct BinaryView;
|
||||||
|
@ -13,24 +13,26 @@ impl BinaryView {
|
||||||
|
|
||||||
impl Plugin for BinaryView {
|
impl Plugin for BinaryView {
|
||||||
fn config(&mut self) -> Result<CommandConfig, ShellError> {
|
fn config(&mut self) -> Result<CommandConfig, ShellError> {
|
||||||
|
let mut named = IndexMap::new();
|
||||||
|
named.insert("lores".to_string(), NamedType::Switch);
|
||||||
Ok(CommandConfig {
|
Ok(CommandConfig {
|
||||||
name: "binaryview".to_string(),
|
name: "binaryview".to_string(),
|
||||||
positional: vec![],
|
positional: vec![],
|
||||||
is_filter: false,
|
is_filter: false,
|
||||||
is_sink: true,
|
is_sink: true,
|
||||||
named: IndexMap::new(),
|
named,
|
||||||
rest_positional: true,
|
rest_positional: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sink(&mut self, _args: Args, input: Vec<Spanned<Value>>) {
|
fn sink(&mut self, args: Args, input: Vec<Spanned<Value>>) {
|
||||||
for v in input {
|
for v in input {
|
||||||
match v {
|
match v {
|
||||||
Spanned {
|
Spanned {
|
||||||
item: Value::Binary(b),
|
item: Value::Binary(b),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let _ = view_binary(&b);
|
let _ = view_binary(&b, args.has("lores"));
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
@ -38,62 +40,65 @@ impl Plugin for BinaryView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view_binary(b: &[u8]) -> Result<(), Box<dyn std::error::Error>> {
|
fn view_binary(b: &[u8], lores_mode: bool) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
if b.len() > 3 {
|
if b.len() > 3 {
|
||||||
match (b[0], b[1], b[2]) {
|
match (b[0], b[1], b[2]) {
|
||||||
(0x4e, 0x45, 0x53) => {
|
(0x4e, 0x45, 0x53) => {
|
||||||
view_contents_interactive(b)?;
|
view_contents_interactive(b, lores_mode)?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
view_contents(b)?;
|
view_contents(b, lores_mode)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Context {
|
pub struct RenderContext {
|
||||||
pub width: usize,
|
pub width: usize,
|
||||||
pub height: usize,
|
pub height: usize,
|
||||||
pub frame_buffer: Vec<(char, (u8, u8, u8))>,
|
pub frame_buffer: Vec<(u8, u8, u8)>,
|
||||||
pub since_last_button: Vec<usize>,
|
pub since_last_button: Vec<usize>,
|
||||||
|
pub lores_mode: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Context {
|
impl RenderContext {
|
||||||
pub fn blank() -> Context {
|
pub fn blank(lores_mode: bool) -> RenderContext {
|
||||||
Context {
|
RenderContext {
|
||||||
width: 0,
|
width: 0,
|
||||||
height: 0,
|
height: 0,
|
||||||
frame_buffer: vec![],
|
frame_buffer: vec![],
|
||||||
since_last_button: vec![0; 8],
|
since_last_button: vec![0; 8],
|
||||||
|
lores_mode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
self.frame_buffer = vec![(' ', (0, 0, 0)); self.width * self.height as usize];
|
self.frame_buffer = vec![(0, 0, 0); self.width * self.height as usize];
|
||||||
}
|
}
|
||||||
pub fn flush(&self) -> Result<(), Box<dyn std::error::Error>> {
|
|
||||||
let cursor = cursor();
|
|
||||||
cursor.goto(0, 0)?;
|
|
||||||
|
|
||||||
|
fn render_to_screen_lores(&mut self) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut prev_color: Option<(u8, u8, u8)> = None;
|
let mut prev_color: Option<(u8, u8, u8)> = None;
|
||||||
let mut prev_count = 1;
|
let mut prev_count = 1;
|
||||||
|
|
||||||
|
let cursor = cursor();
|
||||||
|
cursor.goto(0, 0)?;
|
||||||
|
|
||||||
for pixel in &self.frame_buffer {
|
for pixel in &self.frame_buffer {
|
||||||
match prev_color {
|
match prev_color {
|
||||||
Some(c) if c == pixel.1 => {
|
Some(c) if c == *pixel => {
|
||||||
prev_count += 1;
|
prev_count += 1;
|
||||||
}
|
}
|
||||||
Some(c) => {
|
Some(c) => {
|
||||||
print!(
|
print!(
|
||||||
"{}",
|
"{}",
|
||||||
ansi_term::Colour::RGB(c.0, c.1, c.2)
|
ansi_term::Colour::RGB(c.0, c.1, c.2)
|
||||||
.paint((0..prev_count).map(|_| pixel.0).collect::<String>())
|
.paint((0..prev_count).map(|_| "█").collect::<String>())
|
||||||
);
|
);
|
||||||
prev_color = Some(pixel.1);
|
prev_color = Some(*pixel);
|
||||||
prev_count = 1;
|
prev_count = 1;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
prev_color = Some(pixel.1);
|
prev_color = Some(*pixel);
|
||||||
prev_count = 1;
|
prev_count = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,15 +109,77 @@ impl Context {
|
||||||
print!(
|
print!(
|
||||||
"{}",
|
"{}",
|
||||||
ansi_term::Colour::RGB(color.0, color.1, color.2)
|
ansi_term::Colour::RGB(color.0, color.1, color.2)
|
||||||
.paint((0..prev_count).map(|_| "@").collect::<String>())
|
.paint((0..prev_count).map(|_| "█").collect::<String>())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("{}", Attribute::Reset);
|
println!("{}", Attribute::Reset);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
fn render_to_screen_hires(&mut self) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let mut prev_fg: Option<(u8, u8, u8)> = None;
|
||||||
|
let mut prev_bg: Option<(u8, u8, u8)> = None;
|
||||||
|
let mut prev_count = 1;
|
||||||
|
|
||||||
|
let mut pos = 0;
|
||||||
|
let fb_len = self.frame_buffer.len();
|
||||||
|
|
||||||
|
let cursor = cursor();
|
||||||
|
cursor.goto(0, 0)?;
|
||||||
|
|
||||||
|
while pos < (fb_len - self.width) {
|
||||||
|
let top_pixel = self.frame_buffer[pos];
|
||||||
|
let bottom_pixel = self.frame_buffer[pos + self.width];
|
||||||
|
|
||||||
|
match (prev_fg, prev_bg) {
|
||||||
|
(Some(c), Some(d)) if c == top_pixel && d == bottom_pixel => {
|
||||||
|
prev_count += 1;
|
||||||
|
}
|
||||||
|
(Some(c), Some(d)) => {
|
||||||
|
print!(
|
||||||
|
"{}",
|
||||||
|
ansi_term::Colour::RGB(c.0, c.1, c.2)
|
||||||
|
.on(ansi_term::Colour::RGB(d.0, d.1, d.2,))
|
||||||
|
.paint((0..prev_count).map(|_| "▀").collect::<String>())
|
||||||
|
);
|
||||||
|
prev_fg = Some(top_pixel);
|
||||||
|
prev_bg = Some(bottom_pixel);
|
||||||
|
prev_count = 1;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
prev_fg = Some(top_pixel);
|
||||||
|
prev_bg = Some(bottom_pixel);
|
||||||
|
prev_count = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pos += 1;
|
||||||
|
if pos % self.width == 0 {
|
||||||
|
pos += self.width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if prev_count > 0 {
|
||||||
|
match (prev_fg, prev_bg) {
|
||||||
|
(Some(c), Some(d)) => {
|
||||||
|
print!(
|
||||||
|
"{}",
|
||||||
|
ansi_term::Colour::RGB(c.0, c.1, c.2)
|
||||||
|
.on(ansi_term::Colour::RGB(d.0, d.1, d.2,))
|
||||||
|
.paint((0..prev_count).map(|_| "▀").collect::<String>())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("{}", Attribute::Reset);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn flush(&mut self) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
if self.lores_mode {
|
||||||
|
self.render_to_screen_lores()
|
||||||
|
} else {
|
||||||
|
self.render_to_screen_hires()
|
||||||
|
}
|
||||||
|
}
|
||||||
pub fn update(&mut self) -> Result<(), Box<dyn std::error::Error>> {
|
pub fn update(&mut self) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let terminal = terminal();
|
let terminal = terminal();
|
||||||
let terminal_size = terminal.terminal_size();
|
let terminal_size = terminal.terminal_size();
|
||||||
|
@ -122,7 +189,11 @@ impl Context {
|
||||||
cursor.hide()?;
|
cursor.hide()?;
|
||||||
|
|
||||||
self.width = terminal_size.0 as usize + 1;
|
self.width = terminal_size.0 as usize + 1;
|
||||||
self.height = terminal_size.1 as usize;
|
self.height = if self.lores_mode {
|
||||||
|
terminal_size.1 as usize
|
||||||
|
} else {
|
||||||
|
terminal_size.1 as usize * 2
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -176,7 +247,7 @@ fn load_from_jpg_buffer(buffer: &[u8]) -> Option<(RawImageBuffer)> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn view_contents(buffer: &[u8]) -> Result<(), Box<dyn std::error::Error>> {
|
pub fn view_contents(buffer: &[u8], lores_mode: bool) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut raw_image_buffer = load_from_png_buffer(buffer);
|
let mut raw_image_buffer = load_from_png_buffer(buffer);
|
||||||
|
|
||||||
if raw_image_buffer.is_none() {
|
if raw_image_buffer.is_none() {
|
||||||
|
@ -190,9 +261,9 @@ pub fn view_contents(buffer: &[u8]) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
}
|
}
|
||||||
let raw_image_buffer = raw_image_buffer.unwrap();
|
let raw_image_buffer = raw_image_buffer.unwrap();
|
||||||
|
|
||||||
let mut context: Context = Context::blank();
|
let mut render_context: RenderContext = RenderContext::blank(lores_mode);
|
||||||
let _ = context.update();
|
let _ = render_context.update();
|
||||||
context.clear();
|
render_context.clear();
|
||||||
|
|
||||||
match raw_image_buffer.colortype {
|
match raw_image_buffer.colortype {
|
||||||
image::ColorType::RGBA(8) => {
|
image::ColorType::RGBA(8) => {
|
||||||
|
@ -205,8 +276,8 @@ pub fn view_contents(buffer: &[u8]) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
|
||||||
let resized_img = image::imageops::resize(
|
let resized_img = image::imageops::resize(
|
||||||
&img,
|
&img,
|
||||||
context.width as u32,
|
render_context.width as u32,
|
||||||
context.height as u32,
|
render_context.height as u32,
|
||||||
image::FilterType::Lanczos3,
|
image::FilterType::Lanczos3,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -214,8 +285,7 @@ pub fn view_contents(buffer: &[u8]) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
for pixel in resized_img.pixels() {
|
for pixel in resized_img.pixels() {
|
||||||
use image::Pixel;
|
use image::Pixel;
|
||||||
let rgb = pixel.to_rgb();
|
let rgb = pixel.to_rgb();
|
||||||
//print!("{}", rgb[0]);
|
render_context.frame_buffer[count] = (rgb[0], rgb[1], rgb[2]);
|
||||||
context.frame_buffer[count] = ('@', (rgb[0], rgb[1], rgb[2]));
|
|
||||||
count += 1;
|
count += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -229,8 +299,8 @@ pub fn view_contents(buffer: &[u8]) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
|
||||||
let resized_img = image::imageops::resize(
|
let resized_img = image::imageops::resize(
|
||||||
&img,
|
&img,
|
||||||
context.width as u32,
|
render_context.width as u32,
|
||||||
context.height as u32,
|
render_context.height as u32,
|
||||||
image::FilterType::Lanczos3,
|
image::FilterType::Lanczos3,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -238,8 +308,7 @@ pub fn view_contents(buffer: &[u8]) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
for pixel in resized_img.pixels() {
|
for pixel in resized_img.pixels() {
|
||||||
use image::Pixel;
|
use image::Pixel;
|
||||||
let rgb = pixel.to_rgb();
|
let rgb = pixel.to_rgb();
|
||||||
//print!("{}", rgb[0]);
|
render_context.frame_buffer[count] = (rgb[0], rgb[1], rgb[2]);
|
||||||
context.frame_buffer[count] = ('@', (rgb[0], rgb[1], rgb[2]));
|
|
||||||
count += 1;
|
count += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -250,7 +319,7 @@ pub fn view_contents(buffer: &[u8]) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
context.flush()?;
|
render_context.flush()?;
|
||||||
|
|
||||||
let cursor = cursor();
|
let cursor = cursor();
|
||||||
let _ = cursor.show();
|
let _ = cursor.show();
|
||||||
|
@ -261,7 +330,10 @@ pub fn view_contents(buffer: &[u8]) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn view_contents_interactive(buffer: &[u8]) -> Result<(), Box<dyn std::error::Error>> {
|
pub fn view_contents_interactive(
|
||||||
|
buffer: &[u8],
|
||||||
|
lores_mode: bool,
|
||||||
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
use rawkey::{KeyCode, RawKey};
|
use rawkey::{KeyCode, RawKey};
|
||||||
|
|
||||||
let mut nes = neso::Nes::new(48000.0);
|
let mut nes = neso::Nes::new(48000.0);
|
||||||
|
@ -271,7 +343,7 @@ pub fn view_contents_interactive(buffer: &[u8]) -> Result<(), Box<dyn std::error
|
||||||
nes.reset();
|
nes.reset();
|
||||||
|
|
||||||
if let Ok(_raw) = RawScreen::into_raw_mode() {
|
if let Ok(_raw) = RawScreen::into_raw_mode() {
|
||||||
let mut context: Context = Context::blank();
|
let mut render_context: RenderContext = RenderContext::blank(lores_mode);
|
||||||
let input = crossterm::input();
|
let input = crossterm::input();
|
||||||
let _ = input.read_async();
|
let _ = input.read_async();
|
||||||
let cursor = cursor();
|
let cursor = cursor();
|
||||||
|
@ -290,7 +362,7 @@ pub fn view_contents_interactive(buffer: &[u8]) -> Result<(), Box<dyn std::error
|
||||||
cursor.hide()?;
|
cursor.hide()?;
|
||||||
|
|
||||||
'gameloop: loop {
|
'gameloop: loop {
|
||||||
let _ = context.update();
|
let _ = render_context.update();
|
||||||
nes.step_frame();
|
nes.step_frame();
|
||||||
|
|
||||||
let image_buffer = nes.image_buffer();
|
let image_buffer = nes.image_buffer();
|
||||||
|
@ -300,22 +372,22 @@ pub fn view_contents_interactive(buffer: &[u8]) -> Result<(), Box<dyn std::error
|
||||||
image::ImageBuffer::<image::Rgba<u8>, &[u8]>::from_raw(256, 240, slice).unwrap();
|
image::ImageBuffer::<image::Rgba<u8>, &[u8]>::from_raw(256, 240, slice).unwrap();
|
||||||
let resized_img = image::imageops::resize(
|
let resized_img = image::imageops::resize(
|
||||||
&img,
|
&img,
|
||||||
context.width as u32,
|
render_context.width as u32,
|
||||||
context.height as u32,
|
render_context.height as u32,
|
||||||
image::FilterType::Lanczos3,
|
image::FilterType::Lanczos3,
|
||||||
);
|
);
|
||||||
|
|
||||||
context.clear();
|
render_context.clear();
|
||||||
|
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
for pixel in resized_img.pixels() {
|
for pixel in resized_img.pixels() {
|
||||||
use image::Pixel;
|
use image::Pixel;
|
||||||
let rgb = pixel.to_rgb();
|
let rgb = pixel.to_rgb();
|
||||||
|
|
||||||
context.frame_buffer[count] = ('@', (rgb[0], rgb[1], rgb[2]));
|
render_context.frame_buffer[count] = (rgb[0], rgb[1], rgb[2]);
|
||||||
count += 1;
|
count += 1;
|
||||||
}
|
}
|
||||||
context.flush()?;
|
render_context.flush()?;
|
||||||
|
|
||||||
if rawkey.is_pressed(rawkey::KeyCode::Escape) {
|
if rawkey.is_pressed(rawkey::KeyCode::Escape) {
|
||||||
break 'gameloop;
|
break 'gameloop;
|
||||||
|
|
|
@ -17,7 +17,7 @@ impl Plugin for Inc {
|
||||||
fn config(&mut self) -> Result<CommandConfig, ShellError> {
|
fn config(&mut self) -> Result<CommandConfig, ShellError> {
|
||||||
Ok(CommandConfig {
|
Ok(CommandConfig {
|
||||||
name: "inc".to_string(),
|
name: "inc".to_string(),
|
||||||
positional: vec![PositionalType::mandatory_any("Increment")],
|
positional: vec![PositionalType::optional_any("Increment")],
|
||||||
is_filter: true,
|
is_filter: true,
|
||||||
is_sink: false,
|
is_sink: false,
|
||||||
named: IndexMap::new(),
|
named: IndexMap::new(),
|
||||||
|
|
|
@ -34,7 +34,7 @@ macro_rules! trace_stream {
|
||||||
|
|
||||||
crate use crate::cli::MaybeOwned;
|
crate use crate::cli::MaybeOwned;
|
||||||
crate use crate::commands::command::{
|
crate use crate::commands::command::{
|
||||||
Command, CommandAction, CommandArgs, ReturnSuccess, ReturnValue,
|
Command, CommandAction, CommandArgs, ReturnSuccess, ReturnValue, Sink, SinkCommandArgs,
|
||||||
};
|
};
|
||||||
crate use crate::context::Context;
|
crate use crate::context::Context;
|
||||||
crate use crate::env::host::handle_unexpected;
|
crate use crate::env::host::handle_unexpected;
|
||||||
|
|
Loading…
Reference in a new issue