[debugger] Separate out formatting options.

Moves the FormatValueOptions from console/format_value.h to a new file
in the "expr" directory. This is to move to a design where the abstract
output formatting is done in the expr directory, and the conversion to
text is done in the console directory.

There should be no behavior change, this only moves and renames the
struct.

TEST=none

Change-Id: I24ad66f564bb6bae690c7be80fb2823d63a936f6
diff --git a/bin/zxdb/console/format_frame.cc b/bin/zxdb/console/format_frame.cc
index 250ae81..42f466c 100644
--- a/bin/zxdb/console/format_frame.cc
+++ b/bin/zxdb/console/format_frame.cc
@@ -33,8 +33,8 @@
       std::make_unique<FormatValueProcessContextImpl>(thread->GetProcess()));
 
   // Formatting used for long format mode.
-  FormatValueOptions format_options;
-  format_options.verbosity = FormatValueOptions::Verbosity::kMinimal;
+  FormatExprValueOptions format_options;
+  format_options.verbosity = FormatExprValueOptions::Verbosity::kMinimal;
 
   // This doesn't use table output since the format of the stack frames is
   // usually so unpredictable.
@@ -105,7 +105,7 @@
 }
 
 void FormatFrameLong(const Frame* frame, bool include_params, FormatValue* out,
-                     const FormatValueOptions& options, int id) {
+                     const FormatExprValueOptions& options, int id) {
   if (id >= 0)
     out->Append(OutputBuffer(fxl::StringPrintf("Frame %d ", id)));
 
diff --git a/bin/zxdb/console/format_frame.h b/bin/zxdb/console/format_frame.h
index 64748b8..1a0090b 100644
--- a/bin/zxdb/console/format_frame.h
+++ b/bin/zxdb/console/format_frame.h
@@ -7,7 +7,7 @@
 namespace zxdb {
 
 class FormatValue;
-struct FormatValueOptions;
+struct FormatExprValueOptions;
 class Frame;
 class OutputBuffer;
 class Thread;
@@ -23,7 +23,8 @@
 // Printing of function parameter types is controlled by include_params.
 //
 // This does not append a newline at the end of the output.
-void FormatFrame(const Frame* frame, bool include_params, OutputBuffer* out, int id = -1);
+void FormatFrame(const Frame* frame, bool include_params, OutputBuffer* out,
+                 int id = -1);
 
 // Formats one frame using the long format. Since the long format includes
 // function parameters which are computed asynchronously, this takes the
@@ -31,6 +32,6 @@
 //
 // This does not append a newline at the end of the output.
 void FormatFrameLong(const Frame* frame, bool include_params, FormatValue* out,
-                     const FormatValueOptions& options, int id = -1);
+                     const FormatExprValueOptions& options, int id = -1);
 
 }  // namespace zxdb
diff --git a/bin/zxdb/console/format_frame_unittest.cc b/bin/zxdb/console/format_frame_unittest.cc
index 0684440..0b5f496 100644
--- a/bin/zxdb/console/format_frame_unittest.cc
+++ b/bin/zxdb/console/format_frame_unittest.cc
@@ -18,13 +18,13 @@
 
 // Synchronous wrapper around asynchronous long formatting.
 std::string SyncFormatFrameLong(const Frame* frame,
-                                const FormatValueOptions& options) {
+                                const FormatExprValueOptions& options) {
   debug_ipc::PlatformMessageLoop loop;
   loop.Init();
 
   auto helper = fxl::MakeRefCounted<FormatValue>(
       std::make_unique<MockFormatValueProcessContext>());
-  FormatFrameLong(frame, false, helper.get(), FormatValueOptions());
+  FormatFrameLong(frame, false, helper.get(), FormatExprValueOptions());
 
   std::string out_string;
   bool complete = false;
@@ -64,7 +64,7 @@
 
   // Long version should do the same (not duplicate it).
   EXPECT_EQ("\n      IP = 0x12345678, BP = 0xdeadbeef, SP = 0x567890",
-            SyncFormatFrameLong(&frame, FormatValueOptions()));
+            SyncFormatFrameLong(&frame, FormatExprValueOptions()));
 
   // With index.
   out = OutputBuffer();
diff --git a/bin/zxdb/console/format_value.cc b/bin/zxdb/console/format_value.cc
index ebfeef6..1225fa0 100644
--- a/bin/zxdb/console/format_value.cc
+++ b/bin/zxdb/console/format_value.cc
@@ -33,8 +33,8 @@
 
 namespace {
 
-using NumFormat = FormatValueOptions::NumFormat;
-using Verbosity = FormatValueOptions::Verbosity;
+using NumFormat = FormatExprValueOptions::NumFormat;
+using Verbosity = FormatExprValueOptions::Verbosity;
 
 // When there are errors during value printing we can't just print them since
 // they're associated with a value. This function formats the error in a way
@@ -138,7 +138,7 @@
 
 void FormatValue::AppendValue(fxl::RefPtr<SymbolDataProvider> data_provider,
                               const ExprValue value,
-                              const FormatValueOptions& options) {
+                              const FormatExprValueOptions& options) {
   FormatExprValue(data_provider, value, options, false,
                   AsyncAppend(GetRootOutputKey()));
 }
@@ -146,7 +146,7 @@
 void FormatValue::AppendVariable(const SymbolContext& symbol_context,
                                  fxl::RefPtr<SymbolDataProvider> data_provider,
                                  const Variable* var,
-                                 const FormatValueOptions& options) {
+                                 const FormatExprValueOptions& options) {
   OutputKey output_key = AsyncAppend(
       NodeType::kVariable, var->GetAssignedName(), GetRootOutputKey());
   auto resolver = std::make_unique<SymbolVariableResolver>(data_provider);
@@ -184,7 +184,7 @@
 
 void FormatValue::FormatExprValue(fxl::RefPtr<SymbolDataProvider> data_provider,
                                   const ExprValue& value,
-                                  const FormatValueOptions& options,
+                                  const FormatExprValueOptions& options,
                                   bool suppress_type_printing,
                                   OutputKey output_key) {
   const Type* type = value.type();
@@ -262,7 +262,7 @@
     switch (value.GetBaseType()) {
       case BaseType::kBaseTypeAddress: {
         // Always print addresses as unsigned hex.
-        FormatValueOptions overridden(options);
+        FormatExprValueOptions overridden(options);
         overridden.num_format = NumFormat::kHex;
         FormatUnsignedInt(value, options, &out);
         break;
@@ -287,7 +287,7 @@
 
 void FormatValue::FormatExprValue(fxl::RefPtr<SymbolDataProvider> data_provider,
                                   const Err& err, const ExprValue& value,
-                                  const FormatValueOptions& options,
+                                  const FormatExprValueOptions& options,
                                   bool suppress_type_printing,
                                   OutputKey output_key) {
   if (err.has_error()) {
@@ -320,7 +320,7 @@
 //   }
 void FormatValue::FormatCollection(
     fxl::RefPtr<SymbolDataProvider> data_provider, const Collection* coll,
-    const ExprValue& value, const FormatValueOptions& options,
+    const ExprValue& value, const FormatExprValueOptions& options,
     OutputKey output_key) {
   AppendToOutputKey(output_key, OutputBuffer("{"));
 
@@ -403,12 +403,12 @@
                                const ExprValue& value,
                                const Type* array_value_type,
                                int known_elt_count,
-                               const FormatValueOptions& options,
+                               const FormatExprValueOptions& options,
                                OutputKey output_key) {}
 
 bool FormatValue::TryFormatArrayOrString(
     fxl::RefPtr<SymbolDataProvider> data_provider, const Type* type,
-    const ExprValue& value, const FormatValueOptions& options,
+    const ExprValue& value, const FormatExprValueOptions& options,
     OutputKey output_key) {
   FXL_DCHECK(type == type->GetConcreteType());
 
@@ -447,7 +447,7 @@
 
 void FormatValue::FormatCharPointer(
     fxl::RefPtr<SymbolDataProvider> data_provider, const Type* type,
-    const ExprValue& value, const FormatValueOptions& options,
+    const ExprValue& value, const FormatExprValueOptions& options,
     OutputKey output_key) {
   if (value.data().size() != kTargetPointerSize) {
     OutputKeyComplete(output_key, ErrStringToOutput("Bad pointer data."));
@@ -519,7 +519,7 @@
 
 void FormatValue::FormatArray(fxl::RefPtr<SymbolDataProvider> data_provider,
                               const ExprValue& value, int elt_count,
-                              const FormatValueOptions& options,
+                              const FormatExprValueOptions& options,
                               OutputKey output_key) {
   // Arrays should have known non-zero sizes.
   FXL_DCHECK(elt_count >= 0);
@@ -556,7 +556,7 @@
 }
 
 void FormatValue::FormatNumeric(const ExprValue& value,
-                                const FormatValueOptions& options,
+                                const FormatExprValueOptions& options,
                                 OutputBuffer* out) {
   if (options.num_format != NumFormat::kDefault) {
     // Overridden format option.
@@ -612,7 +612,7 @@
 
 void FormatValue::FormatEnum(const ExprValue& value,
                              const Enumeration* enum_type,
-                             const FormatValueOptions& options,
+                             const FormatExprValueOptions& options,
                              OutputBuffer* out) {
   // Get the value out casted to a uint64.
   Err err;
@@ -645,7 +645,7 @@
 
   // Invalid enum values of explicitly overridden numeric formatting gets
   // printed as a number.
-  FormatValueOptions modified_opts = options;
+  FormatExprValueOptions modified_opts = options;
   if (modified_opts.num_format == NumFormat::kDefault) {
     // Compute the formatting for invalid enum values when there is no numeric
     // override.
@@ -680,7 +680,7 @@
 }
 
 void FormatValue::FormatUnsignedInt(const ExprValue& value,
-                                    const FormatValueOptions& options,
+                                    const FormatExprValueOptions& options,
                                     OutputBuffer* out) {
   // This formatter handles unsigned and hex output.
   uint64_t int_val = 0;
@@ -707,7 +707,7 @@
 }
 
 void FormatValue::FormatPointer(const ExprValue& value,
-                                const FormatValueOptions& options,
+                                const FormatExprValueOptions& options,
                                 OutputBuffer* out) {
   // Don't make assumptions about the type of value.type() since it isn't
   // necessarily a ModifiedType representing a pointer, but could be other
@@ -732,7 +732,7 @@
 
 void FormatValue::FormatReference(fxl::RefPtr<SymbolDataProvider> data_provider,
                                   const ExprValue& value,
-                                  const FormatValueOptions& options,
+                                  const FormatExprValueOptions& options,
                                   OutputKey output_key) {
   EnsureResolveReference(data_provider, value, [
     weak_this = weak_factory_.GetWeakPtr(), data_provider,
@@ -783,7 +783,7 @@
 }
 
 void FormatValue::FormatFunctionPointer(const ExprValue& value,
-                                        const FormatValueOptions& options,
+                                        const FormatExprValueOptions& options,
                                         OutputBuffer* out) {
   // Unlike pointers, we don't print the type for function pointers. These
   // are usually very long and not very informative. If explicitly requested,
@@ -827,7 +827,7 @@
 }
 
 void FormatValue::FormatMemberPtr(const ExprValue& value, const MemberPtr* type,
-                                  const FormatValueOptions& options,
+                                  const FormatExprValueOptions& options,
                                   OutputBuffer* out) {
   const Type* container_type = type->container_type().Get()->AsType();
   const Type* pointed_to_type = type->member_type().Get()->AsType();
diff --git a/bin/zxdb/console/format_value.h b/bin/zxdb/console/format_value.h
index ba9cff5..f4de011 100644
--- a/bin/zxdb/console/format_value.h
+++ b/bin/zxdb/console/format_value.h
@@ -11,6 +11,7 @@
 #include <vector>
 
 #include "garnet/bin/zxdb/console/output_buffer.h"
+#include "garnet/bin/zxdb/expr/format_expr_value_options.h"
 #include "lib/fxl/memory/ref_counted.h"
 #include "lib/fxl/memory/ref_ptr.h"
 #include "lib/fxl/memory/weak_ptr.h"
@@ -31,39 +32,6 @@
 class Value;
 class Variable;
 
-struct FormatValueOptions {
-  enum class NumFormat { kDefault, kUnsigned, kSigned, kHex, kChar };
-
-  // This has numeric values so one can compare verbosity levels.
-  enum class Verbosity : int {
-    // Show as little as possible without being misleading. Some long types
-    // will be elided with "...", references won't have addresses.
-    kMinimal = 0,
-
-    // Print like GDB does. Show the full names of base classes, reference
-    // addresses, and pointer types.
-    kMedium = 1,
-
-    // All full type information and pointer values are shown for everything.
-    kAllTypes = 2
-  };
-
-  // Maximum number of elements to print in an array. For strings we'll
-  // speculatively fetch this much data since we don't know mow long the string
-  // will be in advance. This means that increasing this will make all string
-  // printing (even small strings) slower.
-  //
-  // If we want to support larger sizes, we may want to add a special memory
-  // request option where the debug agent fetches until a null terminator is
-  // reached.
-  uint32_t max_array_size = 256;
-
-  // Format to apply to numeric types.
-  NumFormat num_format = NumFormat::kDefault;
-
-  Verbosity verbosity = Verbosity::kMedium;
-};
-
 // Manages formatting of variables and ExprValues (the results of expressions).
 // Since formatting is asynchronous this can be tricky. This class manages a
 // set of output operations interleaved with synchronously and asynchronously
@@ -100,7 +68,8 @@
   // Construct with fxl::MakeRefCounted<FormatValue>().
 
   void AppendValue(fxl::RefPtr<SymbolDataProvider> data_provider,
-                   const ExprValue value, const FormatValueOptions& options);
+                   const ExprValue value,
+                   const FormatExprValueOptions& options);
 
   // The data provider normally comes from the frame where you want to evaluate
   // the variable in. This will prepend "<name> = " to the value of the
@@ -108,7 +77,7 @@
   void AppendVariable(const SymbolContext& symbol_context,
                       fxl::RefPtr<SymbolDataProvider> data_provider,
                       const Variable* var,
-                      const FormatValueOptions& options);
+                      const FormatExprValueOptions& options);
 
   void Append(std::string str);
   void Append(OutputBuffer out);
@@ -203,11 +172,11 @@
   // been printed.
   void FormatExprValue(fxl::RefPtr<SymbolDataProvider> data_provider,
                        const ExprValue& value,
-                       const FormatValueOptions& options,
+                       const FormatExprValueOptions& options,
                        bool suppress_type_printing, OutputKey output_key);
   void FormatExprValue(fxl::RefPtr<SymbolDataProvider> data_provider,
                        const Err& err, const ExprValue& value,
-                       const FormatValueOptions& options,
+                       const FormatExprValueOptions& options,
                        bool suppress_type_printing, OutputKey output_key);
 
   // Asynchronously formats the given type.
@@ -215,11 +184,11 @@
   // The known_elt_count can be -1 if the array size is not statically known.
   void FormatCollection(fxl::RefPtr<SymbolDataProvider> data_provider,
                         const Collection* coll, const ExprValue& value,
-                        const FormatValueOptions& options,
+                        const FormatExprValueOptions& options,
                         OutputKey output_key);
   void FormatString(fxl::RefPtr<SymbolDataProvider> data_provider,
                     const ExprValue& value, const Type* array_value_type,
-                    int known_elt_count, const FormatValueOptions& options,
+                    int known_elt_count, const FormatExprValueOptions& options,
                     OutputKey output_key);
 
   // Checks array and string types and formats the value accordingly. Returns
@@ -227,43 +196,46 @@
   // was anything else.
   bool TryFormatArrayOrString(fxl::RefPtr<SymbolDataProvider> data_provider,
                               const Type* type, const ExprValue& value,
-                              const FormatValueOptions& options,
+                              const FormatExprValueOptions& options,
                               OutputKey output_key);
 
   // Array and string format helpers.
   void FormatCharPointer(fxl::RefPtr<SymbolDataProvider> data_provider,
                          const Type* type, const ExprValue& value,
-                         const FormatValueOptions& options,
+                         const FormatExprValueOptions& options,
                          OutputKey output_key);
   void FormatCharArray(const uint8_t* data, size_t length, bool truncated,
                        OutputKey output_key);
   void FormatArray(fxl::RefPtr<SymbolDataProvider> data_provider,
                    const ExprValue& value, int elt_count,
-                   const FormatValueOptions& options, OutputKey output_key);
+                   const FormatExprValueOptions& options, OutputKey output_key);
 
   // Dispatcher for all numeric types. This handles formatting overrides.
-  void FormatNumeric(const ExprValue& value, const FormatValueOptions& options,
-                     OutputBuffer* out);
+  void FormatNumeric(const ExprValue& value,
+                     const FormatExprValueOptions& options, OutputBuffer* out);
 
   // Simpler synchronous outputs.
   void FormatBoolean(const ExprValue& value, OutputBuffer* out);
   void FormatEnum(const ExprValue& value, const Enumeration* enum_type,
-                  const FormatValueOptions& options, OutputBuffer* out);
+                  const FormatExprValueOptions& options, OutputBuffer* out);
   void FormatFloat(const ExprValue& value, OutputBuffer* out);
   void FormatSignedInt(const ExprValue& value, OutputBuffer* out);
   void FormatUnsignedInt(const ExprValue& value,
-                         const FormatValueOptions& options, OutputBuffer* out);
+                         const FormatExprValueOptions& options,
+                         OutputBuffer* out);
   void FormatChar(const ExprValue& value, OutputBuffer* out);
-  void FormatPointer(const ExprValue& value, const FormatValueOptions& options,
-                     OutputBuffer* out);
+  void FormatPointer(const ExprValue& value,
+                     const FormatExprValueOptions& options, OutputBuffer* out);
   void FormatReference(fxl::RefPtr<SymbolDataProvider> data_provider,
                        const ExprValue& value,
-                       const FormatValueOptions& options, OutputKey output_key);
+                       const FormatExprValueOptions& options,
+                       OutputKey output_key);
   void FormatFunctionPointer(const ExprValue& value,
-                             const FormatValueOptions& options,
+                             const FormatExprValueOptions& options,
                              OutputBuffer* out);
   void FormatMemberPtr(const ExprValue& value, const MemberPtr* type,
-                       const FormatValueOptions& options, OutputBuffer* out);
+                       const FormatExprValueOptions& options,
+                       OutputBuffer* out);
 
   OutputKey GetRootOutputKey();
 
diff --git a/bin/zxdb/console/format_value_unittest.cc b/bin/zxdb/console/format_value_unittest.cc
index 0a2a376..4003f76 100644
--- a/bin/zxdb/console/format_value_unittest.cc
+++ b/bin/zxdb/console/format_value_unittest.cc
@@ -50,7 +50,7 @@
 
   // Synchronously calls FormatExprValue, returning the result.
   std::string SyncFormatValue(const ExprValue& value,
-                              const FormatValueOptions& opts) {
+                              const FormatExprValueOptions& opts) {
     bool called = false;
     std::string output;
 
@@ -83,7 +83,7 @@
 }  // namespace
 
 TEST_F(FormatValueTest, Signed) {
-  FormatValueOptions opts;
+  FormatExprValueOptions opts;
 
   // 8-bit.
   ExprValue val_int8(
@@ -113,12 +113,12 @@
   ExprValue val_float(
       fxl::MakeRefCounted<BaseType>(BaseType::kBaseTypeFloat, 4, "float"),
       {0x04, 0x03, 0x02, 0x01});
-  opts.num_format = FormatValueOptions::NumFormat::kSigned;
+  opts.num_format = FormatExprValueOptions::NumFormat::kSigned;
   EXPECT_EQ("16909060", SyncFormatValue(val_float, opts));
 }
 
 TEST_F(FormatValueTest, Unsigned) {
-  FormatValueOptions opts;
+  FormatExprValueOptions opts;
 
   // 8-bit.
   ExprValue val_int8(
@@ -148,14 +148,14 @@
   ExprValue val_float(
       fxl::MakeRefCounted<BaseType>(BaseType::kBaseTypeFloat, 4, "float"),
       {0x04, 0x03, 0x02, 0x01});
-  opts.num_format = FormatValueOptions::NumFormat::kUnsigned;
+  opts.num_format = FormatExprValueOptions::NumFormat::kUnsigned;
   EXPECT_EQ("16909060", SyncFormatValue(val_float, opts));
-  opts.num_format = FormatValueOptions::NumFormat::kHex;
+  opts.num_format = FormatExprValueOptions::NumFormat::kHex;
   EXPECT_EQ("0x1020304", SyncFormatValue(val_float, opts));
 }
 
 TEST_F(FormatValueTest, Bool) {
-  FormatValueOptions opts;
+  FormatExprValueOptions opts;
 
   // 8-bit true.
   ExprValue val_true8(
@@ -177,7 +177,7 @@
 }
 
 TEST_F(FormatValueTest, Char) {
-  FormatValueOptions opts;
+  FormatExprValueOptions opts;
 
   // 8-bit char.
   ExprValue val_char8(
@@ -204,7 +204,7 @@
   EXPECT_EQ("'A'", SyncFormatValue(val_char32, opts));
 
   // 32-bit int forced to char.
-  opts.num_format = FormatValueOptions::NumFormat::kChar;
+  opts.num_format = FormatExprValueOptions::NumFormat::kChar;
   ExprValue val_int32(
       fxl::MakeRefCounted<BaseType>(BaseType::kBaseTypeSigned, 4, "int32_t"),
       {'$', 0x01, 0x00, 0x00});
@@ -212,7 +212,7 @@
 }
 
 TEST_F(FormatValueTest, Float) {
-  FormatValueOptions opts;
+  FormatExprValueOptions opts;
 
   uint8_t buffer[8];
 
@@ -234,7 +234,7 @@
 }
 
 TEST_F(FormatValueTest, Pointer) {
-  FormatValueOptions opts;
+  FormatExprValueOptions opts;
 
   auto base_type =
       fxl::MakeRefCounted<BaseType>(BaseType::kBaseTypeSigned, 1, "int");
@@ -249,16 +249,16 @@
 
   // Print with type printing forced on. The result should be the same (the
   // type shouldn't be duplicated).
-  opts.verbosity = FormatValueOptions::Verbosity::kAllTypes;
+  opts.verbosity = FormatExprValueOptions::Verbosity::kAllTypes;
   EXPECT_EQ("(int*) 0x807060504030201", SyncFormatValue(value, opts));
 
   // Minimal formatting should omit the type name
-  opts.verbosity = FormatValueOptions::Verbosity::kMinimal;
+  opts.verbosity = FormatExprValueOptions::Verbosity::kMinimal;
   EXPECT_EQ("(*) 0x807060504030201", SyncFormatValue(value, opts));
 
   // Test an invalid one with an incorrect size.
   data.resize(7);
-  opts.verbosity = FormatValueOptions::Verbosity::kMedium;
+  opts.verbosity = FormatExprValueOptions::Verbosity::kMedium;
   ExprValue bad_value(ptr_type, data);
   EXPECT_EQ(
       "(int*) <The value of type 'int*' is the incorrect size (expecting 8, "
@@ -267,7 +267,7 @@
 }
 
 TEST_F(FormatValueTest, GoodStrings) {
-  FormatValueOptions opts;
+  FormatExprValueOptions opts;
 
   constexpr uint64_t kAddress = 0x1100;
   std::vector<uint8_t> data = {'A',  'B',  'C', 'D',  'E', 'F',
@@ -285,24 +285,24 @@
             SyncFormatValue(ExprValue(ptr_type, address_data), opts));
 
   // Force type info.
-  opts.verbosity = FormatValueOptions::Verbosity::kAllTypes;
+  opts.verbosity = FormatExprValueOptions::Verbosity::kAllTypes;
   EXPECT_EQ(std::string("(char*) ") + kExpected,
             SyncFormatValue(ExprValue(ptr_type, address_data), opts));
 
   // This string has the same data but is type encoded as char[12], it should
   // give the same output (except for type info).
-  opts.verbosity = FormatValueOptions::Verbosity::kMedium;
+  opts.verbosity = FormatExprValueOptions::Verbosity::kMedium;
   auto array_type = fxl::MakeRefCounted<ArrayType>(GetCharType(), 12);
   EXPECT_EQ(kExpected, SyncFormatValue(ExprValue(array_type, data), opts));
 
   // Force type info.
-  opts.verbosity = FormatValueOptions::Verbosity::kAllTypes;
+  opts.verbosity = FormatExprValueOptions::Verbosity::kAllTypes;
   EXPECT_EQ(std::string("(char[12]) ") + kExpected,
             SyncFormatValue(ExprValue(array_type, data), opts));
 }
 
 TEST_F(FormatValueTest, BadStrings) {
-  FormatValueOptions opts;
+  FormatExprValueOptions opts;
   std::vector<uint8_t> address_data = {0x00, 0x11, 0x00, 0x00,
                                        0x00, 0x00, 0x00, 0x00};
 
@@ -317,7 +317,7 @@
 }
 
 TEST_F(FormatValueTest, TruncatedString) {
-  FormatValueOptions opts;
+  FormatExprValueOptions opts;
 
   constexpr uint64_t kAddress = 0x1100;
   provider()->AddMemory(kAddress, {'A', 'B', 'C', 'D', 'E', 'F'});
@@ -339,7 +339,7 @@
 }
 
 TEST_F(FormatValueTest, EmptyAndBadArray) {
-  FormatValueOptions opts;
+  FormatExprValueOptions opts;
 
   // Array of two int32's: [1, 2]
   constexpr uint64_t kAddress = 0x1100;
@@ -360,7 +360,7 @@
 }
 
 TEST_F(FormatValueTest, TruncatedArray) {
-  FormatValueOptions opts;
+  FormatExprValueOptions opts;
   opts.max_array_size = 2;
 
   // Array of two int32's: {1, 2}
@@ -376,7 +376,7 @@
 
   // Try one with type info forced on. Only the root array type should have the
   // type, not each individual element.
-  opts.verbosity = FormatValueOptions::Verbosity::kAllTypes;
+  opts.verbosity = FormatExprValueOptions::Verbosity::kAllTypes;
   EXPECT_EQ("(int32_t[2]) {1, 2}",
             SyncFormatValue(ExprValue(array_type, data, source), opts));
 
@@ -387,7 +387,7 @@
 }
 
 TEST_F(FormatValueTest, Reference) {
-  FormatValueOptions opts;
+  FormatExprValueOptions opts;
 
   auto base_type =
       fxl::MakeRefCounted<BaseType>(BaseType::kBaseTypeSigned, 1, "int");
@@ -402,16 +402,16 @@
   EXPECT_EQ("(int&) 0x1100 = 123", SyncFormatValue(value, opts));
 
   // Forcing type info on shouldn't duplicate the type.
-  opts.verbosity = FormatValueOptions::Verbosity::kAllTypes;
+  opts.verbosity = FormatExprValueOptions::Verbosity::kAllTypes;
   EXPECT_EQ("(int&) 0x1100 = 123", SyncFormatValue(value, opts));
 
   // Force with minimal formatting (no addr ot type info).
-  opts.verbosity = FormatValueOptions::Verbosity::kMinimal;
+  opts.verbosity = FormatExprValueOptions::Verbosity::kMinimal;
   EXPECT_EQ("123", SyncFormatValue(value, opts));
 
   // Test an invalid one with an invalid address.
   std::vector<uint8_t> bad_data = {0x00, 0x22, 0, 0, 0, 0, 0, 0};
-  opts.verbosity = FormatValueOptions::Verbosity::kMedium;
+  opts.verbosity = FormatExprValueOptions::Verbosity::kMedium;
   value = ExprValue(ref_type, bad_data);
   EXPECT_EQ("(int&) 0x2200 = <Invalid pointer 0x2200>",
             SyncFormatValue(value, opts));
@@ -421,16 +421,16 @@
   auto rvalue_ref_type = fxl::MakeRefCounted<ModifiedType>(
       Symbol::kTagRvalueReferenceType, LazySymbol(base_type));
   value = ExprValue(rvalue_ref_type, data);
-  opts.verbosity = FormatValueOptions::Verbosity::kMedium;
+  opts.verbosity = FormatExprValueOptions::Verbosity::kMedium;
   EXPECT_EQ("(int&&) 0x1100 = 123", SyncFormatValue(value, opts));
 
-  opts.verbosity = FormatValueOptions::Verbosity::kMinimal;
+  opts.verbosity = FormatExprValueOptions::Verbosity::kMinimal;
   EXPECT_EQ("123", SyncFormatValue(value, opts));
 }
 
 TEST_F(FormatValueTest, Structs) {
-  FormatValueOptions opts;
-  opts.num_format = FormatValueOptions::NumFormat::kHex;
+  FormatExprValueOptions opts;
+  opts.num_format = FormatExprValueOptions::NumFormat::kHex;
 
   auto int32_type = MakeInt32Type();
 
@@ -465,7 +465,7 @@
 
   // Force type info. Now the reference types move before the member names like
   // the other types.
-  opts.verbosity = FormatValueOptions::Verbosity::kAllTypes;
+  opts.verbosity = FormatExprValueOptions::Verbosity::kAllTypes;
   EXPECT_EQ(
       "(Pair) {(Foo) first = {(int32_t) a = 0x110011, (int32_t&) b = 0x1100 = "
       "0x12}, "
@@ -485,7 +485,7 @@
 // GDB and LLDB both print all members of a union and accept the possibility
 // that sometimes one of them might be garbage, we do the same.
 TEST_F(FormatValueTest, Union) {
-  FormatValueOptions opts;
+  FormatExprValueOptions opts;
 
   // Define a union type with two int32 values.
   auto int32_type = MakeInt32Type();
@@ -546,12 +546,12 @@
 
   // Default formatting. Only the Base should be printed, EmptyBase should be
   // omitted because it has no data.
-  FormatValueOptions opts;
+  FormatExprValueOptions opts;
   EXPECT_EQ("{Base = {a = 1, b = 2}, c = 3, d = 4}",
             SyncFormatValue(value, opts));
 
   // Force types on. The type of the base class should not be duplicated.
-  opts.verbosity = FormatValueOptions::Verbosity::kAllTypes;
+  opts.verbosity = FormatExprValueOptions::Verbosity::kAllTypes;
   EXPECT_EQ(
       "(Derived) {Base = {(int32_t) a = 1, (int32_t) b = 2}, (int32_t) c = 3, "
       "(int32_t) d = 4}",
@@ -568,7 +568,7 @@
       "UnsignedEnum", LazySymbol(), 8, false, unsigned_map);
 
   // Found value
-  FormatValueOptions opts;
+  FormatExprValueOptions opts;
   EXPECT_EQ("kZero",
             SyncFormatValue(ExprValue(unsigned_enum, {0, 0, 0, 0, 0, 0, 0, 0}),
                             opts));
@@ -578,8 +578,8 @@
                             opts));
 
   // Found value forced to hex.
-  FormatValueOptions hex_opts;
-  hex_opts.num_format = FormatValueOptions::NumFormat::kHex;
+  FormatExprValueOptions hex_opts;
+  hex_opts.num_format = FormatExprValueOptions::NumFormat::kHex;
   EXPECT_EQ("0xffffffffffffffff",
             SyncFormatValue(ExprValue(unsigned_enum, {0xff, 0xff, 0xff, 0xff,
                                                       0xff, 0xff, 0xff, 0xff}),
@@ -616,8 +616,8 @@
                             hex_opts));
 
   // Force type info.
-  FormatValueOptions type_opts;
-  type_opts.verbosity = FormatValueOptions::Verbosity::kAllTypes;
+  FormatExprValueOptions type_opts;
+  type_opts.verbosity = FormatExprValueOptions::Verbosity::kAllTypes;
   EXPECT_EQ("(SignedEnum) kZero",
             SyncFormatValue(ExprValue(signed_enum, {0, 0, 0, 0}), type_opts));
   EXPECT_EQ("(SignedEnum) -4",
@@ -648,13 +648,13 @@
                          LazySymbol(function)));
 
   // Function.
-  FormatValueOptions type_opts;
-  type_opts.verbosity = FormatValueOptions::Verbosity::kAllTypes;
+  FormatExprValueOptions type_opts;
+  type_opts.verbosity = FormatExprValueOptions::Verbosity::kAllTypes;
   ExprValue null_func(func_type, {0, 0, 0, 0, 0, 0, 0, 0});
   EXPECT_EQ("(void()) 0x0", SyncFormatValue(null_func, type_opts));
 
   // Null function pointer.
-  FormatValueOptions opts;
+  FormatExprValueOptions opts;
   ExprValue null_ptr(func_ptr_type, {0, 0, 0, 0, 0, 0, 0, 0});
   EXPECT_EQ("0x0", SyncFormatValue(null_ptr, opts));
 
@@ -671,8 +671,8 @@
   EXPECT_EQ("&MyFunc", SyncFormatValue(good_ptr, opts));
 
   // Force output as hex even when the function is matched.
-  FormatValueOptions hex_opts;
-  hex_opts.num_format = FormatValueOptions::NumFormat::kHex;
+  FormatExprValueOptions hex_opts;
+  hex_opts.num_format = FormatExprValueOptions::NumFormat::kHex;
   EXPECT_EQ("0x1234", SyncFormatValue(good_ptr, hex_opts));
 
   // Member function pointer. The type naming of function pointers is tested by
@@ -707,13 +707,13 @@
                                                      LazySymbol(int32_type));
 
   // Null pointer.
-  FormatValueOptions opts;
+  FormatExprValueOptions opts;
   ExprValue null_member_ptr(member_int32, {0, 0, 0, 0, 0, 0, 0, 0});
   EXPECT_EQ("(int32_t MyClass::*) 0x0", SyncFormatValue(null_member_ptr, opts));
 
   // Regular pointer with types forced on.
-  FormatValueOptions type_opts;
-  type_opts.verbosity = FormatValueOptions::Verbosity::kAllTypes;
+  FormatExprValueOptions type_opts;
+  type_opts.verbosity = FormatExprValueOptions::Verbosity::kAllTypes;
   ExprValue good_member_ptr(member_int32, {0x34, 0x12, 0, 0, 0, 0, 0, 0});
   EXPECT_EQ("(int32_t MyClass::*) 0x1234",
             SyncFormatValue(good_member_ptr, type_opts));
diff --git a/bin/zxdb/console/nouns.cc b/bin/zxdb/console/nouns.cc
index 5e14399..913842e 100644
--- a/bin/zxdb/console/nouns.cc
+++ b/bin/zxdb/console/nouns.cc
@@ -114,7 +114,7 @@
   auto helper = fxl::MakeRefCounted<FormatValue>(
       std::make_unique<FormatValueProcessContextImpl>(cmd.target()));
   FormatFrameLong(cmd.frame(), cmd.HasSwitch(kForceTypes), helper.get(),
-                  FormatValueOptions(),
+                  FormatExprValueOptions(),
                   context->GetActiveFrameIdForThread(cmd.thread()));
   helper->Complete(
       [helper](OutputBuffer out) { Console::get()->Output(std::move(out)); });
diff --git a/bin/zxdb/console/verbs_thread.cc b/bin/zxdb/console/verbs_thread.cc
index 39da1dd..1618723 100644
--- a/bin/zxdb/console/verbs_thread.cc
+++ b/bin/zxdb/console/verbs_thread.cc
@@ -63,14 +63,15 @@
 }
 
 // Populates the formatting options with the given command's switches.
-Err GetFormatValueOptions(const Command& cmd, FormatValueOptions* options) {
+Err GetFormatExprValueOptions(const Command& cmd,
+                              FormatExprValueOptions* options) {
   // Verbosity.
   if (cmd.HasSwitch(kForceAllTypes))
-    options->verbosity = FormatValueOptions::Verbosity::kAllTypes;
+    options->verbosity = FormatExprValueOptions::Verbosity::kAllTypes;
   else if (cmd.HasSwitch(kVerboseFormat))
-    options->verbosity = FormatValueOptions::Verbosity::kMedium;
+    options->verbosity = FormatExprValueOptions::Verbosity::kMedium;
   else
-    options->verbosity = FormatValueOptions::Verbosity::kMinimal;
+    options->verbosity = FormatExprValueOptions::Verbosity::kMinimal;
 
   // Array size.
   if (cmd.HasSwitch(kMaxArraySize)) {
@@ -83,12 +84,12 @@
 
   // Mapping from command-line parameter to format enum.
   constexpr size_t kFormatCount = 4;
-  static constexpr std::pair<int, FormatValueOptions::NumFormat>
+  static constexpr std::pair<int, FormatExprValueOptions::NumFormat>
       kFormats[kFormatCount] = {
-          {kForceNumberChar, FormatValueOptions::NumFormat::kChar},
-          {kForceNumberUnsigned, FormatValueOptions::NumFormat::kUnsigned},
-          {kForceNumberSigned, FormatValueOptions::NumFormat::kSigned},
-          {kForceNumberHex, FormatValueOptions::NumFormat::kHex}};
+          {kForceNumberChar, FormatExprValueOptions::NumFormat::kChar},
+          {kForceNumberUnsigned, FormatExprValueOptions::NumFormat::kUnsigned},
+          {kForceNumberSigned, FormatExprValueOptions::NumFormat::kSigned},
+          {kForceNumberHex, FormatExprValueOptions::NumFormat::kHex}};
 
   int num_type_overrides = 0;
   for (const auto& cur : kFormats) {
@@ -432,8 +433,8 @@
     return Err();
   }
 
-  FormatValueOptions options;
-  err = GetFormatValueOptions(cmd, &options);
+  FormatExprValueOptions options;
+  err = GetFormatExprValueOptions(cmd, &options);
   if (err.has_error())
     return err;
 
@@ -697,8 +698,8 @@
   if (expr.empty())
     return Err("Usage: print <expression>\nSee \"help print\" for more.");
 
-  FormatValueOptions options;
-  err = GetFormatValueOptions(cmd, &options);
+  FormatExprValueOptions options;
+  err = GetFormatExprValueOptions(cmd, &options);
   if (err.has_error())
     return err;
 
diff --git a/bin/zxdb/expr/BUILD.gn b/bin/zxdb/expr/BUILD.gn
index 0b13908..501ed1c 100644
--- a/bin/zxdb/expr/BUILD.gn
+++ b/bin/zxdb/expr/BUILD.gn
@@ -27,6 +27,7 @@
     "found_member.h",
     "found_variable.cc",
     "found_variable.h",
+    "format_expr_value_options.h",
     "identifier.cc",
     "identifier.h",
     "index_walker.cc",
diff --git a/bin/zxdb/expr/format_expr_value_options.h b/bin/zxdb/expr/format_expr_value_options.h
new file mode 100644
index 0000000..9d1a8c7
--- /dev/null
+++ b/bin/zxdb/expr/format_expr_value_options.h
@@ -0,0 +1,44 @@
+// 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.
+
+#pragma once
+
+#include <stdint.h>
+
+namespace zxdb {
+
+struct FormatExprValueOptions {
+  enum class NumFormat { kDefault, kUnsigned, kSigned, kHex, kChar };
+
+  // This has numeric values so one can compare verbosity levels.
+  enum class Verbosity : int {
+    // Show as little as possible without being misleading. Some long types
+    // will be elided with "...", references won't have addresses.
+    kMinimal = 0,
+
+    // Print like GDB does. Show the full names of base classes, reference
+    // addresses, and pointer types.
+    kMedium = 1,
+
+    // All full type information and pointer values are shown for everything.
+    kAllTypes = 2
+  };
+
+  // Maximum number of elements to print in an array. For strings we'll
+  // speculatively fetch this much data since we don't know mow long the string
+  // will be in advance. This means that increasing this will make all string
+  // printing (even small strings) slower.
+  //
+  // If we want to support larger sizes, we may want to add a special memory
+  // request option where the debug agent fetches until a null terminator is
+  // reached.
+  uint32_t max_array_size = 256;
+
+  // Format to apply to numeric types.
+  NumFormat num_format = NumFormat::kDefault;
+
+  Verbosity verbosity = Verbosity::kMedium;
+};
+
+}  // namespace zxdb