@@ -22,7 +22,7 @@ fn get_string_input(
2222 input : PipelineData ,
2323 span : nu_protocol:: Span ,
2424) -> Result < String , ShellError > {
25- if let Some ( id) = call. opt :: < String > ( engine_state, stack, 1 ) ? {
25+ if let Some ( id) = call. opt :: < String > ( engine_state, stack, 0 ) ? {
2626 Ok ( id)
2727 } else {
2828 match input {
@@ -44,7 +44,7 @@ fn get_record_input(
4444 input : PipelineData ,
4545 span : nu_protocol:: Span ,
4646) -> Result < Value , ShellError > {
47- if let Some ( arg) = call. opt :: < Value > ( engine_state, stack, 1 ) ? {
47+ if let Some ( arg) = call. opt :: < Value > ( engine_state, stack, 0 ) ? {
4848 Ok ( arg)
4949 } else {
5050 match input {
@@ -107,26 +107,67 @@ impl Command for Scru128Command {
107107
108108 fn signature ( & self ) -> Signature {
109109 Signature :: build ( ".id" )
110+ . input_output_types ( vec ! [ ( Type :: Nothing , Type :: String ) ] )
111+ . category ( Category :: Experimental )
112+ }
113+
114+ fn description ( & self ) -> & str {
115+ "Generate a SCRU128 ID"
116+ }
117+
118+ fn extra_description ( & self ) -> & str {
119+ "Use `.id unpack` to read an id's components, and `.id pack` to build one from them."
120+ }
121+
122+ fn run (
123+ & self ,
124+ _engine_state : & EngineState ,
125+ _stack : & mut Stack ,
126+ call : & Call ,
127+ _input : PipelineData ,
128+ ) -> Result < PipelineData , ShellError > {
129+ let span = call. head ;
130+ let result = crate :: scru128:: generate ( )
131+ . map_err ( |e| scru128_error ( format ! ( "Failed to generate ID: {e}" ) , span) ) ?;
132+ Ok ( PipelineData :: Value ( Value :: string ( result, span) , None ) )
133+ }
134+ }
135+
136+ #[ derive( Clone , Default ) ]
137+ pub struct Scru128UnpackCommand ;
138+
139+ impl Scru128UnpackCommand {
140+ pub fn new ( ) -> Self {
141+ Self
142+ }
143+ }
144+
145+ impl Command for Scru128UnpackCommand {
146+ fn name ( & self ) -> & str {
147+ ".id unpack"
148+ }
149+
150+ fn signature ( & self ) -> Signature {
151+ // Both input types produce a record, so nu knows the output whether
152+ // the id arrives on the pipeline or as the argument. One command per
153+ // subcommand is what makes that possible: a single `.id` taking the
154+ // subcommand as a positional has one output type per input type, and
155+ // no input has to cover generate, unpack and pack at once.
156+ Signature :: build ( ".id unpack" )
110157 . input_output_types ( vec ! [
111- ( Type :: Nothing , Type :: String ) ,
158+ ( Type :: Nothing , Type :: Record ( vec! [ ] . into ( ) ) ) ,
112159 ( Type :: String , Type :: Record ( vec![ ] . into( ) ) ) ,
113- ( Type :: Record ( vec![ ] . into( ) ) , Type :: String ) ,
114160 ] )
115161 . optional (
116- "subcommand " ,
162+ "id " ,
117163 SyntaxShape :: String ,
118- "subcommand: 'unpack' or 'pack'" ,
119- )
120- . optional (
121- "input" ,
122- SyntaxShape :: Any ,
123- "input for subcommand (ID string for unpack, record for pack)" ,
164+ "the id to unpack, if not given on the pipeline" ,
124165 )
125166 . category ( Category :: Experimental )
126167 }
127168
128169 fn description ( & self ) -> & str {
129- "Generate SCRU128 IDs or manipulate them with unpack/pack operations "
170+ "Unpack a SCRU128 ID into its components "
130171 }
131172
132173 fn run (
@@ -137,45 +178,64 @@ impl Command for Scru128Command {
137178 input : PipelineData ,
138179 ) -> Result < PipelineData , ShellError > {
139180 let span = call. head ;
181+ let id_string = get_string_input ( call, engine_state, stack, input, span) ?;
182+ let result = crate :: scru128:: unpack_to_json ( & id_string)
183+ . map_err ( |e| scru128_error ( format ! ( "Failed to unpack ID: {e}" ) , span) ) ?;
140184
141- // Check if there's a subcommand
142- let subcommand : Option < String > = call . opt ( engine_state , stack , 0 ) ? ;
185+ let nu_value = util :: json_to_value ( & result , span ) ;
186+ let nu_value = add_when_field ( nu_value , span ) ;
143187
144- match subcommand. as_deref ( ) {
145- Some ( "unpack" ) => {
146- let id_string = get_string_input ( call, engine_state, stack, input, span) ?;
147- let result = crate :: scru128:: unpack_to_json ( & id_string)
148- . map_err ( |e| scru128_error ( format ! ( "Failed to unpack ID: {e}" ) , span) ) ?;
188+ Ok ( PipelineData :: Value ( nu_value, None ) )
189+ }
190+ }
149191
150- let nu_value = util :: json_to_value ( & result , span ) ;
151- let nu_value = add_when_field ( nu_value , span ) ;
192+ # [ derive ( Clone , Default ) ]
193+ pub struct Scru128PackCommand ;
152194
153- Ok ( PipelineData :: Value ( nu_value, None ) )
154- }
155- Some ( "pack" ) => {
156- let components = get_record_input ( call, engine_state, stack, input, span) ?;
157- let json_value = util:: value_to_json ( & components) ;
158- let json_value = drop_when_field ( json_value) ;
195+ impl Scru128PackCommand {
196+ pub fn new ( ) -> Self {
197+ Self
198+ }
199+ }
159200
160- let result = crate :: scru128:: pack_from_json ( json_value)
161- . map_err ( |e| scru128_error ( format ! ( "Failed to pack components: {e}" ) , span) ) ?;
201+ impl Command for Scru128PackCommand {
202+ fn name ( & self ) -> & str {
203+ ".id pack"
204+ }
162205
163- Ok ( PipelineData :: Value ( Value :: string ( result , span ) , None ) )
164- }
165- Some ( unknown ) => Err ( ShellError :: Generic (
166- GenericError :: new (
167- "Invalid subcommand" ,
168- format ! ( "Unknown subcommand: {unknown}" ) ,
169- span ,
170- )
171- . with_help ( "Available subcommands: unpack, pack" ) ,
172- ) ) ,
173- None => {
174- let result = crate :: scru128 :: generate ( )
175- . map_err ( |e| scru128_error ( format ! ( "Failed to generate ID: {e}" ) , span ) ) ? ;
206+ fn signature ( & self ) -> Signature {
207+ Signature :: build ( ".id pack" )
208+ . input_output_types ( vec ! [
209+ ( Type :: Nothing , Type :: String ) ,
210+ ( Type :: Record ( vec! [ ] . into ( ) ) , Type :: String ) ,
211+ ] )
212+ . optional (
213+ "components" ,
214+ SyntaxShape :: Record ( vec ! [ ] . into ( ) ) ,
215+ "the components to pack, if not given on the pipeline" ,
216+ )
217+ . category ( Category :: Experimental )
218+ }
176219
177- Ok ( PipelineData :: Value ( Value :: string ( result, span) , None ) )
178- }
179- }
220+ fn description ( & self ) -> & str {
221+ "Pack SCRU128 components back into an ID"
222+ }
223+
224+ fn run (
225+ & self ,
226+ engine_state : & EngineState ,
227+ stack : & mut Stack ,
228+ call : & Call ,
229+ input : PipelineData ,
230+ ) -> Result < PipelineData , ShellError > {
231+ let span = call. head ;
232+ let components = get_record_input ( call, engine_state, stack, input, span) ?;
233+ let json_value = util:: value_to_json ( & components) ;
234+ let json_value = drop_when_field ( json_value) ;
235+
236+ let result = crate :: scru128:: pack_from_json ( json_value)
237+ . map_err ( |e| scru128_error ( format ! ( "Failed to pack components: {e}" ) , span) ) ?;
238+
239+ Ok ( PipelineData :: Value ( Value :: string ( result, span) , None ) )
180240 }
181241}
0 commit comments