commit 830e90761e0c63976f9fac161d78b914e15184c8 Author: trivernis Date: Sat Oct 1 23:44:33 2022 +0200 Add state builder with command state Signed-off-by: trivernis diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4fffb2f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +/Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..a0d9270 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "embed-nu" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +nu-command = "0.69.1" +nu-engine = "0.69.1" +nu-parser = "0.69.1" +nu-protocol = "0.69.1" +paste = "1.0.9" +thiserror = "1.0.37" diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..21f6e52 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,3 @@ +pub type CrateResult = std::result::Result; + +pub enum CrateError {} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..b75881e --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,6 @@ +use state_builder::StateBuilder; + +pub(crate) mod error; +pub mod state_builder; + +pub type Error = error::CrateError; diff --git a/src/state_builder/bindings.rs b/src/state_builder/bindings.rs new file mode 100644 index 0000000..c377a56 --- /dev/null +++ b/src/state_builder/bindings.rs @@ -0,0 +1,458 @@ +use nu_command::*; +use nu_protocol::engine::{EngineState, StateWorkingSet}; + +macro_rules! bind_commands { + ($engine_state:expr, $( $command:expr),* $(,)? ) => { + bind($engine_state, |working_set| { + $( working_set.add_decl(Box::new($command)); )* + }); + }; + } + +pub fn bind_core_commands(engine_state: &mut EngineState) { + bind_commands!( + engine_state, + Alias, + Ast, + Commandline, + Debug, + Def, + DefEnv, + Describe, + Do, + Echo, + ErrorMake, + ExportAlias, + ExportCommand, + ExportDef, + ExportDefEnv, + ExportExtern, + ExportUse, + Extern, + For, + Help, + Hide, + HideEnv, + If, + Ignore, + Overlay, + OverlayUse, + OverlayList, + OverlayNew, + OverlayHide, + Let, + Metadata, + Module, + Use, + Version, + ); +} + +pub fn bind_chart_commands(engine_state: &mut EngineState) { + bind_commands!(engine_state, Histogram); +} + +pub fn bind_filter_commands(engine_state: &mut EngineState) { + bind_commands! { + engine_state, + All, + Any, + Append, + Collect, + Columns, + Compact, + Default, + Drop, + DropColumn, + DropNth, + Each, + EachWhile, + Empty, + Every, + Find, + First, + Flatten, + Get, + Group, + GroupBy, + Headers, + Insert, + SplitBy, + Take, + Merge, + Move, + TakeWhile, + TakeUntil, + Last, + Length, + Lines, + ParEach, + Prepend, + Range, + Reduce, + Reject, + Rename, + Reverse, + Roll, + RollDown, + RollUp, + RollLeft, + RollRight, + Rotate, + Select, + Shuffle, + Skip, + SkipUntil, + SkipWhile, + Sort, + SortBy, + SplitList, + Transpose, + Uniq, + Upsert, + Update, + UpdateCells, + Where, + Window, + Wrap, + Zip, + }; +} + +pub fn bind_misc_commands(engine_state: &mut EngineState) { + bind_commands!(engine_state, History, Tutor, HistorySession); +} + +pub fn bind_path_commands(engine_state: &mut EngineState) { + bind_commands! { + engine_state, + Path, + PathBasename, + PathDirname, + PathExists, + PathExpand, + PathJoin, + PathParse, + PathRelativeTo, + PathSplit, + PathType, + }; +} + +pub fn bind_system_commands(engine_state: &mut EngineState) { + bind_commands! { + engine_state, + Benchmark, + Complete, + Exec, + External, + NuCheck, + Sys, + Ps, + }; +} + +pub fn bind_string_commands(engine_state: &mut EngineState) { + bind_commands! { + engine_state, + BuildString, + Char, + Decode, + Encode, + DecodeBase64, + EncodeBase64, + DetectColumns, + Format, + FileSize, + Parse, + Size, + Split, + SplitChars, + SplitColumn, + SplitRow, + SplitWords, + Str, + StrCamelCase, + StrCapitalize, + StrCollect, + StrContains, + StrDistance, + StrDowncase, + StrEndswith, + StrJoin, + StrReplace, + StrIndexOf, + StrKebabCase, + StrLength, + StrLpad, + StrPascalCase, + StrReverse, + StrRpad, + StrScreamingSnakeCase, + StrSnakeCase, + StrStartsWith, + StrSubstring, + StrTrim, + StrTitleCase, + StrUpcase + }; +} + +pub fn bind_bit_commands(engine_state: &mut EngineState) { + bind_commands! { + engine_state, + Bits, + BitsAnd, + BitsNot, + BitsOr, + BitsXor, + BitsRotateLeft, + BitsRotateRight, + BitsShiftLeft, + BitsShiftRight, + } +} + +pub fn bind_byte_commands(engine_state: &mut EngineState) { + bind_commands! { + engine_state, + Bytes, + BytesLen, + BytesStartsWith, + BytesEndsWith, + BytesReverse, + BytesReplace, + BytesAdd, + BytesAt, + BytesIndexOf, + BytesCollect, + BytesRemove, + BytesBuild, + } +} + +pub fn bind_file_system_commands(engine_state: &mut EngineState) { + bind_commands! { + engine_state, + Cd, + Cp, + Ls, + Mkdir, + Mv, + Open, + Rm, + Save, + Touch, + Glob, + Watch, + }; +} + +pub fn bind_platform_commands(engine_state: &mut EngineState) { + bind_commands! { + engine_state, + Ansi, + AnsiGradient, + AnsiStrip, + Clear, + Du, + KeybindingsDefault, + Input, + KeybindingsListen, + Keybindings, + Kill, + KeybindingsList, + Sleep, + TermSize, + }; +} + +pub fn bind_date_commands(engine_state: &mut EngineState) { + bind_commands! { + engine_state, + Date, + DateFormat, + DateHumanize, + DateListTimezones, + DateNow, + DateToRecord, + DateToTable, + DateToTimezone, + }; +} + +pub fn bind_shell_commands(engine_state: &mut EngineState) { + bind_commands! { + engine_state, + Enter, + Exit, + GotoShell, + NextShell, + PrevShell, + Shells, + }; +} + +pub fn bind_format_commands(engine_state: &mut EngineState) { + bind_commands! { + engine_state, + From, + FromCsv, + FromEml, + FromIcs, + FromIni, + FromJson, + FromNuon, + FromOds, + FromSsv, + FromToml, + FromTsv, + FromUrl, + FromVcf, + FromXlsx, + FromXml, + FromYaml, + FromYml, + To, + ToCsv, + ToHtml, + ToJson, + ToMd, + ToNuon, + ToText, + ToToml, + ToTsv, + ToCsv, + Touch, + Use, + Upsert, + Where, + ToUrl, + ToXml, + ToYaml, + }; +} + +pub fn bind_viewer_commands(engine_state: &mut EngineState) { + bind_commands! { + engine_state, + Griddle, + Table, + }; +} + +pub fn bind_conversion_commands(engine_state: &mut EngineState) { + bind_commands! { + engine_state, + Fmt, + Into, + IntoBool, + IntoBinary, + IntoDatetime, + IntoDecimal, + IntoDuration, + IntoFilesize, + IntoInt, + IntoString, + }; +} + +pub fn bind_environment_commands(engine_state: &mut EngineState) { + bind_commands! { + engine_state, + Env, + ExportEnv, + LetEnv, + LoadEnv, + SourceEnv, + WithEnv, + // nu config commands have been removed as editing isn't possible + // in this environment + }; +} + +pub fn bind_math_commands(engine_state: &mut EngineState) { + bind_commands! { + engine_state, + Math, + MathAbs, + MathAvg, + MathCeil, + MathEval, + MathFloor, + MathMax, + MathMedian, + MathMin, + MathMode, + MathProduct, + MathRound, + MathSqrt, + MathStddev, + MathSum, + MathVariance, + }; +} + +pub fn bind_network_commands(engine_state: &mut EngineState) { + bind_commands! { + engine_state, + Fetch, + Post, + Url, + UrlHost, + UrlPath, + UrlQuery, + UrlScheme, + Port, + } +} + +pub fn bind_random_commands(engine_state: &mut EngineState) { + bind_commands! { + engine_state, + Random, + RandomBool, + RandomChars, + RandomDecimal, + RandomDice, + RandomInteger, + RandomUuid, + }; +} + +pub fn bind_generator_commands(engine_state: &mut EngineState) { + bind_commands! { + engine_state, + Cal, + Seq, + SeqDate, + SeqChar, + }; +} + +pub fn bind_hash_commands(engine_state: &mut EngineState) { + bind_commands! { + engine_state, + Hash, + HashMd5::default(), + HashSha256::default(), + }; +} + +pub fn bind_experimental_commands(engine_state: &mut EngineState) { + bind_commands! { + engine_state, + ViewSource, + IsAdmin, + }; +} + +#[inline] +fn bind(engine_state: &mut EngineState, bind_fn: F) { + let mut working_set = StateWorkingSet::new(&engine_state); + bind_fn(&mut working_set); + let delta = working_set.render(); + engine_state + .merge_delta(delta) + .expect("Failed to bind commands"); +} diff --git a/src/state_builder/command_group_config.rs b/src/state_builder/command_group_config.rs new file mode 100644 index 0000000..8126acf --- /dev/null +++ b/src/state_builder/command_group_config.rs @@ -0,0 +1,83 @@ +macro_rules! command_group_config { + + ($(#[doc=$doc:literal] $group:ident),*) => { + + /// Enables or disables certain command groups + #[derive(Clone, Debug)] + pub struct CommandGroupConfig { + $(pub(crate) $group: bool,)* + } + + impl CommandGroupConfig { + /// Enables all commands + pub fn all_groups(&mut self, enabled: bool) -> &mut Self { + $( + self.$group = enabled; + )* + + self + } + + $( + paste::item! { + #[doc=$doc] + #[inline] + pub fn [< $group _group>](&mut self, enabled: bool) -> &mut Self { + self.$group = enabled; + + self + } + } + )* + } + } +} + +command_group_config!( + /// Enables core commands + core, + /// Enables filter commands + filter, + /// Enables chart commands + chart, + /// Enables misc commands + misc, + /// Enables commands that allow path manipulation + path, + /// Enables system commands + system, + /// Enables commands to manipulate strings + string, + /// Enables commands to manipulate bits + bit, + /// Enables commands to manipulate bytes + byte, + /// Enables commands that allow file system operations + file_system, + /// Enables commands that allow using shell features like ansi colors + platform, + /// Enables commands that allow datetime manipulation + date, + /// Enables commands that allow creating and switching between nu shell instances + shell, + /// Enables commands that allow parsing from one data format to another + format, + /// Enables commands that allow displaying data in certain viewers like a table or grid + viewer, + /// Enables commands that allow converting from one data format to another + conversion, + /// Enables commands that allow manipulating environment variables + environment, + /// Enables math related commands + math, + /// Enables commands that allow networking + network, + /// Enables commands that generate random values + random, + /// Enables commands that generate values for a given input + generator, + /// Enables commands that work with hash sums + hash, + /// Enables commands that are still experimental like `is-admin` and `view-source` + experimental +); diff --git a/src/state_builder/mod.rs b/src/state_builder/mod.rs new file mode 100644 index 0000000..11b49fc --- /dev/null +++ b/src/state_builder/mod.rs @@ -0,0 +1,64 @@ +use nu_protocol::engine::{EngineState, Stack}; + +mod bindings; +mod command_group_config; +pub use command_group_config::CommandGroupConfig; + +/// Builder to create a new nu engine state +pub struct StateBuilder { + engine_state: EngineState, + stack: Stack, +} + +impl Default for StateBuilder { + fn default() -> Self { + Self { + engine_state: EngineState::new(), + stack: Stack::new(), + } + } +} + +impl StateBuilder { + /// Enables certain command groups specified in the Config on the state + pub fn with_command_groups(&mut self, group_config: CommandGroupConfig) -> &mut Self { + macro_rules! toggle_command_groups { + ($($group:ident),*) => { + paste::item!( + $( + if group_config.$group { + bindings::[](&mut self.engine_state); + } + )* + ) + } + } + + toggle_command_groups!( + core, + filter, + chart, + misc, + path, + system, + string, + bit, + byte, + file_system, + platform, + date, + shell, + format, + viewer, + conversion, + environment, + math, + network, + random, + generator, + hash, + experimental + ); + self + } +}