xs/nu/commands/
last_command.rs1use nu_engine::CallExt;
2use nu_protocol::engine::{Call, Command, EngineState, Stack};
3use nu_protocol::{Category, PipelineData, ShellError, Signature, SyntaxShape, Type, Value};
4
5use crate::nu::util;
6use crate::store::{ReadOptions, Store};
7
8#[derive(Clone)]
9pub struct LastCommand {
10 store: Store,
11}
12
13impl LastCommand {
14 pub fn new(store: Store) -> Self {
15 Self { store }
16 }
17}
18
19impl Command for LastCommand {
20 fn name(&self) -> &str {
21 ".last"
22 }
23
24 fn signature(&self) -> Signature {
25 Signature::build(".last")
26 .input_output_types(vec![(Type::Nothing, Type::Any)])
27 .optional(
28 "topic",
29 SyntaxShape::String,
30 "topic to get most recent frame from (default: all topics)",
31 )
32 .optional(
33 "count",
34 SyntaxShape::Int,
35 "number of frames to return (default: 1)",
36 )
37 .switch(
38 "with-timestamp",
39 "include timestamp extracted from frame ID",
40 None,
41 )
42 .category(Category::Experimental)
43 }
44
45 fn description(&self) -> &str {
46 "get the most recent frame(s) for a topic"
47 }
48
49 fn run(
50 &self,
51 engine_state: &EngineState,
52 stack: &mut Stack,
53 call: &Call,
54 _input: PipelineData,
55 ) -> Result<PipelineData, ShellError> {
56 let raw_topic: Option<String> = call.opt(engine_state, stack, 0)?;
57 let raw_count: Option<i64> = call.opt(engine_state, stack, 1)?;
58 let with_timestamp = call.has_flag(engine_state, stack, "with-timestamp")?;
59 let span = call.head;
60
61 let (topic, n) = match (&raw_topic, raw_count) {
64 (Some(t), None) if t.parse::<usize>().is_ok() => (None, t.parse::<usize>().unwrap()),
65 _ => (raw_topic, raw_count.map(|v| v as usize).unwrap_or(1)),
66 };
67
68 let options = ReadOptions::builder().last(n).maybe_topic(topic).build();
69
70 let frames: Vec<Value> = self
71 .store
72 .read_sync(options)
73 .map(|frame| util::frame_to_value(&frame, span, with_timestamp))
74 .collect();
75
76 if frames.is_empty() {
77 Ok(PipelineData::Empty)
78 } else if frames.len() == 1 {
79 Ok(PipelineData::Value(
80 frames.into_iter().next().unwrap(),
81 None,
82 ))
83 } else {
84 Ok(PipelineData::Value(Value::list(frames, span), None))
85 }
86 }
87}