1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 13:57:35 +00:00

Spreadsheet: Reimplement ranges as lazy objects instead of arrays

Doing so makes it possible to talk about theoretically infinite ranges
like "all of column A".
This commit is contained in:
Ali Mohammad Pur 2021-11-21 03:38:10 +03:30 committed by Ali Mohammad Pur
parent 892e585e9a
commit 91444de2cf
5 changed files with 214 additions and 51 deletions

View file

@ -157,6 +157,7 @@ void SheetGlobalObject::initialize_global_object()
define_native_function("current_cell_position", current_cell_position, 0, attr);
define_native_function("column_arithmetic", column_arithmetic, 2, attr);
define_native_function("column_index", column_index, 1, attr);
define_native_function("get_column_bound", get_column_bound, 1, attr);
}
void SheetGlobalObject::visit_edges(Visitor& visitor)
@ -329,6 +330,31 @@ JS_DEFINE_NATIVE_FUNCTION(SheetGlobalObject::column_arithmetic)
return JS::js_string(vm, new_column.release_value());
}
JS_DEFINE_NATIVE_FUNCTION(SheetGlobalObject::get_column_bound)
{
if (vm.argument_count() != 1)
return vm.throw_completion<JS::TypeError>(global_object, "Expected exactly one argument to get_column_bound()");
auto column_name = vm.argument(0);
if (!column_name.is_string())
return vm.throw_completion<JS::TypeError>(global_object, JS::ErrorType::NotAnObjectOfType, "String");
auto& column_name_str = column_name.as_string().string();
auto* this_object = TRY(vm.this_value(global_object).to_object(global_object));
if (!is<SheetGlobalObject>(this_object))
return vm.throw_completion<JS::TypeError>(global_object, JS::ErrorType::NotAnObjectOfType, "SheetGlobalObject");
auto sheet_object = static_cast<SheetGlobalObject*>(this_object);
auto& sheet = sheet_object->m_sheet;
auto maybe_column_index = sheet.column_index(column_name_str);
if (!maybe_column_index.has_value())
return vm.throw_completion<JS::TypeError>(global_object, String::formatted("'{}' is not a valid column", column_name_str));
auto bounds = sheet.written_data_bounds(*maybe_column_index);
return JS::Value(bounds.row);
}
WorkbookObject::WorkbookObject(Workbook& workbook)
: JS::Object(*JS::Object::create(workbook.global_object(), workbook.global_object().object_prototype()))
, m_workbook(workbook)

View file

@ -38,6 +38,7 @@ public:
JS_DECLARE_NATIVE_FUNCTION(current_cell_position);
JS_DECLARE_NATIVE_FUNCTION(column_index);
JS_DECLARE_NATIVE_FUNCTION(column_arithmetic);
JS_DECLARE_NATIVE_FUNCTION(get_column_bound);
private:
virtual void visit_edges(Visitor&) override;

View file

@ -468,12 +468,14 @@ RefPtr<Sheet> Sheet::from_json(const JsonObject& object, Workbook& workbook)
return sheet;
}
Position Sheet::written_data_bounds() const
Position Sheet::written_data_bounds(Optional<size_t> column_index) const
{
Position bound;
for (auto& entry : m_cells) {
for (auto const& entry : m_cells) {
if (entry.value->data().is_empty())
continue;
if (column_index.has_value() && entry.key.column != *column_index)
continue;
if (entry.key.row >= bound.row)
bound.row = entry.key.row;
if (entry.key.column >= bound.column)

View file

@ -127,8 +127,8 @@ public:
void copy_cells(Vector<Position> from, Vector<Position> to, Optional<Position> resolve_relative_to = {}, CopyOperation copy_operation = CopyOperation::Copy);
/// Gives the bottom-right corner of the smallest bounding box containing all the written data.
Position written_data_bounds() const;
/// Gives the bottom-right corner of the smallest bounding box containing all the written data, optionally limited to the given column.
Position written_data_bounds(Optional<size_t> column_index = {}) const;
bool columns_are_standard() const;