| // Copyright 2018 The Fuchsia Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "src/developer/debug/zxdb/console/actions.h" | 
 |  | 
 | #include "src/developer/debug/shared/message_loop.h" | 
 | #include "src/lib/files/file.h" | 
 | #include "src/lib/files/path.h" | 
 | #include "src/lib/fxl/strings/split_string.h" | 
 | #include "src/lib/fxl/strings/string_printf.h" | 
 |  | 
 | namespace zxdb { | 
 |  | 
 | namespace { | 
 |  | 
 | using Option = fxl::CommandLine::Option; | 
 |  | 
 | }  // namespace | 
 |  | 
 | // Action ---------------------------------------------------------------------- | 
 |  | 
 | Action::Action() = default; | 
 | Action::Action(std::string name, Action::ActionFunction action) | 
 |     : name_(name), action_(std::move(action)) {} | 
 |  | 
 | Action::Action(Action&&) = default; | 
 | Action& Action::operator=(Action&& other) { | 
 |   this->name_ = std::move(other.name_); | 
 |   this->action_ = std::move(other.action_); | 
 |   return *this; | 
 | } | 
 |  | 
 | void Action::operator()(const Session& session, Console* console) const { | 
 |   // The next_action_ chaining will take care of calling the following command | 
 |   // when the time is due. | 
 |   action_(*this, session, console); | 
 | } | 
 |  | 
 | // ActionFlow ------------------------------------------------------------------ | 
 |  | 
 | void ActionFlow::ScheduleActions(std::vector<Action>&& actions, const Session* session, | 
 |                                  Console* console, Callback callback) { | 
 |   // If there are no actions, we schedule the callback. | 
 |   if (actions.empty()) { | 
 |     callback_(Err()); | 
 |     return; | 
 |   } | 
 |  | 
 |   // We store the parameters as they will be used in the future. | 
 |   flow_ = std::move(actions); | 
 |   session_ = session; | 
 |   console_ = console; | 
 |   callback_ = std::move(callback); | 
 |  | 
 |   // We schedule the first action to run | 
 |   debug::MessageLoop::Current()->PostTask(FROM_HERE, [&]() { | 
 |     const auto& action = flow_.front(); | 
 |     action(*session_, console_); | 
 |   }); | 
 | } | 
 |  | 
 | ActionFlow& ActionFlow::Singleton() { | 
 |   // We use the global callback function so that the user doesn't have to | 
 |   // worry about tracking an instance. | 
 |   static ActionFlow flow; | 
 |   return flow; | 
 | } | 
 |  | 
 | ActionFlow::ActionFlow() = default; | 
 |  | 
 | void ActionFlow::PostActionCallback(Err err) { | 
 |   ActionFlow& flow = ActionFlow::Singleton(); | 
 |   // We log the callback | 
 |   flow.callbacks_.push_back(err); | 
 |  | 
 |   // If the command wants us to stop processing, we call the complete callback. | 
 |   if ((err.type() == ErrType::kCanceled) || err.has_error()) { | 
 |     flow.callback_(err); | 
 |     return; | 
 |   } | 
 |  | 
 |   flow.current_action_index_++; | 
 |   // In no more actions available, communicate to caller. | 
 |   if (flow.current_action_index_ >= flow.flow_.size()) { | 
 |     flow.callback_(Err()); | 
 |     return; | 
 |   } | 
 |  | 
 |   // Schedule the next action. | 
 |   const auto& next_action = flow.current_action(); | 
 |   debug::MessageLoop::Current()->PostTask(FROM_HERE, | 
 |                                           [&]() { next_action(*flow.session_, flow.console_); }); | 
 | } | 
 |  | 
 | void ActionFlow::Clear() { | 
 |   flow_.clear(); | 
 |   current_action_index_ = 0; | 
 |   session_ = nullptr; | 
 |   console_ = nullptr; | 
 |   callback_ = nullptr; | 
 |   callbacks_.clear(); | 
 | } | 
 |  | 
 | std::vector<Action> CommandsToActions(const std::string& input) { | 
 |   auto commands = fxl::SplitStringCopy(input, "\n", fxl::kTrimWhitespace, fxl::kSplitWantNonEmpty); | 
 |   std::vector<Action> result; | 
 |   for (size_t i = 0; i < commands.size(); i++) { | 
 |     result.push_back(Action( | 
 |         commands[i], | 
 |         [&, cmd = commands[i]](const Action& action, const Session& session, Console* console) { | 
 |           console->ProcessInputLine(cmd.c_str(), ActionFlow::PostActionCallback); | 
 |         })); | 
 |   } | 
 |   return result; | 
 | } | 
 |  | 
 | Err ScriptFileToActions(const std::string& path, std::vector<Action>* actions) { | 
 |   std::string contents; | 
 |   if (!files::ReadFileToString(files::AbsolutePath(path), &contents)) | 
 |     return Err(fxl::StringPrintf("Could not read file \"%s\"", path.c_str())); | 
 |  | 
 |   *actions = CommandsToActions(contents); | 
 |   return Err(); | 
 | } | 
 |  | 
 | }  // namespace zxdb |