mirror of
https://github.com/nushell/nushell.git
synced 2024-11-21 16:03:19 +01:00
Add syntect (and borrow bat's theme file)
This commit is contained in:
parent
d5d4da0bf8
commit
27dbc1cb9a
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -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)",
|
||||
|
@ -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
BIN
assets/themes.bin
Normal file
Binary file not shown.
@ -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,
|
||||
}))
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
)?;
|
||||
|
@ -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>>,
|
||||
}
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -5,6 +5,7 @@
|
||||
#![feature(bind_by_move_pattern_guards)]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(type_ascription)]
|
||||
#![feature(option_flattening)]
|
||||
|
||||
#[macro_use]
|
||||
mod prelude;
|
||||
|
@ -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")
|
||||
|
Loading…
Reference in New Issue
Block a user