2020-06-16 20:00:11 -04:00
|
|
|
use std::{
|
2020-08-14 21:40:20 +02:00
|
|
|
fs::OpenOptions,
|
2020-07-16 00:20:51 -04:00
|
|
|
io::{stdin, stdout, BufWriter, Read, Write},
|
2020-07-13 14:52:52 +01:00
|
|
|
path::Path,
|
2020-06-16 20:00:11 -04:00
|
|
|
};
|
2020-01-04 22:55:04 -05:00
|
|
|
|
2020-07-06 21:09:25 -05:00
|
|
|
use clap::{arg_enum, App, AppSettings, Arg};
|
2020-03-01 14:53:52 -05:00
|
|
|
|
2020-06-16 20:40:19 -04:00
|
|
|
#[cfg(not(feature = "wasm"))]
|
2020-07-16 00:20:51 -04:00
|
|
|
use grass::{from_path, from_string, Options};
|
2020-01-11 20:41:36 -05:00
|
|
|
|
2020-05-01 14:16:40 -04:00
|
|
|
arg_enum! {
|
|
|
|
#[derive(PartialEq, Debug)]
|
|
|
|
pub enum Style {
|
|
|
|
Expanded,
|
|
|
|
Compressed,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
arg_enum! {
|
|
|
|
#[derive(PartialEq, Debug)]
|
|
|
|
pub enum SourceMapUrls {
|
|
|
|
Relative,
|
|
|
|
Absolute,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-05 19:12:17 -04:00
|
|
|
#[cfg(feature = "wasm")]
|
|
|
|
fn main() {}
|
|
|
|
|
|
|
|
#[cfg(not(feature = "wasm"))]
|
2020-05-01 15:43:43 -04:00
|
|
|
#[cfg_attr(feature = "profiling", inline(never))]
|
2020-05-01 14:16:40 -04:00
|
|
|
fn main() -> std::io::Result<()> {
|
2020-01-20 11:00:01 -05:00
|
|
|
let matches = App::new("grass")
|
2020-07-06 21:09:25 -05:00
|
|
|
.setting(AppSettings::ColoredHelp)
|
2020-01-20 11:00:01 -05:00
|
|
|
.version(env!("CARGO_PKG_VERSION"))
|
2020-07-16 00:20:51 -04:00
|
|
|
.about("A near-feature-complete Sass compiler written purely in Rust")
|
2020-01-20 11:09:05 -05:00
|
|
|
.version_short("v")
|
2020-01-20 11:00:01 -05:00
|
|
|
.arg(
|
2020-05-01 14:16:40 -04:00
|
|
|
Arg::with_name("STDIN")
|
2020-01-20 11:00:01 -05:00
|
|
|
.long("stdin")
|
|
|
|
.help("Read the stylesheet from stdin"),
|
|
|
|
)
|
|
|
|
.arg(
|
2020-05-01 14:16:40 -04:00
|
|
|
Arg::with_name("INDENTED")
|
2020-01-20 11:00:01 -05:00
|
|
|
.long("indented")
|
2020-07-10 16:31:44 -04:00
|
|
|
.hidden(true)
|
2020-01-20 11:00:01 -05:00
|
|
|
.help("Use the indented syntax for input from stdin"),
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("LOAD_PATH")
|
|
|
|
.short("I")
|
|
|
|
.long("load-path")
|
2020-05-01 14:16:40 -04:00
|
|
|
.help("A path to use when resolving imports. May be passed multiple times.")
|
|
|
|
.multiple(true)
|
2020-05-01 16:06:22 -04:00
|
|
|
.takes_value(true)
|
2020-07-24 23:34:25 -04:00
|
|
|
.number_of_values(1)
|
2020-01-20 11:00:01 -05:00
|
|
|
)
|
|
|
|
.arg(
|
2020-05-01 14:16:40 -04:00
|
|
|
Arg::with_name("STYLE")
|
2020-01-20 11:00:01 -05:00
|
|
|
.short("s")
|
2020-05-01 15:57:37 -04:00
|
|
|
// this is required for compatibility with ruby sass
|
|
|
|
.short("t")
|
2020-01-20 11:00:01 -05:00
|
|
|
.long("style")
|
2020-07-10 16:31:44 -04:00
|
|
|
.hidden(true)
|
2020-05-01 14:16:40 -04:00
|
|
|
.help("Minified or expanded output")
|
|
|
|
.default_value("expanded")
|
|
|
|
.case_insensitive(true)
|
|
|
|
.possible_values(&Style::variants())
|
2020-01-20 11:00:01 -05:00
|
|
|
.takes_value(true),
|
|
|
|
)
|
|
|
|
.arg(
|
2020-05-01 14:16:40 -04:00
|
|
|
Arg::with_name("NO_CHARSET")
|
|
|
|
.long("no-charset")
|
|
|
|
.help("Don't emit a @charset or BOM for CSS with non-ASCII characters."),
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("UPDATE")
|
2020-01-20 11:00:01 -05:00
|
|
|
.long("update")
|
2020-07-10 16:31:44 -04:00
|
|
|
.hidden(true)
|
2020-05-01 14:16:40 -04:00
|
|
|
.help("Only compile out-of-date stylesheets."),
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("NO_ERROR_CSS")
|
|
|
|
.long("no-error-css")
|
2020-07-10 16:31:44 -04:00
|
|
|
.hidden(true)
|
2020-05-01 14:16:40 -04:00
|
|
|
.help("When an error occurs, don't emit a stylesheet describing it."),
|
|
|
|
)
|
|
|
|
// Source maps
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("NO_SOURCE_MAP")
|
|
|
|
.long("no-source-map")
|
2020-07-10 16:31:44 -04:00
|
|
|
.hidden(true)
|
2020-05-01 14:16:40 -04:00
|
|
|
.help("Whether to generate source maps."),
|
2020-01-20 11:00:01 -05:00
|
|
|
)
|
|
|
|
.arg(
|
2020-05-01 14:16:40 -04:00
|
|
|
Arg::with_name("SOURCE_MAP_URLS")
|
|
|
|
.long("source-map-urls")
|
2020-07-10 16:31:44 -04:00
|
|
|
.hidden(true)
|
2020-05-01 14:16:40 -04:00
|
|
|
.help("How to link from source maps to source files.")
|
|
|
|
.default_value("relative")
|
|
|
|
.case_insensitive(true)
|
|
|
|
.possible_values(&SourceMapUrls::variants())
|
2020-01-20 11:00:01 -05:00
|
|
|
.takes_value(true),
|
|
|
|
)
|
|
|
|
.arg(
|
2020-05-01 14:16:40 -04:00
|
|
|
Arg::with_name("EMBED_SOURCES")
|
|
|
|
.long("embed-sources")
|
2020-07-10 16:31:44 -04:00
|
|
|
.hidden(true)
|
2020-05-01 14:16:40 -04:00
|
|
|
.help("Embed source file contents in source maps."),
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("EMBED_SOURCE_MAP")
|
|
|
|
.long("embed-source-map")
|
2020-07-10 16:31:44 -04:00
|
|
|
.hidden(true)
|
2020-05-01 14:16:40 -04:00
|
|
|
.help("Embed source map contents in CSS."),
|
|
|
|
)
|
|
|
|
// Other
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("WATCH")
|
|
|
|
.long("watch")
|
2020-07-10 16:31:44 -04:00
|
|
|
.hidden(true)
|
2020-05-01 14:16:40 -04:00
|
|
|
.help("Watch stylesheets and recompile when they change."),
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("POLL")
|
|
|
|
.long("poll")
|
2020-07-10 16:31:44 -04:00
|
|
|
.hidden(true)
|
2020-05-01 14:16:40 -04:00
|
|
|
.help("Manually check for changes rather than using a native watcher. Only valid with --watch.")
|
|
|
|
.requires("WATCH"),
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("NO_STOP_ON_ERROR")
|
|
|
|
.long("no-stop-on-error")
|
2020-07-10 16:31:44 -04:00
|
|
|
.hidden(true)
|
2020-05-01 14:16:40 -04:00
|
|
|
.help("Continue to compile more files after error is encountered.")
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("INTERACTIVE")
|
|
|
|
.short("i")
|
|
|
|
.long("interactive")
|
2020-07-10 16:31:44 -04:00
|
|
|
.hidden(true)
|
2020-05-01 14:16:40 -04:00
|
|
|
.help("Run an interactive SassScript shell.")
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("NO_COLOR")
|
|
|
|
.short("c")
|
|
|
|
.long("no-color")
|
2020-07-10 16:31:44 -04:00
|
|
|
.hidden(true)
|
2020-05-01 14:16:40 -04:00
|
|
|
.help("Whether to use terminal colors for messages.")
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("NO_UNICODE")
|
|
|
|
.long("no-unicode")
|
|
|
|
.help("Whether to use Unicode characters for messages.")
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("QUIET")
|
2020-01-20 11:00:01 -05:00
|
|
|
.short("q")
|
|
|
|
.long("quiet")
|
2020-05-01 14:16:40 -04:00
|
|
|
.help("Don't print warnings."),
|
2020-01-20 11:00:01 -05:00
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("INPUT")
|
2020-07-16 00:20:51 -04:00
|
|
|
.required_unless("STDIN")
|
2020-01-20 11:00:01 -05:00
|
|
|
.help("SCSS files"),
|
|
|
|
)
|
2020-05-01 14:16:40 -04:00
|
|
|
.arg(
|
|
|
|
Arg::with_name("OUTPUT")
|
|
|
|
.help("Output SCSS file")
|
|
|
|
)
|
2020-05-01 15:48:08 -04:00
|
|
|
|
|
|
|
// Hidden, legacy arguments
|
|
|
|
.arg(
|
2020-05-01 15:57:37 -04:00
|
|
|
Arg::with_name("PRECISION")
|
2020-05-01 15:48:08 -04:00
|
|
|
.long("precision")
|
|
|
|
.hidden(true)
|
2020-05-01 16:06:22 -04:00
|
|
|
.takes_value(true)
|
2020-05-01 15:48:08 -04:00
|
|
|
)
|
2020-01-20 11:00:01 -05:00
|
|
|
.get_matches();
|
2020-01-05 20:26:34 -05:00
|
|
|
|
2020-07-16 21:15:24 +08:00
|
|
|
let load_paths = matches
|
|
|
|
.values_of("LOAD_PATH")
|
|
|
|
.map_or_else(Vec::new, |vals| vals.map(Path::new).collect());
|
2020-07-13 14:52:52 +01:00
|
|
|
|
2020-07-15 23:54:46 -04:00
|
|
|
let options = &Options::default()
|
2020-07-16 00:22:50 -04:00
|
|
|
.load_paths(&load_paths)
|
2020-07-15 23:54:46 -04:00
|
|
|
.quiet(matches.is_present("QUIET"))
|
2020-07-16 00:02:42 -04:00
|
|
|
.unicode_error_messages(!matches.is_present("NO_UNICODE"))
|
|
|
|
.allows_charset(!matches.is_present("NO_CHARSET"));
|
2020-07-15 12:37:19 +01:00
|
|
|
|
2020-07-16 00:07:59 -04:00
|
|
|
let (mut stdout_write, mut file_write);
|
|
|
|
let buf_out: &mut dyn Write = if let Some(path) = matches.value_of("OUTPUT") {
|
2020-08-14 21:40:20 +02:00
|
|
|
file_write = BufWriter::new(
|
|
|
|
OpenOptions::new()
|
|
|
|
.create(true)
|
|
|
|
.write(true)
|
|
|
|
.truncate(true)
|
|
|
|
.open(path)?,
|
|
|
|
);
|
2020-07-16 00:07:59 -04:00
|
|
|
&mut file_write
|
|
|
|
} else {
|
|
|
|
stdout_write = BufWriter::new(stdout());
|
|
|
|
&mut stdout_write
|
|
|
|
};
|
|
|
|
|
2020-07-16 00:20:51 -04:00
|
|
|
buf_out.write_all(
|
|
|
|
if let Some(name) = matches.value_of("INPUT") {
|
2021-07-04 01:24:08 -04:00
|
|
|
from_path(name, options)
|
2020-07-16 00:20:51 -04:00
|
|
|
} else if matches.is_present("STDIN") {
|
|
|
|
from_string(
|
|
|
|
{
|
|
|
|
let mut buffer = String::new();
|
|
|
|
stdin().read_to_string(&mut buffer)?;
|
|
|
|
buffer
|
|
|
|
},
|
|
|
|
options,
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
unreachable!()
|
|
|
|
}
|
|
|
|
.unwrap_or_else(|e| {
|
|
|
|
eprintln!("{}", e);
|
|
|
|
std::process::exit(1)
|
|
|
|
})
|
|
|
|
.as_bytes(),
|
|
|
|
)?;
|
2020-05-01 14:16:40 -04:00
|
|
|
Ok(())
|
2020-01-18 15:47:51 -05:00
|
|
|
}
|