// Copyright 2019 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/format/format.h"

#include "src/developer/debug/shared/string_util.h"
#include "src/developer/debug/zxdb/common/ref_ptr_to.h"
#include "src/developer/debug/zxdb/expr/format.h"
#include "src/developer/debug/zxdb/expr/format_node.h"
#include "src/developer/debug/zxdb/format/format_name.h"
#include "src/developer/debug/zxdb/format/string_util.h"
#include "src/developer/debug/zxdb/symbols/variable.h"
#include "src/lib/fxl/memory/ref_counted.h"

namespace zxdb {

namespace {

// Provides a way to execute a single callback when a set of deferred actions is complete.
class AggregateDeferredCallback : public fxl::RefCountedThreadSafe<AggregateDeferredCallback> {
 public:
  // Returns a subordinate callback, the completion of which will contribute to the outer callback.
  fit::deferred_callback MakeSubordinate() {
    // This callback exists only to hold the bound reference to the outer callback.
    return fit::defer_callback([ref = RefPtrTo(this)]() {});
  }

 private:
  FRIEND_REF_COUNTED_THREAD_SAFE(AggregateDeferredCallback);
  FRIEND_MAKE_REF_COUNTED(AggregateDeferredCallback);

  explicit AggregateDeferredCallback(fit::deferred_callback cb) : outer_(std::move(cb)) {}

  fit::deferred_callback outer_;
};

// Some state needs to be tracked recursively as we iterate through the tree.
struct RecursiveState {
  explicit RecursiveState(const FormatBufferOptions& opts) : options(opts) {}

  // Returns a modified version of the state for one additional level of recursion, advancing
  // both indent and tree depth.
  RecursiveState Advance() const;

  // Advances the tree depth but not the visual nesting depth.
  RecursiveState AdvanceNoIndent() const;

  // Returns true if the combination of options means the type should be shown.
  bool TypeForcedOn() const {
    return !inhibit_one_type && options.verbosity == FormatBufferOptions::Verbosity::kAllTypes;
  }

  // Returns true if the current item should be formatted in expanded tree mode or in one line.
  bool ShouldExpand() const {
    return options.wrapping == FormatBufferOptions::Wrapping::kExpanded ||
           (options.wrapping == FormatBufferOptions::Wrapping::kSmart && smart_indent_is_expanded);
  }

  int GetIndentAmount() const {
    if (!ShouldExpand())
      return 0;
    return options.indent_amount * indent_depth;
  }

  // Returns the string to indent a node at the given level.
  std::string GetIndentString() const { return std::string(GetIndentAmount(), ' '); }

  // Returns true if items at this level should be elided because the printing depth is too deep.
  bool DepthTooDeep() const { return tree_depth >= options.max_depth; }

  const FormatBufferOptions options;

  // Forces various information off for exactly one level of printing. Use for array printing, for
  // example, to avoid duplicating the type information for every entry.
  bool inhibit_one_name = false;
  bool inhibit_one_type = false;

  // How deep in the node tree we are, the top level is 0.
  int tree_depth = 0;

  // How many levels of visual indent we are, the top level is 0. This is often the same as the
  // tree depth but some things like pointer resolution are different levels of the tree but
  // are presented as the same visual level.
  int indent_depth = 0;

  // Number of pointers we've expanded so far in this level of recursion.
  int pointer_depth = 0;

  // Controls what mode of smart indenting (single-line or expanded) the current node should be
  // formatted in.
  bool smart_indent_is_expanded = true;
};

RecursiveState RecursiveState::Advance() const {
  RecursiveState result = *this;
  result.inhibit_one_name = false;
  result.inhibit_one_type = false;

  result.tree_depth++;
  result.indent_depth++;

  return result;
}

RecursiveState RecursiveState::AdvanceNoIndent() const {
  RecursiveState result = Advance();
  result.indent_depth--;  // Undo visual indent from Advance().
  return result;
}

void RecursiveDescribeFormatTreeNode(FormatNode* node, fxl::RefPtr<EvalContext> context,
                                     const RecursiveState& state, fit::deferred_callback cb) {
  if (state.tree_depth == state.options.max_depth)
    return;  // Reached max depth, give up.

  auto on_complete = fit::defer_callback([weak_node = node->GetWeakPtr(), context,
                                          cb = std::move(cb), state = state.Advance()]() mutable {
    // Description is complete.
    if (!weak_node || weak_node->children().empty())
      return;

    // Check for pointer expansion to avoid recursing into too many.
    if (weak_node->description_kind() == FormatNode::kPointer) {
      if (state.pointer_depth == state.options.pointer_expand_depth)
        return;  // Don't recurse into another level of pointer.
      state.pointer_depth++;
    }

    // Recurse into children.
    auto aggregator = fxl::MakeRefCounted<AggregateDeferredCallback>(std::move(cb));
    for (const auto& child : weak_node->children())
      RecursiveDescribeFormatTreeNode(child.get(), context, state, aggregator->MakeSubordinate());
  });

  if (node->state() != FormatNode::kDescribed)
    FillFormatNodeDescription(node, state.options, context, std::move(on_complete));
}

bool IsRust(const FormatNode* node) {
  if (!node->value().type())
    return false;
  return node->value().type()->GetLanguage() == DwarfLang::kRust;
}

// Forward decls, see the implementation for comments.
OutputBuffer DoFormatTreeNode(const FormatNode* node, const RecursiveState& state,
                              int line_start_char);
OutputBuffer DoFormatNodeOneWay(const FormatNode* node, const RecursiveState& state,
                                int indent_amount);

// Get a possibly-elided version of the type name for a medium verbosity level.
std::string GetElidedTypeName(const RecursiveState& state, const std::string& name) {
  if (state.options.verbosity != FormatBufferOptions::Verbosity::kMinimal)
    return name;  // No eliding except in minimal mode.

  // Pick different thresholds depending on if we're doing multiline or not. The threshold and
  // the eliding length are different so we don't elide one or two characters.
  size_t always_allow_below = 64;
  size_t elide_to = 50;
  if (!state.ShouldExpand()) {
    always_allow_below /= 2;
    elide_to /= 2;
  }

  // Names shorter than this are always displayed in full.
  if (name.size() <= always_allow_below)
    return name;

  return name.substr(0, elide_to) + "…";
}

// Rust collections (structs) normally have the type name before the bracket like "MyStruct{...}".
// This function appends this name.
//
// For some struct types including common standard containers the names can get very long. As a
// result in "minimal" verbosity mode we never show the namespaces and also elide template
// parameters when the template is long.
void AppendRustCollectionName(const FormatNode* node, const RecursiveState& state,
                              OutputBuffer* out) {
  if (!IsRust(node) || !node->value().type())
    return;

  if (state.options.verbosity != FormatBufferOptions::Verbosity::kMinimal) {
    // Use the full identifier name in the more verbose modes.
    FormatIdentifierOptions opts;
    opts.show_global_qual = false;
    opts.elide_templates = false;
    opts.bold_last = false;
    out->Append(FormatIdentifier(node->value().type()->GetIdentifier(), opts));
    return;
  }

  // Special-case "Vec" with the macro that's normally used and omit the type.
  if (debug::StringStartsWith(node->type(), "alloc::vec::Vec<")) {
    out->Append("vec!");
    return;
  }

  // In minimal mode, extract just the last component of the identifier.
  const Identifier& ident = node->value().type()->GetIdentifier();
  if (ident.empty())
    return;
  ParsedIdentifier parsed =
      ToParsedIdentifier(Identifier(IdentifierQualification::kRelative, ident.components().back()));

  if (parsed.components()[0].has_template()) {
    // Some containers have very long template names. Since Rust structs always have the name, the
    // lengths can get a little bit nuts. Elide the template contents when too long by converting
    // all template parameters to one string and eliding.
    const auto& template_contents = parsed.components()[0].template_contents();
    std::string template_string;
    for (size_t i = 0; i < template_contents.size(); i++) {
      if (i > 0)
        template_string += ", ";
      template_string += template_contents[i];
    }

    // Replace the template parameters with our single string, elided if necessary.
    parsed.components()[0] = ParsedIdentifierComponent(parsed.components()[0].name(),
                                                       {GetElidedTypeName(state, template_string)});
  }

  FormatIdentifierOptions ident_opts;
  ident_opts.show_global_qual = false;
  ident_opts.elide_templates = false;
  ident_opts.bold_last = false;
  out->Append(FormatIdentifier(parsed, ident_opts));
}

// Writes the suffix for when there are multiple items in a collection or an array.
void AppendItemSuffix(const RecursiveState& state, bool last_item, OutputBuffer* out) {
  if (state.ShouldExpand())
    out->Append("\n");  // Expanded children always end with a newline.
  else if (!last_item)
    out->Append(Syntax::kOperatorNormal, ", ");  // Get commas for everything but the last.
}

// Returns true if type information should be displayed before the variable name, as in
//   <TYPE> name = value
bool ShouldPrependTypeNameBeforeName(const FormatNode* node, const RecursiveState& state) {
  if (!state.TypeForcedOn())
    return false;  // Never show types unless requested.

  if (node->type().empty())
    return false;  // Don't show empty types.

  if (!IsRust(node))
    return true;  // Non-Rust code always gets the type.

  if (node->description_kind() == FormatNode::kCollection ||
      node->description_kind() == FormatNode::kArray ||
      node->description_kind() == FormatNode::kRustTuple ||
      node->description_kind() == FormatNode::kRustTupleStruct) {
    // Rust structs and tuple structs are special. They encode the type after the variable, so:
    // "foo = StructName{...}" and we don't want to prepend it before "foo". But this doesn't happen
    // for tuples.
    //
    // Rust tuples don't have the name shown ever. The individual members will have their types
    // displayed which will encode the type of the tuple.
    return false;
  }

  return true;
}

// Appends the formatted name and "=" as needed by this node.
void AppendNodeNameAndType(const FormatNode* node, const RecursiveState& state, OutputBuffer* out) {
  if (ShouldPrependTypeNameBeforeName(node, state)) {
    out->Append(Syntax::kOperatorDim, "(");
    out->Append(Syntax::kComment, node->type());
    out->Append(Syntax::kOperatorDim, ") ");
  }

  if (!state.inhibit_one_name && !node->name().empty()) {
    // Node name. Base class names are less important so get dimmed. Especially STL base classes
    // can get very long so we also elide them unless verbose mode is turned on.
    if (node->child_kind() == FormatNode::kBaseClass) {
      out->Append(Syntax::kComment, GetElidedTypeName(state, node->name()));
    } else {
      // Normal variable-style node name.
      out->Append(Syntax::kVariable, node->name());
    }

    // Rust uses colons for most things, while C uses equals. The exception for Rust is local
    // variables which "=" to better match how the variables are declared.
    if (IsRust(node) && node->child_kind() != FormatNode::kVariable)
      out->Append(Syntax::kOperatorNormal, ": ");
    else
      out->Append(Syntax::kOperatorNormal, " = ");
  }
}

// Writes the node's children. The caller sets up how it wants the children to be formatted by
// passing both the recursive state for the node, and the state it wants to use for the children.
//
// The opening and closing strings are used to wrap the contents, e.g. "{" and "}". If these are
// empty it's assumed that the first line doesn't need a newline after it in multiline mode
// (normally the opening character would be followed by a newline and an indent in multiline mode).
void AppendNodeChildren(const FormatNode* node, const RecursiveState& node_state,
                        const std::string& opening, const std::string& closing,
                        const RecursiveState& child_state, OutputBuffer* out) {
  out->Append(Syntax::kOperatorNormal, opening);

  if (child_state.DepthTooDeep()) {
    // Don't print the child names if those children will be elided. Otherwise this prints a
    // whole struct out with no data: "{foo=…, bar=…, baz=…}" which is wasteful of space and not
    // helpful.
    out->Append(Syntax::kComment, "…");
    out->Append(Syntax::kOperatorNormal, closing);
    return;
  }

  // Special-case empty ones because we never want wrapping.
  if (node->children().empty()) {
    out->Append(Syntax::kOperatorNormal, closing);
    return;
  }

  if (!opening.empty() && node_state.ShouldExpand())
    out->Append("\n");

  int child_indent = child_state.GetIndentAmount();
  for (size_t i = 0; i < node->children().size(); i++) {
    const FormatNode* child = node->children()[i].get();

    if (child->state() == FormatNode::kEmpty) {
      // Arrays can have "empty" nodes which use the name to indicate clipping ("...").
      if (!child->name().empty())
        out->Append(Syntax::kComment, child->name());
    } else {
      out->Append(DoFormatTreeNode(child, child_state, child_indent));
    }

    // Separator (comma or newline).
    AppendItemSuffix(node_state, i + 1 == node->children().size(), out);
  }

  out->Append(Syntax::kOperatorNormal, node_state.GetIndentString() + closing);
}

OutputBuffer DoFormatArrayOrTupleNode(const FormatNode* node, const RecursiveState& state) {
  OutputBuffer out;

  RecursiveState child_state = state.Advance();
  // In multiline mode, show the names of the array indices ("[0] = ...").
  child_state.inhibit_one_name = !state.ShouldExpand();

  if (node->description_kind() == FormatNode::kArray) {
    // Arrays all have the same type so don't show the type for every child.
    child_state.inhibit_one_type = true;

    if (IsRust(node)) {
      // Rust sequences use "[...]".
      AppendRustCollectionName(node, state, &out);
      AppendNodeChildren(node, state, "[", "]", child_state, &out);
    } else {
      AppendNodeChildren(node, state, "{", "}", child_state, &out);
    }
  } else {
    // Rust tuple or tuple struct. These should not be empty.
    if (node->description_kind() == FormatNode::kRustTupleStruct) {
      // Tuple structs get the name, regular tuples have none.
      AppendRustCollectionName(node, state, &out);
    }

    // Tuples of length 1 never show the child names, even in expanded mode because it's not
    // helpful and looks weird.o
    //
    // We show the indices of tuple members in expanded mode for larger tuples even though
    // Rust wouldn't do that because highly nested data structures can get very difficult to
    // follow. Something like a closure or a generator can go on for >100 lines and have many
    // tuple members (>10). Without these indices the structure is not interpretable. This doesn't
    // come up when using println in the language very often because normally these types of
    // tuples are not printed.
    if (node->children().size() == 1)
      child_state.inhibit_one_name = true;

    AppendNodeChildren(node, state, "(", ")", child_state, &out);
  }

  return out;
}

OutputBuffer DoFormatCollectionNode(const FormatNode* node, const RecursiveState& state) {
  OutputBuffer out;

  // Rust structs are always prefixed with the struct name. This does nothing for non-Rust.
  AppendRustCollectionName(node, state, &out);

  // Special-case empty collections because we never want wrapping.
  if (node->children().empty()) {
    // Rust empty structs have no brackets.
    if (!IsRust(node))
      out.Append(Syntax::kOperatorNormal, "{}");
    return out;
  }

  AppendNodeChildren(node, state, "{", "}", state.Advance(), &out);
  return out;
}

OutputBuffer DoFormatPointerNode(const FormatNode* node, const RecursiveState& state) {
  OutputBuffer out;

  // When type information is forced on, the type will have already been printed. Otherwise we print
  // a "(*)" to indicate the value is a pointer.
  if (!state.TypeForcedOn())
    out.Append(Syntax::kOperatorDim, "(*)");

  // Pointers will have a child node that expands to the pointed-to value. If this is in a
  // "described" state with no error, then show the data.
  //
  // Don't show errors dereferencing pointers here since for long structure listings with
  // potentially multiple bad pointers, these get very verbose. The user can print the specific
  // value and see the error if desired.
  if (node->children().empty() || node->children()[0]->state() != FormatNode::kDescribed ||
      node->children()[0]->err().has_error()) {
    // Just have the pointer address.
    out.Append(node->description());
  } else {
    // Have the pointed-to data, dim the address and show the data. Omit types because we already
    // printed the pointer type. We do not want to indent another level.
    RecursiveState child_state = state.AdvanceNoIndent();
    child_state.inhibit_one_name = true;
    child_state.inhibit_one_type = true;

    out.Append(Syntax::kComment, node->description() + " " + GetRightArrow() + " ");
    // Use the "one way" version to propagate our formatting mode. This node cant't get different
    // formatting than its child.
    out.Append(DoFormatNodeOneWay(node->children()[0].get(), child_state, 0));
  }
  return out;
}

OutputBuffer DoFormatReferenceNode(const FormatNode* node, const RecursiveState& state) {
  // References will have a child node that expands to the referenced value. If this is in a
  // "described" state, then we have the data and should show it. Otherwise omit this.
  if (node->children().empty() || node->children()[0]->state() != FormatNode::kDescribed) {
    // The caller should have expanded the references if it wants them shown. If not, display
    // a placeholder with the address. Show the whole thing dimmed to help indicate this isn't the
    // actual value.
    return OutputBuffer(Syntax::kComment, "(&)" + node->description());
  }

  // Have the pointed-to data, just show the value. We do not want to indent another level.
  RecursiveState child_state = state.AdvanceNoIndent();
  child_state.inhibit_one_name = true;
  child_state.inhibit_one_type = true;

  // Use the "one way" version to propagate our formatting mode. This node cant't get different
  // formatting than its child.
  return DoFormatNodeOneWay(node->children()[0].get(), child_state, 0);
}

// A Rust enum is currently like a reference in that is has a child that's the resolved type.
// A resolved enum type will be a TupleStruct (unnamed members) or a Struct (named members). Enums
// with no members are encoded as empty structs which the struct printing code will handle.
OutputBuffer DoFormatRustEnum(const FormatNode* node, const RecursiveState& state) {
  if (node->children().empty()) {
    // The caller should have expanded the enum if it wants it to be shown. If not, display the
    // description which will generally be the short name of the enum.
    return OutputBuffer(Syntax::kComment, node->description());
  }

  // Have the pointed-to data, just show the value. We do not want to indent another level. The
  // type is also hidden because it will be a generated type. If requested, the type of the overall
  // enum will have already been printed.
  RecursiveState child_state = state.AdvanceNoIndent();
  child_state.inhibit_one_name = true;
  child_state.inhibit_one_type = true;

  // Use the "one way" version to propagate our formatting mode. This node can't get different
  // formatting than its child.
  return DoFormatNodeOneWay(node->children()[0].get(), child_state, 0);
}

// A generic node with one child for things like std::optional or std::atomic.
OutputBuffer DoFormatWrapper(const FormatNode* node, const RecursiveState& state) {
  if (node->children().empty())
    return OutputBuffer(node->description() + node->wrapper_prefix() + node->wrapper_suffix());

  RecursiveState child_state = state.AdvanceNoIndent();

  OutputBuffer out;
  out.Append(node->description());
  out.Append(Syntax::kOperatorNormal, node->wrapper_prefix());
  out.Append(DoFormatNodeOneWay(node->children()[0].get(), child_state, 0));
  out.Append(Syntax::kOperatorNormal, node->wrapper_suffix());
  return out;
}

// Appends the description for a normal node (number or whatever).
OutputBuffer DoFormatStandardNode(const FormatNode* node, const RecursiveState& state,
                                  Syntax syntax = Syntax::kNormal) {
  return OutputBuffer(syntax, node->description());
}

// Groups have no heading, they're always just a list of children.
OutputBuffer DoFormatGroupNode(const FormatNode* node, const RecursiveState& state) {
  OutputBuffer out;
  AppendNodeChildren(node, state, std::string(), std::string(), state, &out);
  return out;
}

// Inner implementation for DoFormatTreeNode() (see that for more). This does the actual formatting
// one time according to the current formatting options and state.
//
// Some callers may want to call this directly rather than DoFormatTreeNode() if they want to bypass
// the two-pass formatting. This is useful for pointers which are two nodes (when auto dereferenced)
// but appear as one and the expansion mode of the outer should be passed transparently to the
// nested node.
OutputBuffer DoFormatNodeOneWay(const FormatNode* node, const RecursiveState& state,
                                int indent_amount) {
  OutputBuffer out;

  if (indent_amount)
    out.Append(std::string(indent_amount, ' '));

  AppendNodeNameAndType(node, state, &out);
  if (state.DepthTooDeep() || node->state() != FormatNode::kDescribed) {
    // Hit max depth, give up.
    out.Append(Syntax::kComment, "…");
  } else if (node->err().has_error()) {
    // Write the error.
    out.Append(Syntax::kComment, "<" + node->err().msg() + ">");
  } else {
    // Normal formatting.
    switch (node->description_kind()) {
      case FormatNode::kNone:
      case FormatNode::kBaseType:
      case FormatNode::kFunctionPointer:
      case FormatNode::kOther:
        // All these things just print the description only.
        out.Append(DoFormatStandardNode(node, state));
        break;
      case FormatNode::kGroup:
        out.Append(DoFormatGroupNode(node, state));
        break;
      case FormatNode::kArray:
      case FormatNode::kRustTuple:
      case FormatNode::kRustTupleStruct:
        out.Append(DoFormatArrayOrTupleNode(node, state));
        break;
      case FormatNode::kCollection:
        out.Append(DoFormatCollectionNode(node, state));
        break;
      case FormatNode::kPointer:
        out.Append(DoFormatPointerNode(node, state));
        break;
      case FormatNode::kReference:
        out.Append(DoFormatReferenceNode(node, state));
        break;
      case FormatNode::kRustEnum:
        out.Append(DoFormatRustEnum(node, state));
        break;
      case FormatNode::kWrapper:
        out.Append(DoFormatWrapper(node, state));
        break;
      case FormatNode::kString:
        // For strings, use the number format to determine if the output should be displayed
        // as the string data or a numeric array.
        // TODO(https://fxbug.dev/428735755): Don't rely on the number formatting for strings.
        if (state.options.num_format == FormatOptions::NumFormat::kDefault ||
            state.options.num_format == FormatOptions::NumFormat::kChar) {
          out.Append(DoFormatStandardNode(node, state, Syntax::kStringNormal));
        } else {
          out.Append(DoFormatArrayOrTupleNode(node, state));
        }
        break;
    }
  }

  return out;
}

// Formats one node. This layer provides the smart wrapping logic where we may try to format an
// item twice, first to see if it fits on one line, and possibly again ig it doesn't.
//
// The caller of this function is in charge of computing (but not inserting) the appropriate level
// of indent and also appending trailing newlines if necessary.
//
// The caller must compute the indenting amount because whether or not there's indenting for this
// node depends the expansion level of the caller, not this node. (This item could be in single-line
// mode and still be indented if the caller is expanded.)
OutputBuffer DoFormatTreeNode(const FormatNode* node, const RecursiveState& state,
                              int indent_amount) {
  if (state.options.wrapping != FormatBufferOptions::Wrapping::kSmart)
    return DoFormatNodeOneWay(node, state, indent_amount);  // Nothing fancy to do.

  // Nodes with few children we try to fit on one line if possible in smart mode. Generally
  // structures with more than 4 children will always spill over to multiline mode, so this check is
  // more of an optimization to avoid trying and failing to format the whole thing as a single line
  // first. Even if it fits, many members on a line are not readable.
  if (state.smart_indent_is_expanded && node->children().size() <= 4) {
    // The previous node was in an expanded state. First try to format this one as non-expanded.
    // to see if it fits.
    RecursiveState one_line_state = state;
    one_line_state.smart_indent_is_expanded = false;

    OutputBuffer one_line = DoFormatNodeOneWay(node, one_line_state, indent_amount);
    if (static_cast<int>(one_line.UnicodeCharWidth()) <= state.options.smart_indent_cols)
      return one_line;  // Fits.

    // Too big, format as expanded.
    return DoFormatNodeOneWay(node, state, indent_amount);
  }

  // The previous node was already in one-line mode, stay in that mode.
  return DoFormatNodeOneWay(node, state, indent_amount);
}

}  // namespace

void DescribeFormatTreeNode(FormatNode* node, const FormatBufferOptions& options,
                            fxl::RefPtr<EvalContext> context, fit::deferred_callback cb) {
  RecursiveDescribeFormatTreeNode(node, context, RecursiveState(options), std::move(cb));
}

OutputBuffer FormatTreeNode(const FormatNode& node, const FormatBufferOptions& options) {
  return DoFormatTreeNode(&node, RecursiveState(options), 0);
}

fxl::RefPtr<AsyncOutputBuffer> FormatValue(ExprValue value, const FormatBufferOptions& options,
                                           fxl::RefPtr<EvalContext> eval_context,
                                           const std::string& value_name) {
  auto node = std::make_unique<FormatNode>(value_name, std::move(value));
  node->set_child_kind(FormatNode::kVariable);

  FormatNode* node_ptr = node.get();

  auto out = fxl::MakeRefCounted<AsyncOutputBuffer>();
  DescribeFormatTreeNode(node_ptr, options, eval_context,
                         fit::defer_callback([node = std::move(node), options, out]() {
                           // Asynchronous expansion is complete, now format the completed
                           // output.
                           out->Complete(FormatTreeNode(*node, options));
                         }));
  return out;
}

fxl::RefPtr<AsyncOutputBuffer> FormatVariable(const Variable* var,
                                              const FormatBufferOptions& options,
                                              fxl::RefPtr<EvalContext> eval_context) {
  auto out = fxl::MakeRefCounted<AsyncOutputBuffer>();
  eval_context->GetVariableValue(RefPtrTo(var), [name = var->GetAssignedName(), eval_context,
                                                 options, out](ErrOrValue value) mutable {
    if (value.has_error()) {
      // In the error case, construct a node with the error set so the formatting with other
      // types of errors is consistent.
      FormatNode err_node(name);
      err_node.SetDescribedError(value.err());
      out->Complete(FormatTreeNode(err_node, options));
    } else {
      out->Complete(FormatValue(value.take_value(), options, eval_context, name));
    }
  });
  return out;
}

fxl::RefPtr<AsyncOutputBuffer> FormatExpressions(const std::vector<std::string>& expressions,
                                                 const FormatBufferOptions& options,
                                                 fxl::RefPtr<EvalContext> eval_context) {
  // Put all of the expressions in a "group" node and then evaluate and format this node. This will
  // allow single- and multi-line formatting for the values and also handles all of the asynchronous
  // state across all of the expressions automatically.
  auto out = fxl::MakeRefCounted<AsyncOutputBuffer>();
  auto list_node = std::make_unique<FormatNode>(FormatNode::GroupTag());
  FormatNode* list_node_ptr = list_node.get();

  for (const std::string& expr : expressions) {
    // Use the expression as the description.
    auto child_node = std::make_unique<FormatNode>(expr, expr);
    list_node->children().push_back(std::move(child_node));
  }

  DescribeFormatTreeNode(list_node_ptr, options, eval_context,
                         fit::defer_callback([list_node = std::move(list_node), options, out]() {
                           out->Complete(FormatTreeNode(*list_node, options));
                         }));
  return out;
}

}  // namespace zxdb
