blob: 78b9343c3000b9bdac61127e86e9965ab730a18a [file] [log] [blame]
// 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