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