Spreadsheet: Avoid using Value.to_string_without_side_effects()
We should use .to_string() and handle the possible exceptions. This makes the displayed cell contents so much more informative than '[object Object]' :^)
This commit is contained in:
parent
235eb0b1ad
commit
5f1a34bba3
Notes:
sideshowbarker
2024-07-17 22:53:49 +09:00
Author: https://github.com/alimpfard Commit: https://github.com/SerenityOS/serenity/commit/5f1a34bba3a Pull-request: https://github.com/SerenityOS/serenity/pull/10991
13 changed files with 72 additions and 53 deletions
|
@ -74,12 +74,12 @@ const CellType& Cell::type() const
|
|||
return *CellType::get_by_name("Identity");
|
||||
}
|
||||
|
||||
String Cell::typed_display() const
|
||||
JS::ThrowCompletionOr<String> Cell::typed_display() const
|
||||
{
|
||||
return type().display(const_cast<Cell&>(*this), m_type_metadata);
|
||||
}
|
||||
|
||||
JS::Value Cell::typed_js_data() const
|
||||
JS::ThrowCompletionOr<JS::Value> Cell::typed_js_data() const
|
||||
{
|
||||
return type().js_value(const_cast<Cell&>(*this), m_type_metadata);
|
||||
}
|
||||
|
|
|
@ -79,8 +79,8 @@ struct Cell : public Weakable<Cell> {
|
|||
m_conditional_formats = move(fmts);
|
||||
}
|
||||
|
||||
String typed_display() const;
|
||||
JS::Value typed_js_data() const;
|
||||
JS::ThrowCompletionOr<String> typed_display() const;
|
||||
JS::ThrowCompletionOr<JS::Value> typed_js_data() const;
|
||||
|
||||
const CellType& type() const;
|
||||
const CellTypeMetadata& type_metadata() const { return m_type_metadata; }
|
||||
|
|
|
@ -21,7 +21,7 @@ DateCell::~DateCell()
|
|||
{
|
||||
}
|
||||
|
||||
String DateCell::display(Cell& cell, const CellTypeMetadata& metadata) const
|
||||
JS::ThrowCompletionOr<String> DateCell::display(Cell& cell, const CellTypeMetadata& metadata) const
|
||||
{
|
||||
ScopeGuard propagate_exception { [&cell] {
|
||||
if (auto exc = cell.sheet().interpreter().exception()) {
|
||||
|
@ -29,8 +29,8 @@ String DateCell::display(Cell& cell, const CellTypeMetadata& metadata) const
|
|||
cell.set_exception(exc);
|
||||
}
|
||||
} };
|
||||
auto timestamp = js_value(cell, metadata);
|
||||
auto string = Core::DateTime::from_timestamp(TRY_OR_DISCARD(timestamp.to_i32(cell.sheet().global_object()))).to_string(metadata.format.is_empty() ? "%Y-%m-%d %H:%M:%S" : metadata.format.characters());
|
||||
auto timestamp = TRY(js_value(cell, metadata));
|
||||
auto string = Core::DateTime::from_timestamp(TRY(timestamp.to_i32(cell.sheet().global_object()))).to_string(metadata.format.is_empty() ? "%Y-%m-%d %H:%M:%S" : metadata.format.characters());
|
||||
|
||||
if (metadata.length >= 0)
|
||||
return string.substring(0, metadata.length);
|
||||
|
@ -38,10 +38,10 @@ String DateCell::display(Cell& cell, const CellTypeMetadata& metadata) const
|
|||
return string;
|
||||
}
|
||||
|
||||
JS::Value DateCell::js_value(Cell& cell, const CellTypeMetadata&) const
|
||||
JS::ThrowCompletionOr<JS::Value> DateCell::js_value(Cell& cell, const CellTypeMetadata&) const
|
||||
{
|
||||
auto js_data = cell.js_data();
|
||||
auto value = TRY_OR_DISCARD(js_data.to_double(cell.sheet().global_object()));
|
||||
auto value = TRY(js_data.to_double(cell.sheet().global_object()));
|
||||
return JS::Value(value / 1000); // Turn it to seconds
|
||||
}
|
||||
|
||||
|
|
|
@ -15,8 +15,8 @@ class DateCell : public CellType {
|
|||
public:
|
||||
DateCell();
|
||||
virtual ~DateCell() override;
|
||||
virtual String display(Cell&, const CellTypeMetadata&) const override;
|
||||
virtual JS::Value js_value(Cell&, const CellTypeMetadata&) const override;
|
||||
virtual JS::ThrowCompletionOr<String> display(Cell&, const CellTypeMetadata&) const override;
|
||||
virtual JS::ThrowCompletionOr<JS::Value> js_value(Cell&, const CellTypeMetadata&) const override;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -19,12 +19,12 @@ IdentityCell::~IdentityCell()
|
|||
{
|
||||
}
|
||||
|
||||
String IdentityCell::display(Cell& cell, const CellTypeMetadata&) const
|
||||
JS::ThrowCompletionOr<String> IdentityCell::display(Cell& cell, const CellTypeMetadata&) const
|
||||
{
|
||||
return cell.js_data().to_string_without_side_effects();
|
||||
return cell.js_data().to_string(cell.sheet().global_object());
|
||||
}
|
||||
|
||||
JS::Value IdentityCell::js_value(Cell& cell, const CellTypeMetadata&) const
|
||||
JS::ThrowCompletionOr<JS::Value> IdentityCell::js_value(Cell& cell, const CellTypeMetadata&) const
|
||||
{
|
||||
return cell.js_data();
|
||||
}
|
||||
|
|
|
@ -15,8 +15,8 @@ class IdentityCell : public CellType {
|
|||
public:
|
||||
IdentityCell();
|
||||
virtual ~IdentityCell() override;
|
||||
virtual String display(Cell&, const CellTypeMetadata&) const override;
|
||||
virtual JS::Value js_value(Cell&, const CellTypeMetadata&) const override;
|
||||
virtual JS::ThrowCompletionOr<String> display(Cell&, const CellTypeMetadata&) const override;
|
||||
virtual JS::ThrowCompletionOr<JS::Value> js_value(Cell&, const CellTypeMetadata&) const override;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ NumericCell::~NumericCell()
|
|||
{
|
||||
}
|
||||
|
||||
String NumericCell::display(Cell& cell, const CellTypeMetadata& metadata) const
|
||||
JS::ThrowCompletionOr<String> NumericCell::display(Cell& cell, const CellTypeMetadata& metadata) const
|
||||
{
|
||||
ScopeGuard propagate_exception { [&cell] {
|
||||
if (auto exc = cell.sheet().interpreter().exception()) {
|
||||
|
@ -29,12 +29,12 @@ String NumericCell::display(Cell& cell, const CellTypeMetadata& metadata) const
|
|||
cell.set_exception(exc);
|
||||
}
|
||||
} };
|
||||
auto value = js_value(cell, metadata);
|
||||
auto value = TRY(js_value(cell, metadata));
|
||||
String string;
|
||||
if (metadata.format.is_empty())
|
||||
string = value.to_string_without_side_effects();
|
||||
string = TRY(value.to_string(cell.sheet().global_object()));
|
||||
else
|
||||
string = format_double(metadata.format.characters(), TRY_OR_DISCARD(value.to_double(cell.sheet().global_object())));
|
||||
string = format_double(metadata.format.characters(), TRY(value.to_double(cell.sheet().global_object())));
|
||||
|
||||
if (metadata.length >= 0)
|
||||
return string.substring(0, metadata.length);
|
||||
|
@ -42,7 +42,7 @@ String NumericCell::display(Cell& cell, const CellTypeMetadata& metadata) const
|
|||
return string;
|
||||
}
|
||||
|
||||
JS::Value NumericCell::js_value(Cell& cell, const CellTypeMetadata&) const
|
||||
JS::ThrowCompletionOr<JS::Value> NumericCell::js_value(Cell& cell, const CellTypeMetadata&) const
|
||||
{
|
||||
ScopeGuard propagate_exception { [&cell] {
|
||||
if (auto exc = cell.sheet().interpreter().exception()) {
|
||||
|
@ -50,7 +50,7 @@ JS::Value NumericCell::js_value(Cell& cell, const CellTypeMetadata&) const
|
|||
cell.set_exception(exc);
|
||||
}
|
||||
} };
|
||||
return TRY_OR_DISCARD(cell.js_data().to_number(cell.sheet().global_object()));
|
||||
return cell.js_data().to_number(cell.sheet().global_object());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,8 +15,8 @@ class NumericCell : public CellType {
|
|||
public:
|
||||
NumericCell();
|
||||
virtual ~NumericCell() override;
|
||||
virtual String display(Cell&, const CellTypeMetadata&) const override;
|
||||
virtual JS::Value js_value(Cell&, const CellTypeMetadata&) const override;
|
||||
virtual JS::ThrowCompletionOr<String> display(Cell&, const CellTypeMetadata&) const override;
|
||||
virtual JS::ThrowCompletionOr<JS::Value> js_value(Cell&, const CellTypeMetadata&) const override;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -19,18 +19,18 @@ StringCell::~StringCell()
|
|||
{
|
||||
}
|
||||
|
||||
String StringCell::display(Cell& cell, const CellTypeMetadata& metadata) const
|
||||
JS::ThrowCompletionOr<String> StringCell::display(Cell& cell, const CellTypeMetadata& metadata) const
|
||||
{
|
||||
auto string = cell.js_data().to_string_without_side_effects();
|
||||
auto string = TRY(cell.js_data().to_string(cell.sheet().global_object()));
|
||||
if (metadata.length >= 0)
|
||||
return string.substring(0, metadata.length);
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
JS::Value StringCell::js_value(Cell& cell, const CellTypeMetadata& metadata) const
|
||||
JS::ThrowCompletionOr<JS::Value> StringCell::js_value(Cell& cell, const CellTypeMetadata& metadata) const
|
||||
{
|
||||
auto string = display(cell, metadata);
|
||||
auto string = TRY(display(cell, metadata));
|
||||
return JS::js_string(cell.sheet().interpreter().heap(), string);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,8 +15,8 @@ class StringCell : public CellType {
|
|||
public:
|
||||
StringCell();
|
||||
virtual ~StringCell() override;
|
||||
virtual String display(Cell&, const CellTypeMetadata&) const override;
|
||||
virtual JS::Value js_value(Cell&, const CellTypeMetadata&) const override;
|
||||
virtual JS::ThrowCompletionOr<String> display(Cell&, const CellTypeMetadata&) const override;
|
||||
virtual JS::ThrowCompletionOr<JS::Value> js_value(Cell&, const CellTypeMetadata&) const override;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -28,8 +28,8 @@ public:
|
|||
static const CellType* get_by_name(StringView);
|
||||
static Vector<StringView> names();
|
||||
|
||||
virtual String display(Cell&, const CellTypeMetadata&) const = 0;
|
||||
virtual JS::Value js_value(Cell&, const CellTypeMetadata&) const = 0;
|
||||
virtual JS::ThrowCompletionOr<String> display(Cell&, const CellTypeMetadata&) const = 0;
|
||||
virtual JS::ThrowCompletionOr<JS::Value> js_value(Cell&, const CellTypeMetadata&) const = 0;
|
||||
virtual ~CellType() { }
|
||||
|
||||
const String& name() const { return m_name; }
|
||||
|
|
|
@ -598,8 +598,11 @@ Vector<Vector<String>> Sheet::to_xsv() const
|
|||
row.resize(column_count);
|
||||
for (size_t j = 0; j < column_count; ++j) {
|
||||
auto cell = at({ j, i });
|
||||
if (cell)
|
||||
row[j] = cell->typed_display();
|
||||
if (cell) {
|
||||
auto result = cell->typed_display();
|
||||
if (result.has_value())
|
||||
row[j] = result.value();
|
||||
}
|
||||
}
|
||||
|
||||
data.append(move(row));
|
||||
|
|
|
@ -27,29 +27,46 @@ GUI::Variant SheetModel::data(const GUI::ModelIndex& index, GUI::ModelRole role)
|
|||
if (!cell)
|
||||
return String::empty();
|
||||
|
||||
if (cell->kind() == Spreadsheet::Cell::Formula) {
|
||||
if (auto exception = cell->exception()) {
|
||||
StringBuilder builder;
|
||||
builder.append("Error: ");
|
||||
auto value = exception->value();
|
||||
if (value.is_object()) {
|
||||
auto& object = value.as_object();
|
||||
if (is<JS::Error>(object)) {
|
||||
auto error = object.get_without_side_effects("message").to_string_without_side_effects();
|
||||
builder.append(error);
|
||||
return builder.to_string();
|
||||
}
|
||||
Function<String(JS::Value)> to_string_as_exception = [&](JS::Value value) {
|
||||
ScopeGuard clear_exception {
|
||||
[&] {
|
||||
cell->sheet().interpreter().vm().clear_exception();
|
||||
}
|
||||
auto error = value.to_string_without_side_effects();
|
||||
// This is annoying, but whatever.
|
||||
cell->sheet().interpreter().vm().clear_exception();
|
||||
};
|
||||
|
||||
builder.append(error);
|
||||
return builder.to_string();
|
||||
StringBuilder builder;
|
||||
builder.append("Error: "sv);
|
||||
if (value.is_object()) {
|
||||
auto& object = value.as_object();
|
||||
if (is<JS::Error>(object)) {
|
||||
auto message = object.get_without_side_effects("message");
|
||||
auto error = message.to_string(cell->sheet().global_object());
|
||||
if (error.is_throw_completion())
|
||||
builder.append(message.to_string_without_side_effects());
|
||||
else
|
||||
builder.append(error.release_value());
|
||||
return builder.to_string();
|
||||
}
|
||||
}
|
||||
auto error_message = value.to_string(cell->sheet().global_object());
|
||||
|
||||
if (error_message.is_throw_completion())
|
||||
return to_string_as_exception(error_message.release_error().value());
|
||||
|
||||
builder.append(error_message.release_value());
|
||||
return builder.to_string();
|
||||
};
|
||||
|
||||
if (cell->kind() == Spreadsheet::Cell::Formula) {
|
||||
if (auto exception = cell->exception())
|
||||
return to_string_as_exception(exception->value());
|
||||
}
|
||||
|
||||
return cell->typed_display();
|
||||
auto display = cell->typed_display();
|
||||
if (display.is_error())
|
||||
return to_string_as_exception(display.release_error().value());
|
||||
|
||||
return display.release_value();
|
||||
}
|
||||
|
||||
if (role == GUI::ModelRole::MimeData)
|
||||
|
@ -155,5 +172,4 @@ void SheetModel::update()
|
|||
m_sheet->update();
|
||||
did_update(UpdateFlag::DontInvalidateIndices);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue