1*af732203SDimitry Andric #include "CommandObjectSession.h"
2*af732203SDimitry Andric #include "lldb/Host/OptionParser.h"
3*af732203SDimitry Andric #include "lldb/Interpreter/CommandInterpreter.h"
4*af732203SDimitry Andric #include "lldb/Interpreter/CommandReturnObject.h"
5*af732203SDimitry Andric #include "lldb/Interpreter/OptionArgParser.h"
6*af732203SDimitry Andric #include "lldb/Interpreter/OptionValue.h"
7*af732203SDimitry Andric #include "lldb/Interpreter/OptionValueBoolean.h"
8*af732203SDimitry Andric #include "lldb/Interpreter/OptionValueString.h"
9*af732203SDimitry Andric #include "lldb/Interpreter/OptionValueUInt64.h"
10*af732203SDimitry Andric #include "lldb/Interpreter/Options.h"
11*af732203SDimitry Andric 
12*af732203SDimitry Andric using namespace lldb;
13*af732203SDimitry Andric using namespace lldb_private;
14*af732203SDimitry Andric 
15*af732203SDimitry Andric class CommandObjectSessionSave : public CommandObjectParsed {
16*af732203SDimitry Andric public:
CommandObjectSessionSave(CommandInterpreter & interpreter)17*af732203SDimitry Andric   CommandObjectSessionSave(CommandInterpreter &interpreter)
18*af732203SDimitry Andric       : CommandObjectParsed(interpreter, "session save",
19*af732203SDimitry Andric                             "Save the current session transcripts to a file.\n"
20*af732203SDimitry Andric                             "If no file if specified, transcripts will be "
21*af732203SDimitry Andric                             "saved to a temporary file.",
22*af732203SDimitry Andric                             "session save [file]") {
23*af732203SDimitry Andric     CommandArgumentEntry arg1;
24*af732203SDimitry Andric     arg1.emplace_back(eArgTypePath, eArgRepeatOptional);
25*af732203SDimitry Andric     m_arguments.push_back(arg1);
26*af732203SDimitry Andric   }
27*af732203SDimitry Andric 
28*af732203SDimitry Andric   ~CommandObjectSessionSave() override = default;
29*af732203SDimitry Andric 
30*af732203SDimitry Andric   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)31*af732203SDimitry Andric   HandleArgumentCompletion(CompletionRequest &request,
32*af732203SDimitry Andric                            OptionElementVector &opt_element_vector) override {
33*af732203SDimitry Andric     CommandCompletions::InvokeCommonCompletionCallbacks(
34*af732203SDimitry Andric         GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion,
35*af732203SDimitry Andric         request, nullptr);
36*af732203SDimitry Andric   }
37*af732203SDimitry Andric 
38*af732203SDimitry Andric protected:
DoExecute(Args & args,CommandReturnObject & result)39*af732203SDimitry Andric   bool DoExecute(Args &args, CommandReturnObject &result) override {
40*af732203SDimitry Andric     llvm::StringRef file_path;
41*af732203SDimitry Andric 
42*af732203SDimitry Andric     if (!args.empty())
43*af732203SDimitry Andric       file_path = args[0].ref();
44*af732203SDimitry Andric 
45*af732203SDimitry Andric     if (m_interpreter.SaveTranscript(result, file_path.str()))
46*af732203SDimitry Andric       result.SetStatus(eReturnStatusSuccessFinishNoResult);
47*af732203SDimitry Andric     else
48*af732203SDimitry Andric       result.SetStatus(eReturnStatusFailed);
49*af732203SDimitry Andric     return result.Succeeded();
50*af732203SDimitry Andric   }
51*af732203SDimitry Andric };
52*af732203SDimitry Andric 
53*af732203SDimitry Andric #define LLDB_OPTIONS_history
54*af732203SDimitry Andric #include "CommandOptions.inc"
55*af732203SDimitry Andric 
56*af732203SDimitry Andric class CommandObjectSessionHistory : public CommandObjectParsed {
57*af732203SDimitry Andric public:
CommandObjectSessionHistory(CommandInterpreter & interpreter)58*af732203SDimitry Andric   CommandObjectSessionHistory(CommandInterpreter &interpreter)
59*af732203SDimitry Andric       : CommandObjectParsed(interpreter, "session history",
60*af732203SDimitry Andric                             "Dump the history of commands in this session.\n"
61*af732203SDimitry Andric                             "Commands in the history list can be run again "
62*af732203SDimitry Andric                             "using \"!<INDEX>\".   \"!-<OFFSET>\" will re-run "
63*af732203SDimitry Andric                             "the command that is <OFFSET> commands from the end"
64*af732203SDimitry Andric                             " of the list (counting the current command).",
65*af732203SDimitry Andric                             nullptr),
66*af732203SDimitry Andric         m_options() {}
67*af732203SDimitry Andric 
68*af732203SDimitry Andric   ~CommandObjectSessionHistory() override = default;
69*af732203SDimitry Andric 
GetOptions()70*af732203SDimitry Andric   Options *GetOptions() override { return &m_options; }
71*af732203SDimitry Andric 
72*af732203SDimitry Andric protected:
73*af732203SDimitry Andric   class CommandOptions : public Options {
74*af732203SDimitry Andric   public:
CommandOptions()75*af732203SDimitry Andric     CommandOptions()
76*af732203SDimitry Andric         : Options(), m_start_idx(0), m_stop_idx(0), m_count(0), m_clear(false) {
77*af732203SDimitry Andric     }
78*af732203SDimitry Andric 
79*af732203SDimitry Andric     ~CommandOptions() override = default;
80*af732203SDimitry Andric 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)81*af732203SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
82*af732203SDimitry Andric                           ExecutionContext *execution_context) override {
83*af732203SDimitry Andric       Status error;
84*af732203SDimitry Andric       const int short_option = m_getopt_table[option_idx].val;
85*af732203SDimitry Andric 
86*af732203SDimitry Andric       switch (short_option) {
87*af732203SDimitry Andric       case 'c':
88*af732203SDimitry Andric         error = m_count.SetValueFromString(option_arg, eVarSetOperationAssign);
89*af732203SDimitry Andric         break;
90*af732203SDimitry Andric       case 's':
91*af732203SDimitry Andric         if (option_arg == "end") {
92*af732203SDimitry Andric           m_start_idx.SetCurrentValue(UINT64_MAX);
93*af732203SDimitry Andric           m_start_idx.SetOptionWasSet();
94*af732203SDimitry Andric         } else
95*af732203SDimitry Andric           error = m_start_idx.SetValueFromString(option_arg,
96*af732203SDimitry Andric                                                  eVarSetOperationAssign);
97*af732203SDimitry Andric         break;
98*af732203SDimitry Andric       case 'e':
99*af732203SDimitry Andric         error =
100*af732203SDimitry Andric             m_stop_idx.SetValueFromString(option_arg, eVarSetOperationAssign);
101*af732203SDimitry Andric         break;
102*af732203SDimitry Andric       case 'C':
103*af732203SDimitry Andric         m_clear.SetCurrentValue(true);
104*af732203SDimitry Andric         m_clear.SetOptionWasSet();
105*af732203SDimitry Andric         break;
106*af732203SDimitry Andric       default:
107*af732203SDimitry Andric         llvm_unreachable("Unimplemented option");
108*af732203SDimitry Andric       }
109*af732203SDimitry Andric 
110*af732203SDimitry Andric       return error;
111*af732203SDimitry Andric     }
112*af732203SDimitry Andric 
OptionParsingStarting(ExecutionContext * execution_context)113*af732203SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
114*af732203SDimitry Andric       m_start_idx.Clear();
115*af732203SDimitry Andric       m_stop_idx.Clear();
116*af732203SDimitry Andric       m_count.Clear();
117*af732203SDimitry Andric       m_clear.Clear();
118*af732203SDimitry Andric     }
119*af732203SDimitry Andric 
GetDefinitions()120*af732203SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
121*af732203SDimitry Andric       return llvm::makeArrayRef(g_history_options);
122*af732203SDimitry Andric     }
123*af732203SDimitry Andric 
124*af732203SDimitry Andric     // Instance variables to hold the values for command options.
125*af732203SDimitry Andric 
126*af732203SDimitry Andric     OptionValueUInt64 m_start_idx;
127*af732203SDimitry Andric     OptionValueUInt64 m_stop_idx;
128*af732203SDimitry Andric     OptionValueUInt64 m_count;
129*af732203SDimitry Andric     OptionValueBoolean m_clear;
130*af732203SDimitry Andric   };
131*af732203SDimitry Andric 
DoExecute(Args & command,CommandReturnObject & result)132*af732203SDimitry Andric   bool DoExecute(Args &command, CommandReturnObject &result) override {
133*af732203SDimitry Andric     if (m_options.m_clear.GetCurrentValue() &&
134*af732203SDimitry Andric         m_options.m_clear.OptionWasSet()) {
135*af732203SDimitry Andric       m_interpreter.GetCommandHistory().Clear();
136*af732203SDimitry Andric       result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult);
137*af732203SDimitry Andric     } else {
138*af732203SDimitry Andric       if (m_options.m_start_idx.OptionWasSet() &&
139*af732203SDimitry Andric           m_options.m_stop_idx.OptionWasSet() &&
140*af732203SDimitry Andric           m_options.m_count.OptionWasSet()) {
141*af732203SDimitry Andric         result.AppendError("--count, --start-index and --end-index cannot be "
142*af732203SDimitry Andric                            "all specified in the same invocation");
143*af732203SDimitry Andric         result.SetStatus(lldb::eReturnStatusFailed);
144*af732203SDimitry Andric       } else {
145*af732203SDimitry Andric         std::pair<bool, uint64_t> start_idx(
146*af732203SDimitry Andric             m_options.m_start_idx.OptionWasSet(),
147*af732203SDimitry Andric             m_options.m_start_idx.GetCurrentValue());
148*af732203SDimitry Andric         std::pair<bool, uint64_t> stop_idx(
149*af732203SDimitry Andric             m_options.m_stop_idx.OptionWasSet(),
150*af732203SDimitry Andric             m_options.m_stop_idx.GetCurrentValue());
151*af732203SDimitry Andric         std::pair<bool, uint64_t> count(m_options.m_count.OptionWasSet(),
152*af732203SDimitry Andric                                         m_options.m_count.GetCurrentValue());
153*af732203SDimitry Andric 
154*af732203SDimitry Andric         const CommandHistory &history(m_interpreter.GetCommandHistory());
155*af732203SDimitry Andric 
156*af732203SDimitry Andric         if (start_idx.first && start_idx.second == UINT64_MAX) {
157*af732203SDimitry Andric           if (count.first) {
158*af732203SDimitry Andric             start_idx.second = history.GetSize() - count.second;
159*af732203SDimitry Andric             stop_idx.second = history.GetSize() - 1;
160*af732203SDimitry Andric           } else if (stop_idx.first) {
161*af732203SDimitry Andric             start_idx.second = stop_idx.second;
162*af732203SDimitry Andric             stop_idx.second = history.GetSize() - 1;
163*af732203SDimitry Andric           } else {
164*af732203SDimitry Andric             start_idx.second = 0;
165*af732203SDimitry Andric             stop_idx.second = history.GetSize() - 1;
166*af732203SDimitry Andric           }
167*af732203SDimitry Andric         } else {
168*af732203SDimitry Andric           if (!start_idx.first && !stop_idx.first && !count.first) {
169*af732203SDimitry Andric             start_idx.second = 0;
170*af732203SDimitry Andric             stop_idx.second = history.GetSize() - 1;
171*af732203SDimitry Andric           } else if (start_idx.first) {
172*af732203SDimitry Andric             if (count.first) {
173*af732203SDimitry Andric               stop_idx.second = start_idx.second + count.second - 1;
174*af732203SDimitry Andric             } else if (!stop_idx.first) {
175*af732203SDimitry Andric               stop_idx.second = history.GetSize() - 1;
176*af732203SDimitry Andric             }
177*af732203SDimitry Andric           } else if (stop_idx.first) {
178*af732203SDimitry Andric             if (count.first) {
179*af732203SDimitry Andric               if (stop_idx.second >= count.second)
180*af732203SDimitry Andric                 start_idx.second = stop_idx.second - count.second + 1;
181*af732203SDimitry Andric               else
182*af732203SDimitry Andric                 start_idx.second = 0;
183*af732203SDimitry Andric             }
184*af732203SDimitry Andric           } else /* if (count.first) */
185*af732203SDimitry Andric           {
186*af732203SDimitry Andric             start_idx.second = 0;
187*af732203SDimitry Andric             stop_idx.second = count.second - 1;
188*af732203SDimitry Andric           }
189*af732203SDimitry Andric         }
190*af732203SDimitry Andric         history.Dump(result.GetOutputStream(), start_idx.second,
191*af732203SDimitry Andric                      stop_idx.second);
192*af732203SDimitry Andric       }
193*af732203SDimitry Andric     }
194*af732203SDimitry Andric     return result.Succeeded();
195*af732203SDimitry Andric   }
196*af732203SDimitry Andric 
197*af732203SDimitry Andric   CommandOptions m_options;
198*af732203SDimitry Andric };
199*af732203SDimitry Andric 
CommandObjectSession(CommandInterpreter & interpreter)200*af732203SDimitry Andric CommandObjectSession::CommandObjectSession(CommandInterpreter &interpreter)
201*af732203SDimitry Andric     : CommandObjectMultiword(interpreter, "session",
202*af732203SDimitry Andric                              "Commands controlling LLDB session.",
203*af732203SDimitry Andric                              "session <subcommand> [<command-options>]") {
204*af732203SDimitry Andric   LoadSubCommand("save",
205*af732203SDimitry Andric                  CommandObjectSP(new CommandObjectSessionSave(interpreter)));
206*af732203SDimitry Andric   LoadSubCommand("history",
207*af732203SDimitry Andric                  CommandObjectSP(new CommandObjectSessionHistory(interpreter)));
208*af732203SDimitry Andric }
209