Add syntect (and borrow bat's theme file)

This commit is contained in:
Jonathan Turner 2019-07-20 13:12:04 +12:00
parent d5d4da0bf8
commit 27dbc1cb9a
10 changed files with 113 additions and 17 deletions

1
Cargo.lock generated
View file

@ -1689,6 +1689,7 @@ dependencies = [
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_yaml 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)",
"subprocess 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
"syntect 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"sys-info 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)",
"sysinfo 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",

View file

@ -76,6 +76,7 @@ tempfile = "3.1.0"
image = "0.21.2"
semver = "0.9.0"
uuid = {version = "0.7.4", features = [ "v4", "serde" ]}
syntect = "3.2.0"
[dev-dependencies]
pretty_assertions = "0.6.1"

BIN
assets/themes.bin Normal file

Binary file not shown.

View file

@ -494,7 +494,7 @@ fn classify_command(
Ok(ClassifiedCommand::Internal(InternalCommand {
command,
name_span: Some(head.span().clone()),
span_sources: context.span_sources.clone(),
source_map: context.source_map.clone(),
args,
}))
}

View file

@ -1,7 +1,9 @@
use crate::commands::command::SinkCommandArgs;
use crate::context::{SourceMap, SpanSource};
use crate::errors::ShellError;
use crate::format::GenericView;
use crate::prelude::*;
use std::path::Path;
pub fn autoview(args: SinkCommandArgs) -> Result<(), ShellError> {
if args.input.len() > 0 {
@ -11,6 +13,8 @@ pub fn autoview(args: SinkCommandArgs) -> Result<(), ShellError> {
} = args.input[0]
{
args.ctx.get_sink("binaryview").run(args)?;
} else if is_single_text_value(&args.input) {
view_text_value(&args.input[0], &args.source_map);
} else if equal_shapes(&args.input) {
args.ctx.get_sink("table").run(args)?;
} else {
@ -44,3 +48,76 @@ fn equal_shapes(input: &Vec<Spanned<Value>>) -> bool {
true
}
fn is_single_text_value(input: &Vec<Spanned<Value>>) -> bool {
if input.len() != 1 {
return false;
}
if let Spanned {
item: Value::Primitive(Primitive::String(_)),
..
} = input[0]
{
true
} else {
false
}
}
fn view_text_value(value: &Spanned<Value>, source_map: &SourceMap) {
match value {
Spanned {
item: Value::Primitive(Primitive::String(s)),
span,
} => {
let source = span.source.map(|x| source_map.get(&x)).flatten();
if let Some(source) = source {
match source {
SpanSource::File(file) => {
let path = Path::new(file);
match path.extension() {
Some(extension) => {
use syntect::easy::HighlightLines;
use syntect::highlighting::{Style, ThemeSet};
use syntect::parsing::SyntaxSet;
use syntect::util::{as_24_bit_terminal_escaped, LinesWithEndings};
// Load these once at the start of your program
let ps = SyntaxSet::load_defaults_newlines();
if let Some(syntax) =
ps.find_syntax_by_extension(extension.to_str().unwrap())
{
let ts: ThemeSet = syntect::dumps::from_binary(include_bytes!(
"../../assets/themes.bin"
));
let mut h =
HighlightLines::new(syntax, &ts.themes["OneHalfDark"]);
for line in LinesWithEndings::from(s) {
let ranges: Vec<(Style, &str)> = h.highlight(line, &ps);
let escaped =
as_24_bit_terminal_escaped(&ranges[..], false);
print!("{}", escaped);
}
} else {
println!("{}", s);
}
}
_ => {
println!("{}", s);
}
}
}
_ => {
println!("{}", s);
}
}
} else {
println!("{}", s);
}
}
_ => {}
}
}

View file

@ -1,16 +1,14 @@
use crate::commands::command::Sink;
use crate::context::SpanSource;
use crate::context::SourceMap;
use crate::parser::{registry::Args, Span, Spanned, TokenNode};
use crate::prelude::*;
use bytes::{BufMut, BytesMut};
use futures::stream::StreamExt;
use futures_codec::{Decoder, Encoder, Framed};
use log::{log_enabled, trace};
use std::collections::HashMap;
use std::io::{Error, ErrorKind};
use std::sync::Arc;
use subprocess::Exec;
use uuid::Uuid;
/// A simple `Codec` implementation that splits up data into lines.
pub struct LinesCodec {}
@ -119,7 +117,7 @@ impl SinkCommand {
crate struct InternalCommand {
crate command: Arc<dyn Command>,
crate name_span: Option<Span>,
crate span_sources: HashMap<Uuid, SpanSource>,
crate source_map: SourceMap,
crate args: Args,
}
@ -141,7 +139,7 @@ impl InternalCommand {
let result = context.run_command(
self.command,
self.name_span.clone(),
self.span_sources,
self.source_map,
self.args,
objects,
)?;

View file

@ -1,3 +1,4 @@
use crate::context::SourceMap;
use crate::context::SpanSource;
use crate::errors::ShellError;
use crate::object::Value;
@ -8,7 +9,6 @@ use crate::parser::{
use crate::prelude::*;
use getset::Getters;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::path::PathBuf;
use uuid::Uuid;
@ -18,7 +18,7 @@ pub struct CommandArgs {
pub host: Arc<Mutex<dyn Host + Send>>,
pub env: Arc<Mutex<Environment>>,
pub name_span: Option<Span>,
pub span_sources: HashMap<Uuid, SpanSource>,
pub source_map: SourceMap,
pub args: Args,
pub input: InputStream,
}
@ -53,7 +53,7 @@ impl CommandArgs {
pub struct SinkCommandArgs {
pub ctx: Context,
pub name_span: Option<Span>,
pub span_sources: HashMap<Uuid, SpanSource>,
pub source_map: SourceMap,
pub args: Args,
pub input: Vec<Spanned<Value>>,
}

View file

@ -17,11 +17,29 @@ pub enum SpanSource {
Url(String),
File(String),
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SourceMap(HashMap<Uuid, SpanSource>);
impl SourceMap {
pub fn insert(&mut self, uuid: Uuid, span_source: SpanSource) {
self.0.insert(uuid, span_source);
}
pub fn get(&self, uuid: &Uuid) -> Option<&SpanSource> {
self.0.get(uuid)
}
pub fn new() -> SourceMap {
SourceMap(HashMap::new())
}
}
#[derive(Clone)]
pub struct Context {
commands: IndexMap<String, Arc<dyn Command>>,
sinks: IndexMap<String, Arc<dyn Sink>>,
crate span_sources: HashMap<Uuid, SpanSource>,
crate source_map: SourceMap,
crate host: Arc<Mutex<dyn Host + Send>>,
crate env: Arc<Mutex<Environment>>,
}
@ -31,7 +49,7 @@ impl Context {
Ok(Context {
commands: indexmap::IndexMap::new(),
sinks: indexmap::IndexMap::new(),
span_sources: HashMap::new(),
source_map: SourceMap::new(),
host: Arc::new(Mutex::new(crate::env::host::BasicHost)),
env: Arc::new(Mutex::new(Environment::basic()?)),
})
@ -50,7 +68,7 @@ impl Context {
}
pub fn add_span_source(&mut self, uuid: Uuid, span_source: SpanSource) {
self.span_sources.insert(uuid, span_source);
self.source_map.insert(uuid, span_source);
}
crate fn has_sink(&self, name: &str) -> bool {
@ -71,7 +89,7 @@ impl Context {
let command_args = SinkCommandArgs {
ctx: self.clone(),
name_span,
span_sources: self.span_sources.clone(),
source_map: self.source_map.clone(),
args,
input,
};
@ -95,7 +113,7 @@ impl Context {
&mut self,
command: Arc<dyn Command>,
name_span: Option<Span>,
span_sources: HashMap<Uuid, SpanSource>,
source_map: SourceMap,
args: Args,
input: InputStream,
) -> Result<OutputStream, ShellError> {
@ -103,7 +121,7 @@ impl Context {
host: self.host.clone(),
env: self.env.clone(),
name_span,
span_sources,
source_map,
args,
input,
};

View file

@ -5,6 +5,7 @@
#![feature(bind_by_move_pattern_guards)]
#![feature(box_syntax)]
#![feature(type_ascription)]
#![feature(option_flattening)]
#[macro_use]
mod prelude;

View file

@ -9,8 +9,8 @@ use log::LevelFilter;
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
let matches = App::new("nu shell")
.version("0.5")
let matches = App::new("nushell")
.version("0.1.3")
.arg(
Arg::with_name("loglevel")
.short("l")