mirror of
				https://github.com/sharkdp/bat.git
				synced 2025-10-31 15:12:12 +00:00 
			
		
		
		
	Compare commits
	
		
			6 Commits
		
	
	
		
			update-war
			...
			bat-plugin
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | aa35cb52c4 | ||
|  | 446b9181e6 | ||
|  | 040242c9be | ||
|  | dbf78d280a | ||
|  | bc91af3ee5 | ||
|  | 3811615606 | 
							
								
								
									
										25
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										25
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @@ -98,6 +98,7 @@ dependencies = [ | |||||||
|  "path_abs", |  "path_abs", | ||||||
|  "predicates", |  "predicates", | ||||||
|  "regex", |  "regex", | ||||||
|  |  "rlua", | ||||||
|  "semver", |  "semver", | ||||||
|  "serde", |  "serde", | ||||||
|  "serde_yaml", |  "serde_yaml", | ||||||
| @@ -916,6 +917,30 @@ dependencies = [ | |||||||
|  "bytemuck", |  "bytemuck", | ||||||
| ] | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "rlua" | ||||||
|  | version = "0.19.1" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "627ae78424400009e889c43b0c188d0b7af3fe7301b68c03d9cfacb29115408a" | ||||||
|  | dependencies = [ | ||||||
|  |  "bitflags", | ||||||
|  |  "bstr", | ||||||
|  |  "libc", | ||||||
|  |  "num-traits", | ||||||
|  |  "rlua-lua54-sys", | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "rlua-lua54-sys" | ||||||
|  | version = "0.1.1" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "b4e1fdfc6a5f7acfa1b1fe26c5076b54f5ebd6818b5982460c39844c8b859370" | ||||||
|  | dependencies = [ | ||||||
|  |  "cc", | ||||||
|  |  "libc", | ||||||
|  |  "pkg-config", | ||||||
|  | ] | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "rustversion" | name = "rustversion" | ||||||
| version = "1.0.6" | version = "1.0.6" | ||||||
|   | |||||||
| @@ -30,6 +30,7 @@ minimal-application = [ | |||||||
|     "paging", |     "paging", | ||||||
|     "regex-onig", |     "regex-onig", | ||||||
|     "wild", |     "wild", | ||||||
|  |     "rlua" | ||||||
| ] | ] | ||||||
| git = ["git2"] # Support indicating git modifications | git = ["git2"] # Support indicating git modifications | ||||||
| paging = ["shell-words", "grep-cli"] # Support applying a pager on the output | paging = ["shell-words", "grep-cli"] # Support applying a pager on the output | ||||||
| @@ -65,6 +66,7 @@ grep-cli = { version = "0.1.6", optional = true } | |||||||
| regex = { version = "1.5.5", optional = true } | regex = { version = "1.5.5", optional = true } | ||||||
| walkdir = { version = "2.0", optional = true } | walkdir = { version = "2.0", optional = true } | ||||||
| bytesize = { version = "1.1.0" } | bytesize = { version = "1.1.0" } | ||||||
|  | rlua = { version = "0.19", optional = true } | ||||||
|  |  | ||||||
| [dependencies.git2] | [dependencies.git2] | ||||||
| version = "0.14" | version = "0.14" | ||||||
|   | |||||||
							
								
								
									
										21
									
								
								plugins/curl.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								plugins/curl.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | function tempdir() | ||||||
|  |     local stream = assert(io.popen('mktemp --directory')) | ||||||
|  |     local output = stream:read('*all') | ||||||
|  |     stream:close() | ||||||
|  |     return string.gsub(output, "\n", "") | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function preprocess(path_or_url) | ||||||
|  |     filename_from_url = string.match(path_or_url, '^https?://.*/(.*)$') | ||||||
|  |     if filename_from_url then | ||||||
|  |         local temp_directory = tempdir() | ||||||
|  |         local new_path = temp_directory .. "/" .. filename_from_url | ||||||
|  |  | ||||||
|  |         -- TODO: how to prevent shell injection bugs? | ||||||
|  |         os.execute("curl --silent '" .. path_or_url .. "' --output '" .. new_path .. "'") | ||||||
|  |  | ||||||
|  |         return new_path | ||||||
|  |     else | ||||||
|  |         return path_or_url | ||||||
|  |     end | ||||||
|  | end | ||||||
							
								
								
									
										17
									
								
								plugins/directories.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								plugins/directories.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | |||||||
|  | -- https://stackoverflow.com/a/3254007/704831 | ||||||
|  | function is_dir(path) | ||||||
|  |     local f = io.open(path, "r") | ||||||
|  |     local ok, err, code = f:read(1) | ||||||
|  |     f:close() | ||||||
|  |     return code == 21 | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function preprocess(path) | ||||||
|  |     if is_dir(path) then | ||||||
|  |         tmpfile = os.tmpname() | ||||||
|  |         os.execute("ls -alh --color=always '" .. path .. "' > '" .. tmpfile .. "'") | ||||||
|  |         return tmpfile | ||||||
|  |     else | ||||||
|  |         return path | ||||||
|  |     end | ||||||
|  | end | ||||||
							
								
								
									
										21
									
								
								plugins/hexyl.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								plugins/hexyl.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | -- Note: this plugin depends on the existence of 'inspect' [1] and 'hexyl' [2] | ||||||
|  | -- | ||||||
|  | -- [1] https://github.com/sharkdp/content_inspector | ||||||
|  | -- [2] https://github.com/sharkdp/hexyl | ||||||
|  |  | ||||||
|  | function is_binary(path) | ||||||
|  |     local stream = assert(io.popen("inspect '" .. path .. "'")) | ||||||
|  |     local output = stream:read('*all') | ||||||
|  |     stream:close() | ||||||
|  |     return string.find(output, ": binary\n") | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function preprocess(path) | ||||||
|  |     if is_binary(path) then | ||||||
|  |         tmpfile = os.tmpname() | ||||||
|  |         os.execute("hexyl --length 1024 --no-position --border=none --no-squeezing '" .. path .. "' > '" .. tmpfile .. "'") | ||||||
|  |         return tmpfile | ||||||
|  |     else | ||||||
|  |         return path | ||||||
|  |     end | ||||||
|  | end | ||||||
							
								
								
									
										21
									
								
								plugins/uncompress.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								plugins/uncompress.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | function tempdir() | ||||||
|  |     local stream = assert(io.popen('mktemp --directory')) | ||||||
|  |     local output = stream:read('*all') | ||||||
|  |     stream:close() | ||||||
|  |     return string.gsub(output, "\n", "") | ||||||
|  | end | ||||||
|  |  | ||||||
|  | function preprocess(path) | ||||||
|  |     prefix = string.match(path, '^(.*)%.gz$') | ||||||
|  |     if prefix then | ||||||
|  |         local temp_directory = tempdir() | ||||||
|  |         local new_path = temp_directory .. "/" .. prefix | ||||||
|  |  | ||||||
|  |         -- TODO: how to prevent shell injection bugs? | ||||||
|  |         os.execute("gunzip < '" .. path .. "' > '" .. new_path .. "'") | ||||||
|  |  | ||||||
|  |         return new_path | ||||||
|  |     else | ||||||
|  |         return path | ||||||
|  |     end | ||||||
|  | end | ||||||
| @@ -241,6 +241,11 @@ impl App { | |||||||
|                 .map(HighlightedLineRanges) |                 .map(HighlightedLineRanges) | ||||||
|                 .unwrap_or_default(), |                 .unwrap_or_default(), | ||||||
|             use_custom_assets: !self.matches.is_present("no-custom-assets"), |             use_custom_assets: !self.matches.is_present("no-custom-assets"), | ||||||
|  |             plugins: self | ||||||
|  |                 .matches | ||||||
|  |                 .values_of_os("load-plugin") | ||||||
|  |                 .unwrap_or_default() | ||||||
|  |                 .collect(), | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -474,6 +474,16 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> { | |||||||
|                 .help("Display all supported languages.") |                 .help("Display all supported languages.") | ||||||
|                 .long_help("Display a list of supported languages for syntax highlighting."), |                 .long_help("Display a list of supported languages for syntax highlighting."), | ||||||
|         ) |         ) | ||||||
|  |         .arg( | ||||||
|  |             Arg::with_name("load-plugin") | ||||||
|  |             .long("load-plugin") | ||||||
|  |             .multiple(true) | ||||||
|  |             .takes_value(true) | ||||||
|  |             .number_of_values(1) | ||||||
|  |             .value_name("name") | ||||||
|  |             .help("Load plugin with specified name.") | ||||||
|  |             .hidden_short_help(true) | ||||||
|  |         ) | ||||||
|         .arg( |         .arg( | ||||||
|             Arg::with_name("unbuffered") |             Arg::with_name("unbuffered") | ||||||
|                 .short("u") |                 .short("u") | ||||||
|   | |||||||
| @@ -8,6 +8,7 @@ mod directories; | |||||||
| mod input; | mod input; | ||||||
|  |  | ||||||
| use std::collections::{HashMap, HashSet}; | use std::collections::{HashMap, HashSet}; | ||||||
|  | use std::ffi::OsStr; | ||||||
| use std::io; | use std::io; | ||||||
| use std::io::{BufReader, Write}; | use std::io::{BufReader, Write}; | ||||||
| use std::path::Path; | use std::path::Path; | ||||||
| @@ -218,7 +219,66 @@ pub fn list_themes(cfg: &Config) -> Result<()> { | |||||||
|     Ok(()) |     Ok(()) | ||||||
| } | } | ||||||
|  |  | ||||||
| fn run_controller(inputs: Vec<Input>, config: &Config) -> Result<bool> { | fn load_and_run_preprocess_plugins(plugins: &[&OsStr], inputs: &mut Vec<Input>) -> Result<()> { | ||||||
|  |     use bat::input::InputKind; | ||||||
|  |     use rlua::{Function, Lua, Result as LuaResult}; | ||||||
|  |     use std::fs; | ||||||
|  |     use std::path::PathBuf; | ||||||
|  |  | ||||||
|  |     if plugins.is_empty() { | ||||||
|  |         // Do not create Lua context if there are no plugins | ||||||
|  |         return Ok(()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     let lua = Lua::new(); | ||||||
|  |  | ||||||
|  |     for plugin_name in plugins { | ||||||
|  |         // TODO: properly load plugins from a central directory + user directories | ||||||
|  |         // TODO: how to handle plugin priority? | ||||||
|  |         let mut plugin_path = PathBuf::from("plugins"); | ||||||
|  |         plugin_path.push(plugin_name); | ||||||
|  |  | ||||||
|  |         let plugin_source_code = fs::read_to_string(&plugin_path).map_err(|e| { | ||||||
|  |             format!( | ||||||
|  |                 "Could not load bat plugin '{}': {}", | ||||||
|  |                 plugin_path.to_string_lossy(), | ||||||
|  |                 e | ||||||
|  |             ) | ||||||
|  |         })?; | ||||||
|  |  | ||||||
|  |         lua.context::<_, LuaResult<()>>(|lua_ctx| { | ||||||
|  |             let globals = lua_ctx.globals(); | ||||||
|  |  | ||||||
|  |             lua_ctx.load(&plugin_source_code).exec()?; | ||||||
|  |  | ||||||
|  |             // Plugins are expected to have a 'preprocess' function | ||||||
|  |             let preprocess: Function = globals.get("preprocess")?; | ||||||
|  |  | ||||||
|  |             for input in inputs.iter_mut() { | ||||||
|  |                 if let InputKind::OrdinaryFile(ref mut path) = &mut input.kind { | ||||||
|  |                     let path_str: String = path.to_string_lossy().into(); | ||||||
|  |                     let new_path = preprocess.call::<_, String>(path_str)?; | ||||||
|  |  | ||||||
|  |                     *path = PathBuf::from(new_path); | ||||||
|  |  | ||||||
|  |                     // TODO: the following line overwrites actual user provided names. However, | ||||||
|  |                     // this is necessary to get proper syntax highlighting for the path that | ||||||
|  |                     // is being provided by the plugin. | ||||||
|  |                     input.metadata.user_provided_name = Some(path.clone()); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             Ok(()) | ||||||
|  |         }) | ||||||
|  |         .map_err(|e| format!("Error while executing Lua code: {}", e))?; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | fn run_controller(mut inputs: Vec<Input>, config: &Config) -> Result<bool> { | ||||||
|  |     load_and_run_preprocess_plugins(&config.plugins, &mut inputs)?; | ||||||
|  |  | ||||||
|     let assets = assets_from_cache_or_binary(config.use_custom_assets)?; |     let assets = assets_from_cache_or_binary(config.use_custom_assets)?; | ||||||
|     let controller = Controller::new(config, &assets); |     let controller = Controller::new(config, &assets); | ||||||
|     controller.run(inputs) |     controller.run(inputs) | ||||||
|   | |||||||
| @@ -5,6 +5,8 @@ use crate::style::StyleComponents; | |||||||
| use crate::syntax_mapping::SyntaxMapping; | use crate::syntax_mapping::SyntaxMapping; | ||||||
| use crate::wrapping::WrappingMode; | use crate::wrapping::WrappingMode; | ||||||
|  |  | ||||||
|  | use std::ffi::OsStr; | ||||||
|  |  | ||||||
| #[derive(Debug, Clone)] | #[derive(Debug, Clone)] | ||||||
| pub enum VisibleLines { | pub enum VisibleLines { | ||||||
|     /// Show all lines which are included in the line ranges |     /// Show all lines which are included in the line ranges | ||||||
| @@ -86,6 +88,9 @@ pub struct Config<'a> { | |||||||
|     /// Whether or not to allow custom assets. If this is false or if custom assets (a.k.a. |     /// Whether or not to allow custom assets. If this is false or if custom assets (a.k.a. | ||||||
|     /// cached assets) are not available, assets from the binary will be used instead. |     /// cached assets) are not available, assets from the binary will be used instead. | ||||||
|     pub use_custom_assets: bool, |     pub use_custom_assets: bool, | ||||||
|  |  | ||||||
|  |     /// List of bat plugins to be loaded | ||||||
|  |     pub plugins: Vec<&'a OsStr>, | ||||||
| } | } | ||||||
|  |  | ||||||
| #[cfg(all(feature = "minimal-application", feature = "paging"))] | #[cfg(all(feature = "minimal-application", feature = "paging"))] | ||||||
|   | |||||||
							
								
								
									
										12
									
								
								src/input.rs
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								src/input.rs
									
									
									
									
									
								
							| @@ -69,7 +69,8 @@ impl InputDescription { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| pub(crate) enum InputKind<'a> { | pub enum InputKind<'a> { | ||||||
|  |     // TODO | ||||||
|     OrdinaryFile(PathBuf), |     OrdinaryFile(PathBuf), | ||||||
|     StdIn, |     StdIn, | ||||||
|     CustomReader(Box<dyn Read + 'a>), |     CustomReader(Box<dyn Read + 'a>), | ||||||
| @@ -86,14 +87,15 @@ impl<'a> InputKind<'a> { | |||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Clone, Default)] | #[derive(Clone, Default)] | ||||||
| pub(crate) struct InputMetadata { | pub struct InputMetadata { | ||||||
|     pub(crate) user_provided_name: Option<PathBuf>, |     // TODO | ||||||
|  |     pub user_provided_name: Option<PathBuf>, | ||||||
|     pub(crate) size: Option<u64>, |     pub(crate) size: Option<u64>, | ||||||
| } | } | ||||||
|  |  | ||||||
| pub struct Input<'a> { | pub struct Input<'a> { | ||||||
|     pub(crate) kind: InputKind<'a>, |     pub kind: InputKind<'a>,     // TODO | ||||||
|     pub(crate) metadata: InputMetadata, |     pub metadata: InputMetadata, // TODO | ||||||
|     pub(crate) description: InputDescription, |     pub(crate) description: InputDescription, | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user