| // Copyright 2022 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/command_context.h" | |
| #include "src/developer/debug/shared/string_util.h" | |
| #include "src/developer/debug/zxdb/client/analytics_reporter.h" | |
| #include "src/developer/debug/zxdb/client/session.h" | |
| #include "src/developer/debug/zxdb/common/ref_ptr_to.h" | |
| #include "src/developer/debug/zxdb/console/console.h" | |
| namespace zxdb { | |
| CommandContext::CommandContext(Console* console) | |
| : weak_console_(console ? console->GetWeakPtr() : nullptr) {} | |
| CommandContext::~CommandContext() { | |
| if (weak_console_) { | |
| weak_console_->context().session()->analytics().ReportCommand(report_); | |
| } | |
| } | |
| void CommandContext::Output(fxl::RefPtr<AsyncOutputBuffer> output) { | |
| if (output->is_complete()) { | |
| // Synchronously available. | |
| Output(output->DestructiveFlatten()); | |
| } else { | |
| // Listen for completion. | |
| AsyncOutputBuffer* output_ptr = output.get(); | |
| output->SetCompletionCallback([this_ref = RefPtrTo(this), output_ptr = output.get()]() { | |
| this_ref->Output(output_ptr->DestructiveFlatten()); | |
| auto found = this_ref->async_output_.find(output_ptr); | |
| FX_DCHECK(found != this_ref->async_output_.end()); | |
| this_ref->async_output_.erase(found); | |
| }); | |
| async_output_[output_ptr] = std::move(output); | |
| } | |
| } | |
| ConsoleContext* CommandContext::GetConsoleContext() const { | |
| if (weak_console_) | |
| return &weak_console_->context(); | |
| return nullptr; | |
| } | |
| void CommandContext::SetConsoleCompletionObserver(fit::deferred_callback observer) { | |
| FX_DCHECK(!console_completion_observer_); | |
| console_completion_observer_ = std::move(observer); | |
| } | |
| void CommandContext::SetCommandReport(CommandReport other) { report_ = std::move(other); } | |
| bool CommandContext::has_error() const { return report_.err.has_error(); } | |
| void CommandContext::SetError(const Err& err) { report_.err = err; } | |
| // ConsoleCommandContext --------------------------------------------------------------------------- | |
| ConsoleCommandContext::ConsoleCommandContext(Console* console, CompletionCallback done) | |
| : CommandContext(console), done_(std::move(done)) {} | |
| ConsoleCommandContext::~ConsoleCommandContext() { | |
| if (done_) | |
| done_(first_error_); | |
| } | |
| void ConsoleCommandContext::Output(const OutputBuffer& output) { | |
| if (console()) | |
| console()->Output(output); | |
| } | |
| void ConsoleCommandContext::ReportError(const Err& err) { | |
| if (!first_error_.has_error()) { | |
| SetError(err); | |
| first_error_ = err; | |
| } | |
| OutputBuffer out; | |
| out.Append(err); | |
| Output(out); | |
| } | |
| // OfflineCommandContext --------------------------------------------------------------------------- | |
| OfflineCommandContext::OfflineCommandContext(Console* console, CompletionCallback done) | |
| : CommandContext(console), done_(std::move(done)) {} | |
| OfflineCommandContext::~OfflineCommandContext() { | |
| if (done_) | |
| done_(std::move(output_), std::move(errors_)); | |
| } | |
| void OfflineCommandContext::Output(const OutputBuffer& output) { output_.Append(output); } | |
| void OfflineCommandContext::ReportError(const Err& err) { | |
| // Set the first one to be reported. | |
| if (errors_.empty()) | |
| SetError(err); | |
| errors_.push_back(err); | |
| OutputBuffer out; | |
| out.Append(err); | |
| if (!debug::StringEndsWith(err.msg(), "\n")) | |
| out.Append("\n"); | |
| Output(out); | |
| } | |
| // NestedCommandContext ---------------------------------------------------------------------------- | |
| NestedCommandContext::NestedCommandContext(fxl::RefPtr<CommandContext> parent, | |
| CompletionCallback cb) | |
| : CommandContext(parent->console()), parent_(std::move(parent)), done_(std::move(cb)) {} | |
| NestedCommandContext::~NestedCommandContext() { | |
| if (done_) | |
| done_(first_error_); | |
| } | |
| void NestedCommandContext::Output(const OutputBuffer& output) { parent_->Output(output); } | |
| void NestedCommandContext::ReportError(const Err& err) { | |
| if (!first_error_.has_error()) { | |
| SetError(err); | |
| first_error_ = err; | |
| } | |
| parent_->ReportError(err); | |
| } | |
| } // namespace zxdb |